EA-Setka-2/Libs/TypeToBytes.mqh
super.admin a4b861dd93 convert
2025-05-30 14:50:44 +02:00

1 line
No EOL
19 KiB
MQL4

// MQL4&5-code
#define __TYPETOBYTES__
template <typename T>
class CASTING
{
public:
template <typename T1>
static const T Casting( const T1 &Value )
{
#ifdef TYPETOBYTES_FULL_SLOW
static const bool IsScript = ((ENUM_PROGRAM_TYPE)::MQLInfoInteger(MQL_PROGRAM_TYPE) == PROGRAM_SCRIPT);
static bool FirstRun = true;
T Data = {0};
if (FirstRun)
{
if (IsScript)
{
const int handle = ::FileOpen("Casting.tmp", FILE_READ | FILE_WRITE | FILE_BIN);
if (handle != INVALID_HANDLE)
{
::FileWriteStruct(handle, Value);
::FileSeek(handle, 0, SEEK_SET);
::FileReadStruct(handle, Data);
::FileClose(handle);
}
}
else
{
::Alert("TYPETOBYTES_FULL_SLOW-mode only for Scripts!");
FirstRun = false;
}
}
return(Data);
#else // TYPETOBYTES_FULL_SLOW
union CAST
{
T1 Value1;
const T Value2;
CAST( const T1 &Value)
{
this.Value1 = Value; // êàñòîìíûé îïåðàòîð ìîæåò âñå èñïîðòèòü
}
};
const CAST Union(Value);
return(Union.Value2);
#endif // TYPETOBYTES_FULL_SLOW
}
};
#define _C(A, B) CASTING<A>::Casting(B)
#define _R(A) TYPETOBYTES::Read(A)
#define _W(A) A=TYPETOBYTES::Write(A)
#define _OFFSET(A,B) TYPETOBYTES::Offset(A, A.B)
#define _WRONG_ASSIGN_OPERATOR(A) TYPETOBYTES::IsWrongAssignOperator<A>()
#define EQUAL_DEFINE(A) \
template <typename T1> \
bool operator ==( const T1 &A ) const \
{ \
return(::ArrayCompare(this.Bytes, \
_R(Value).Bytes) == 0); \
} \
\
template <typename T1> \
bool operator !=( const T1 &A ) const \
{ \
return(!(this == Value)); \
}
#define CONSTRUCTOR_DEFINE(A) \
template <typename T1> \
T1 operator []( const T1 Pos ) const \
{ \
STRUCT_TYPE<T1> Res = {0}; \
const int iPos = (int)Pos; \
\
if (iPos + sizeof(T1) <= ::ArraySize(this.Bytes)) \
{ \
STRUCT_READ<T1> Tmp = {0}; \
\
::ArrayCopy(Tmp.Bytes, this.Bytes, 0, iPos, sizeof(T1)); \
\
Res = _C(STRUCT_TYPE<T1>, Tmp); \
} \
\
return(Res.Value); \
} \
\
string operator []( const string Pos ) const \
{ \
string Res = NULL; \
const int iPos = (int)Pos; \
const int Size = ::ArraySize(this.Bytes); \
int iEnd = iPos; \
\
while ((iEnd < Size) && (this.Bytes[iEnd] != 0)) \
iEnd++; \
\
if (iPos < Size) \
{ \
uchar TmpBytes[]; \
\
::ArrayCopy(TmpBytes, this.Bytes, 0, iPos, iEnd - iPos); \
\
_W(Res) = TmpBytes; \
} \
\
return(Res); \
} \
\
EQUAL_DEFINE(Value) \
EQUAL_DEFINE(Value[])
struct STRUCT_READ_ARRAY
{
uchar Bytes[];
STRUCT_READ_ARRAY( void )
{
}
template <typename T>
STRUCT_READ_ARRAY( const T &Value[] )
{
const int Size = ::ArraySize(Value);
const int Step = sizeof(T);
::ArrayResize(this.Bytes, Size * Step);
for (int i = 0, j = 0; i < Size; i++, j += Step)
::ArrayCopy(this.Bytes, _R(Value[i]).Bytes, j);
}
STRUCT_READ_ARRAY( const string &Value[] )
{
const int Size = ::ArraySize(Value);
for (int i = 0, j = 0; i < Size; j += ::StringLen(Value[i++]) + 1)
::ArrayCopy(this.Bytes, _R(Value[i]).Bytes, j);
}
STRUCT_READ_ARRAY( const string &Value )
{
::StringToCharArray(Value, this.Bytes);
}
void operator =( const STRUCT_READ_ARRAY &Value )
{
::ArrayCopy(this.Bytes, Value.Bytes);
return;
}
CONSTRUCTOR_DEFINE(STRUCT_READ_ARRAY)
};
#define DEFINE_TYPES \
M(char) M(short) M(int) M(long) M(uchar) M(ushort) M(uint) \
M(ulong) M(bool) M(double) M(float) M(color) M(datetime)
template <typename T>
struct STRUCT_TYPE
{
private:
template <typename T1>
void Set( STRUCT_TYPE<T1> &Struct, const T1 &tValue ) const
{
Struct = _C(STRUCT_TYPE<T1>, tValue);
}
#define M(A) \
void Set( STRUCT_TYPE<A> &Struct, const A tValue ) const \
{ \
Struct.Value = tValue; \
}
DEFINE_TYPES
#undef M
public:
T Value;
void operator =( const T& tValue )
{
// Îáõîäèì âîçìîæíûé êàñòîìíûé îïåðàòîð ïðèñâàèâàíèÿ ó T-òèïà
// https://www.mql5.com/ru/forum/1111/page1870#comment_4863733
this.Set(this, tValue);
}
};
template <typename T>
struct STRUCT_READ
{
uchar Bytes[sizeof(T)];
void operator =( const T &Value )
{
const STRUCT_TYPE<T> Res = Value;
this = _C(STRUCT_READ<T>, Res);
}
CONSTRUCTOR_DEFINE(STRUCT_READ)
};
#undef CONSTRUCTOR_DEFINE
#undef EQUAL_DEFINE
template <typename T>
struct STRUCT_WRITE
{
private:
T Data;
int Pos;
template <typename T1>
T1 GetValue( const T1&, const uchar &Array[] ) const
{
STRUCT_READ<T1> Res = {0};
// Óêàçàíèå âñåõ ïàðàìåòðîâ, ò.ê. â MQL4 ñòàòè÷åñêèå ìàññèâû ìîãóò ìåíÿòü ðàçìåð
::ArrayCopy(Res.Bytes, Array, 0, 0, ::MathMin(::ArraySize(Array), ::ArraySize(Res.Bytes)));
return(_C(STRUCT_TYPE<T1>, Res).Value);
}
string GetValue( const string&, const uchar &Array[] ) const
{
return(::CharArrayToString(Array));
}
public:
STRUCT_WRITE( const T &Value )
{
this.Data = Value;
this.Pos = 0;
}
STRUCT_WRITE<T> operator []( const int iPos )
{
this.Pos = iPos;
return(this);
}
// Íóæåí äëÿ âûøåñòîÿùåé return(this)
void operator =( const STRUCT_WRITE<T> &Value )
{
this.Data = Value.Data;
this.Pos = Value.Pos;
return;
}
// Íóæåí äëÿ âûøåñòîÿùåé return(this)
STRUCT_WRITE( void )
{
}
#define OPERATOR_DEFINE(A ) \
template <typename T1> \
T operator =( const T1 A ) const \
{ \
uchar TmpBytes[]; \
::ArrayCopy(TmpBytes, _R(this.Data).Bytes); \
\
::ArrayCopy(TmpBytes, _R(Value).Bytes, this.Pos); \
\
return(this.GetValue(this.Data, TmpBytes)); \
}
OPERATOR_DEFINE(Value)
OPERATOR_DEFINE(&Value)
OPERATOR_DEFINE(&Value[])
#undef OPERATOR_DEFINE
T operator =( const string &Value[] ) const
{
uchar TmpBytes[];
::ArrayCopy(TmpBytes, _R(this.Data).Bytes);
if (typename(T) == "string") // êîãäà ïèøåì ñòðîêîâûé ìàññèâ â ñòðîêó, êîíöû ñòðîê èãíîðèðóåì
{
const int Size = ::ArraySize(Value);
for (int i = 0, j = this.Pos; i < Size; j += ::StringLen(Value[i++])/* + 1*/) // Áåç åäèíèöû óäîáíåå - èãíîðèðîâàíèå íóëåâûõ ðàçäåëèòåëåé
::ArrayCopy(TmpBytes, _R(Value[i]).Bytes, j);
}
else
::ArrayCopy(TmpBytes, _R(Value).Bytes, this.Pos);
return(this.GetValue(this.Data, TmpBytes));
}
};
class TYPETOBYTES
{
private:
template <typename T>
static const STRUCT_TYPE<T> FillBytes( const uchar Byte = UCHAR_MAX )
{
STRUCT_READ<T> Res = {0};
::ArrayInitialize(Res.Bytes, Byte);
return(_C(STRUCT_TYPE<T>, Res));
}
public:
#define READ_DEFINE(A, B, C) \
static const B Read( const C A ) \
{ \
const B Res = Value; \
\
return(Res); \
}
template <typename T>
READ_DEFINE(&Value, STRUCT_READ<T>, T)
template <typename T>
READ_DEFINE(&Value[], STRUCT_READ_ARRAY, T)
#define M(A) READ_DEFINE(Value, STRUCT_READ<A>, A)
DEFINE_TYPES
#undef M
#undef READ_DEFINE
#undef DEFINE_TYPES
static const STRUCT_READ_ARRAY Read( const string Value )
{
const STRUCT_READ_ARRAY Res(Value);
return(Res);
}
template <typename T>
static STRUCT_WRITE<T> Write( const T &Value )
{
const STRUCT_WRITE<T> Res(Value);
return(Res);
}
template <typename T>
static bool IsWrongAssignOperator( void )
{
bool Res = (sizeof(T) != 0);
if (Res)
{
STRUCT_TYPE<T> NotNull_Type = TYPETOBYTES::FillBytes<T>();
STRUCT_TYPE<T> Null_Type = {0};
T NotNull = NotNull_Type.Value;
T Null = Null_Type.Value;
// Ïåðåïèñàòü, êîãäà èñïðàâÿò - https://www.mql5.com/ru/forum/1111/page1874#comment_4871926
// Ïðè÷èíà òàêèõ äåéñòâèé - https://www.mql5.com/ru/forum/95447/page3#comment_4872456
const STRUCT_TYPE<T> constNotNull_Type = NotNull_Type;
const STRUCT_TYPE<T> constNull_Type = Null_Type;
const T constNotNull = constNotNull_Type.Value;
const T constNull = constNull_Type.Value;
Res = ((_R(Null) != Null_Type.Value) || (_R(NotNull) != NotNull_Type.Value) || (_R(Null) == NotNull) ||
(_R(constNull) != Null_Type.Value) || (_R(constNotNull) != NotNull_Type.Value) || (_R(constNull) == constNotNull));
}
return(Res);
}
// Co-author - https://www.mql5.com/ru/users/alximiks
// Return the first shift of Field bit in the Struct.
template <typename T1, typename T2>
static int Offset( T1 &Struct, T2 &Field )
{
int Res = -1;
if (!TYPETOBYTES::IsWrongAssignOperator<T2>())
{
const STRUCT_TYPE<T2> StoredField = Field; // Îáõîäèì T2-îïåðàòîð ïðèñâàèâàíèÿ
// get Struct where Field value is with all unset bits (0000...)
const STRUCT_TYPE<T2> Null = {0};
Field = Null.Value;
const STRUCT_READ<T1> StructWithUnsetField = _C(STRUCT_READ<T1>, Struct);
// get Struct where Field value is with all set bits (1111...)
Field = TYPETOBYTES::FillBytes<T2>().Value;
const STRUCT_READ<T1> StructWithSetField = _C(STRUCT_READ<T1>, Struct);
//restore Struct data
Field = StoredField.Value;
for (int i = 0; i < sizeof(T1); i++)
if (StructWithUnsetField.Bytes[i] != StructWithSetField.Bytes[i])
{
Res = i;
break;
}
}
return(Res);
}
template <typename T1, typename T2>
static int Offset( T1 &Struct, T2 &Field[] )
{
int Res = -1;
if (!TYPETOBYTES::IsWrongAssignOperator<T2>())
{
const STRUCT_TYPE<T2> StoredField = Field[0]; // Îáõîäèì T2-îïåðàòîð ïðèñâàèâàíèÿ
// get Struct where Field value is with all unset bits (0000...)
const STRUCT_TYPE<T2> Null = {0};
Field[0] = Null.Value;
const STRUCT_READ<T1> StructWithUnsetField = _C(STRUCT_READ<T1>, Struct);
// get Struct where Field value is with all set bits (1111...)
Field[0] = TYPETOBYTES::FillBytes<T2>().Value;
const STRUCT_READ<T1> StructWithSetField = _C(STRUCT_READ<T1>, Struct);
//restore Struct data
Field[0] = StoredField.Value;
for (int i = 0; i < sizeof(T1); i++)
if (StructWithUnsetField.Bytes[i] != StructWithSetField.Bytes[i])
{
Res = i;
break;
}
}
return(Res);
}
};
// Ïîáàéòîâûé ArrayCopy, âîçâðàøàåò êîëè÷åñòâî ñêîïèðîâàííûõ áàéòîâ
template <typename T1, typename T2>
int _ArrayCopy( T1 &Dst_Array[], const T2 &Src_Array[], const int Dst_Start = 0, const int Src_Start = 0, const int Count = WHOLE_ARRAY )
{
STRUCT_READ_ARRAY Dst(Dst_Array);
const int Amount = _WRONG_ASSIGN_OPERATOR(T1) ? 0 : ::ArrayCopy(Dst.Bytes, _R(Src_Array).Bytes, Dst_Start, Src_Start, Count);
if (Amount > 0)
{
const int Step = sizeof(T1);
const int Size = ::ArraySize(Dst.Bytes);
::ArrayResize(Dst_Array, Size / Step + ((Size % Step == 0) ? 0 : 1));
const int TmpEnd = Dst_Start + Amount;
const int End = ::MathMin(TmpEnd / Step + ((TmpEnd % Step == 0) ? 1 : 2), ::ArraySize(Dst_Array));
STRUCT_READ<T1> Tmp;
for (int i = Dst_Start / Step, j = i * Step; i < End; i++, j += Step)
{
::ArrayCopy(Tmp.Bytes, Dst.Bytes, 0, j, Step);
Dst_Array[i] = _C(STRUCT_TYPE<T1>, Tmp).Value;
}
}
return(Amount);
}
// Âîçâðàøàåò êîëè÷åñòâî ñêîïèðîâàííûõ ñòðîê
template <typename T>
int _ArrayCopy( string &Dst_Array[], const T &Src_Array[], const int Dst_Start = 0, const int Src_Start = 0, const int Count = WHOLE_ARRAY )
{
const int Amount = ((Count == WHOLE_ARRAY) ? ::ArraySize(Src_Array) - Src_Start : Src_Start + Count);
int Res = 0;
if (Amount > 0)
for (int i = Dst_Start, Pos = Src_Start; Pos < Amount ; i++)
{
if (i >= ::ArraySize(Dst_Array))
::ArrayResize(Dst_Array, i + 1);
_W(Dst_Array[i]) = _R(Src_Array)[(string)Pos];
Pos += ::StringLen(Dst_Array[i]) + 1;
Res++;
}
return(Res);
}
template <typename T>
int _ArrayResize( T &Array[], const int Size )
{
return(sizeof(T) * ::ArrayResize(Array, Size / sizeof(T) + ((bool)(Size % sizeof(T)) ? 1 : 0)));
}
// Çàìåíÿåò ïîáàéòîâî êóñîê èñõîäíîãî ìàññèâà íà êóñîê äðóãîãî ìàññèâà.
// Âîçâðàùàåò êîëè÷åñòâî áàéòîâ íîâûõ äàííûõ.
template <typename T1, typename T2>
int _ArrayReplace( T1 &Dst_Array[], const T2 &Src_Array[],
const int Dst_Start = 0, const int Dst_Count = WHOLE_ARRAY,
const int Src_Start = 0, const int Src_Count = WHOLE_ARRAY )
{
uchar TmpData[];
const bool FlagTmpData = (Dst_Count != WHOLE_ARRAY);
if (FlagTmpData)
_ArrayCopy(TmpData, Dst_Array, 0, Dst_Start + Dst_Count);
_ArrayResize(Dst_Array, Dst_Start);
const int Res = _ArrayCopy(Dst_Array, Src_Array, Dst_Start, Src_Start, Src_Count);
if (FlagTmpData)
_ArrayCopy(Dst_Array, TmpData, Dst_Start + Res);
return(Res);
}
template <typename T>
class CONTAINER
{
private:
int AmountBytes;
string Types[];
int Pos;
int Amount;
int GetPosBytes( void ) const
{
int Res = 0;
for (int i = 0; i < this.Pos; i++)
Res += _R(this.Data)[Res] + sizeof(int);
return(Res);
}
public:
T Data[];
CONTAINER( void ) : AmountBytes(0), Pos(-1), Amount(0)
{
}
string GetType( void ) const
{
return(this.Types[(this.Pos == -1) ? 0 : this.Pos]);
}
CONTAINER* operator []( const int iPos )
{
this.Pos = iPos;
return(&this);
}
int GetAmount( void ) const
{
return(this.Amount);
}
#define OPERATOR_MACROS(A, B) \
template <typename T1> \
void operator =( const T1 A ) \
{ \
uchar Bytes[]; \
\
_ArrayCopy(Bytes, _R(::ArraySize(_R(Value).Bytes)).Bytes); \
_ArrayCopy(Bytes, _R(Value).Bytes, ::ArraySize(Bytes)); \
\
if ((this.Pos >= this.Amount) || (this.Pos == -1)) \
{ \
this.Amount = ::ArrayResize(this.Types, this.Amount + 1); \
this.Pos = this.Amount - 1; \
\
this.AmountBytes += _ArrayCopy(this.Data, Bytes, this.AmountBytes); \
} \
else \
{ \
const int PosBytes = this.GetPosBytes(); \
const int Count = _R(this.Data)[PosBytes] + sizeof(int); \
\
this.AmountBytes += _ArrayReplace(this.Data, Bytes, PosBytes, Count) - Count; \
} \
\
this.Types[this.Pos] = typename(T1) + B; \
this.Pos = -1; \
\
return; \
}
OPERATOR_MACROS(Value, "")
OPERATOR_MACROS(&Value, "")
OPERATOR_MACROS(&Value[], "[" + (string)::ArraySize(Value) + "]")
#undef OPERATOR_MACROS
/*
template <typename T1>
void operator =( CONTAINER<T1> &Container )
{
this.AmountBytes = Container.AmountBytes;
this.Amount = Container.Amount;
::ArrayCopy(this.Types, Container.Types);
_ArrayCopy(this.Data, Container.Data);
return;
}
*/
template <typename T1>
void Get( T1 &Value ) const
{
const int PosBytes = this.GetPosBytes();
const int Count = _R(this.Data)[PosBytes];
uchar Bytes[];
_ArrayCopy(Bytes, this.Data, 0, PosBytes + sizeof(int), Count);
_W(Value) = Bytes;
return;
}
template <typename T1>
int Get( T1 &Value[] ) const
{
const int PosBytes = this.GetPosBytes();
const int Count = _R(this.Data)[PosBytes];
_ArrayCopy(Value, this.Data, 0, PosBytes + sizeof(int), Count);
return(::ArraySize(Value));
}
template <typename T1>
T1 Get() // const // https://www.mql5.com/ru/forum/1111/page1948#comment_5461816
{
T1 Res;
this.Get(Res);
return(Res);
}
};