Files
Extern/C3d/Include/io_tape.h
T
SaraP f5f6a9cb47 Extern :
- C3d aggiornamento librerie ( 118027).
2025-02-28 15:40:33 +01:00

2617 lines
131 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
////////////////////////////////////////////////////////////////////////////////
/**
\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 <io_tape_define.h>
#include <io_memory_buffer.h>
#include <templ_pointer.h>
#include <templ_sfdp_array.h>
#include <alg_indicator.h>
#include <tool_cstring.h>
#include <hash32.h>
#include <tool_mutex.h>
#include <map>
#include <typeinfo>
//----------------------------------------------------------------------------------------
/** \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<const TapeBase *, size_t> TapeIndexMap;
typedef std::map<size_t, TapeBase *> 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 Массив для регистрации объектов с сохранением информации о позиции чтения/записи.
\en Array for registration of objects with information about reading/writing position. \~
\details \ru Массив для регистрации объектов с сохранением информации о позиции чтения/записи. \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<ClusterReference, size_t> ClusterIndexMap;
typedef std::map<size_t, const ClusterReference*> 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<ProgressBarWrapper> _progress;
tape & _tape;
public:
ScopedReadProgress( tape & 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 "Обертка" для одного потокового класса ( не экземпляра! ).
Хранит упакованное имя класса и адреса функций, необходимых при чтении/записи. \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<TapeManager> & 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<TapeClass> > & CALL_DECLARATION StaticTapeClassContainer();
/// \ru Добавить потоковый класс. \en Add a stream class.
static bool Add( TapeClass & tapeClass )
{
if ( !StaticTapeClassContainer() )
StaticTapeClassContainer() = new SFDPArray<TapeClass>( 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 == *reinterpret_cast<ClassDescriptor*>(d) ) ? 0 : (( t1.hashValue > *reinterpret_cast<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 ) );
}
};
//----------------------------------------------------------------------------------------
/// \ru Функция чтения базового класса. \en Function of reading the base class. \~ \ingroup Base_Tools_IO
// ---
template <class Base>
inline void ReadBase( reader & in, Base * base ) {
Base::Read( in, base );
}
//----------------------------------------------------------------------------------------
/// \ru Функция записи базового класса. \en Function of writing the base class. \~ \ingroup Base_Tools_IO
// ---
template <class Base>
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 <class Base>
void ReadVBase( reader & in, Base * base )
{
switch( in.readByte() ) {
case tape::otIndexed:
break;
case tape::otObject :
in.registrate( dynamic_cast<TapeBase*>(base) );
Base::Read( in, base );
break;
}
}
//----------------------------------------------------------------------------------------
/// \ru Функция записи виртуального базового класса. \en Function of writing of a virtual base class. \~ \ingroup Base_Tools_IO
// ---
template <class Base>
void WriteVBase( writer & out, const Base * base )
{
if ( !out.good() )
return;
if ( out.exist( dynamic_cast<TapeBase*>(base) ) )
out.writeByte( tape::otIndexed );
else {
out.registrate( dynamic_cast<TapeBase*>(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 <typeinfo>
// #include <iostream>
// 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<class ClassA,class ClassB>" функция возвращает "ClassXClassAClassB".
// \ru For example, for the name "class ClassX<class ClassA,class ClassB>" 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 = reinterpret_cast<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[static_cast<size_t>(len) + 1]; // \ru длина (количество символов) вычитываемой строки с терминальным нулем \en length (number of symbols) of string being read with terminating 0
size_t size = sizeof(uint16) * static_cast<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[static_cast<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 = reinterpret_cast<TCHAR *>(readBuf); // \ru собственно ничего конвертировать не нужно \en nothing to convert
#else // sizeof(wchar_t) == sizeof(uint32)
s = reinterpret_cast<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) * static_cast<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[static_cast<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 = reinterpret_cast<wchar_t *>(readBuf); // \ru собственно ничего конвертировать не нужно \en nothing to convert
#else // sizeof(wchar_t) == sizeof(uint32)
s = reinterpret_cast<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 = static_cast<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 = static_cast<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 = static_cast<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 = static_cast<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 = static_cast<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 = static_cast<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 = static_cast<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 = static_cast<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<class _Class>
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<class _Class>
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 )
{
#ifndef C3D_WINDOWS
C3DLocaleSwitcher lh( FIX_ANSI1251, out.MathVersion() < UNICODE_VERSION );
#endif
// \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 = static_cast<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 ( static_cast<int64>(count) > static_cast<int64>(SYS_MAX_INT32) || static_cast<int64>(count) < static_cast<int64>(SYS_MIN_INT32) )
out.setState( io::underflow64to32 );
int32 _count = static_cast<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 = static_cast<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 = static_cast<size_t>(_count);
}
else
{
uint32 _count = 0;
in >> _count;
count = static_cast<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 = static_cast<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 = static_cast<ptrdiff_t>(_count);
}
else
{
int32 _count = 0;
in >> _count;
count = static_cast<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 = static_cast<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 <= static_cast<size_t>(SYS_MAX_UINT32)/*_UI32_MAX*/ );
const uint32 count32 = static_cast<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 = static_cast<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 <= static_cast<ptrdiff_t>(SYS_MAX_INT32)/*_I32_MAX*/ && count >= static_cast<ptrdiff_t>(SYS_MIN_INT32)/*_I32_MIN*/ );
const int32 count32 = static_cast<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 = static_cast<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 )
{
#ifndef C3D_WINDOWS
C3DLocaleSwitcher lh( FIX_ANSI1251 );
#endif
// \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 )
{
#ifndef C3D_WINDOWS
C3DLocaleSwitcher lh( FIX_ANSI1251 );
#endif
// \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( reinterpret_cast<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( reinterpret_cast<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( static_cast<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, static_cast<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 = static_cast<uint8 *>(out);
// \ru кол-во заполненных байт в кластере \en the number of filled bytes in the cluster
uint16 l = obj._len();
PRECONDITION( l <= clusterSize );
*reinterpret_cast<uint16*>(m) = l;
m += sizeof(uint16);
if ( l > clusterSize )
return static_cast<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 = static_cast<uint8 *>(in);
// \ru прочитать кол-во заполненных байт кластера и заполнить соответствующее поле в нем \en read the number of filled bytes in the cluster and fill its corresponding field
uint16 l = *reinterpret_cast<uint16*>(m);
PRECONDITION( l <= clusterSize );
obj.SetClusterLength( l );
m += sizeof(uint16);
if ( l > clusterSize )
return static_cast<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, static_cast<const Class &>(ref) ); }
#define IMP_KNOWN_OBJECTS_RW_PTR_OPERATORS(Class) \
writer & CALL_DECLARATION operator << ( writer & out, Class * ptr ) { return operator << ( out, static_cast<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, static_cast<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, static_cast<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<TapeBase *>(&ref) ); \
return in; \
} \
DLLFUNC reader & CALL_DECLARATION operator >> ( reader & in, Class *& ptr ) { \
ptr = dynamic_cast<Class *>( in.readObjectPointer() ); \
return in; \
} \
DLLFUNC reader & CALL_DECLARATION operator >> ( reader & in, const Class *& ptr ) \
{ \
ptr = dynamic_cast<Class *>( in.readObjectPointer() ); \
return in; \
} \
DLLFUNC writer & CALL_DECLARATION operator << ( writer & out, const Class & ref ) { \
out.writeObject( dynamic_cast<const TapeBase *>(&ref) ); \
return out; \
} \
DLLFUNC writer & CALL_DECLARATION operator << ( writer & out, const Class * ptr ) { \
out.writeObjectPointer( dynamic_cast<const TapeBase*>(ptr) ); \
return out; \
} \
DLLFUNC writer & CALL_DECLARATION operator << ( writer & out, Class & ref ) { \
out.writeObject( dynamic_cast<TapeBase *>(&ref) ); \
return out; \
} \
DLLFUNC writer & CALL_DECLARATION operator << ( writer& out, Class * ptr ) { \
out.writeObjectPointer( dynamic_cast<TapeBase *>(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<Class *>(const_cast<TapeBase *>(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<TapeBase *>( new Class(tapeInit) ); \
} \
void * CALL_DECLARATION cast ## _ ## Class ( const TapeBase * obj ) { \
return dynamic_cast<Class *>(const_cast<TapeBase *>(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<Class*>(const_cast<TapeBase *>(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<TapeBase *>(&ref) ); \
return in; \
} \
friend inline reader & CALL_DECLARATION operator >> ( reader & in, Class *& ptr ) { \
ptr = dynamic_cast<Class *>( 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