Adwizard/Base/Factorable.mqh

470 lines
37 KiB
MQL5
Raw Permalink Normal View History

2025-04-11 13:28:40 +03:00
<EFBFBD><EFBFBD>//+------------------------------------------------------------------+
//| Factorable.mqh |
//| Copyright 2024, Yuriy Bykov |
//| https://www.mql5.com/ru/users/antekov |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019-2024, Yuriy Bykov"
#property link "https://www.mql5.com/ru/users/antekov"
#property version "1.05"
#include "FactorableCreator.mqh"
// 1JO2;5=85 AB0B8G5A:>3> :>=AB@C:B>@0 2=CB@8 :;0AA0
#define STATIC_CONSTRUCTOR(C) static CFactorable* Create(string p) { return new C(p); }
// >102;5=85 AB0B8G5A:>3> :>=AB@C:B>@0 4;O =>2>3> :;0AA0-=0A;54=8:0 CFactorable
// 2 A?5F80;L=K9 <0AA82 G5@57 A>740=85 3;>10;L=>3> >1J5:B0 :;0AA0 CFactorableCreator
#define REGISTER_FACTORABLE_CLASS(C) CFactorableCreator C##Creator(#C, C::Create);
// !>740=85 >1J5:B0 =0 D01@8:5 87 AB@>:8
#define NEW(P) CFactorable::Create(P)
// !>740=85 4>G5@=53> >1J5:B0 =0 D01@8:5 87 AB@>:8 c ?@>25@:>9.
// K7K205BAO B>;L:> 87 :>=AB@C:B>@0 B5:CI53> >1J5:B0.
// A;8 >1J5:B =5 A>740=, B> B5:CI89 >1J5:B AB0=>28BAO =520;84=K<
// 8 >ACI5AB2;O5BAO 2KE>4 87 :>=AB@C:B>@0
#define CREATE(C, O, P) C *O = NULL; if (IsValid()) { O = dynamic_cast<C*> (NEW(P)); if(!O) { SetInvalid(__FUNCTION__, StringFormat("Expected Object of class %s() at line %d in Params:\n%s", #C, __LINE__, P)); return; }}
//+------------------------------------------------------------------+
//| 07>2K9 :;0AA >1J5:B>2, A>740205<KE 87 AB@>:8 |
//+------------------------------------------------------------------+
class CFactorable {
private:
bool m_isValid; // 1J5:B 8A?@02=K9?
// G8AB:0 ?CABKE A8<2>;>2 A;520 8 A?@020 2 AB@>:5 8=8F80;870F88
static void Trim(string &p_params);
// >8A: ?0@=>9 70:@K20NI59 A:>1:8 2 AB@>:5 8=8F80;870F88
static int FindCloseBracket(string &p_params, char closeBraket = ')');
// G8AB:0 AB@>:8 8=8F80;870F88 A ?@>25@:>9 =0 8A?@02=>ABL B5:CI53> >1J5:B0
bool CheckTrimParams(string &p_params);
protected:
string m_params; // !B@>:0 8=8F80;870F88 B5:CI53> >1J5:B0
// #AB0=>2:0 B5:CI53> >1J5:B0 2 =58A?@02=>5 A>AB>O=85
void SetInvalid(string function = NULL, string message = NULL);
public:
CFactorable() : m_isValid(true) {} // >=AB@C:B>@
bool IsValid(); // 1J5:B 8A?@02=K9?
// @5>1@07>20=85 >1J5:B0 2 AB@>:C
virtual string operator~() = 0;
// !B@>:0 8=8F80;070F88 =0G8=05BAO A >?@545;5=8O >1J5:B0?
static bool IsObject(string &p_params, const string className = "");
// !B@>:0 8=8F80;070F88 =0G8=05BAO A >?@545;5=8O >1J5:B0 =C6=>3> :;0AA0?
static bool IsObjectOf(string &p_params, const string className);
// 'B5=85 8<5=8 :;0AA0 >1J5:B0 87 AB@>:8 8=8F80;870F88
static string ReadClassName(string &p_params, bool p_removeClassName = true);
// 'B5=85 >1J5:B0 87 AB@>:8 8=8F80;870F88
string ReadObject(string &p_params);
// 'B5=85 <0AA820 87 AB@>:8 8=8F80;870F88 2 2845 AB@>:8
string ReadArrayString(string &p_params);
// 'B5=85 AB@>:8 87 AB@>:8 8=8F80;870F88
string ReadString(string &p_params);
// 'B5=85 G8A;0 87 AB@>:8 8=8F80;870F88 2 2845 AB@>:8
string ReadNumber(string &p_params);
// 'B5=85 25I5AB25==>3> G8A;0 87 AB@>:8 8=8F80;870F88
double ReadDouble(string &p_params);
// 'B5=85 F5;>3> G8A;0 87 AB@>:8 8=8F80;870F88
long ReadLong(string &p_params);
// KG8A;5=85 MD5-E5H0 AB@>:8
static string Hash(string p_params, string delimeter = "");
virtual string Hash() {
return CFactorable::Hash(m_params);
}
// !>740=85 >1J5:B0 87 AB@>:8 8=8F80;870F88
static CFactorable* Create(string p_params);
};
//+------------------------------------------------------------------+
//| G8AB:0 ?CABKE A8<2>;>2 A;520 8 A?@020 2 AB@>:5 8=8F80;870F88 |
//+------------------------------------------------------------------+
void CFactorable::Trim(string &p_params) {
// >78F8O A;520, A :>B>@>9 =0G8=05BAO A>45@68<>5 AB@>:8 8=8F80;870F88
int posBeg = 0;
// A;8 2 =0G0;5 84QB >4=0 70?OB0O, B> A428305<AO 2?@02>
if(p_params[posBeg] == ',') posBeg++;
// >:0 84CB ?@>15;L=K5 A8<2>;K, A428305<AO 2?@02>
while(false
|| p_params[posBeg] == '\r'
|| p_params[posBeg] == '\n'
|| p_params[posBeg] == '\t'
|| p_params[posBeg] == ' ') {
posBeg++;
}
// A;8 40;LH5 84QB >4=0 70?OB0O, B> 5IQ A428305<AO 2?@02>
if(p_params[posBeg] == ',') posBeg++;
// K@5705< =57=0G0ICN ;52CN G0ABL AB@>:8 8=8F80;870F88
p_params = StringSubstr(p_params, posBeg);
// >78F8O A?@020, =0 :>B>@>9 70:0=G8205BAO A>45@60B5;L=0O
// G0ABL AB@>:8 8=8F80;870F88
int posEnd = StringLen(p_params) - 1;
// A;8 2 :>=F5 84QB >4=0 70?OB0O, B> A428305<AO 2;52>
if(p_params[posEnd] == ',') posEnd--;
// >:0 84CB ?@>15;L=K5 A8<2>;K, A428305<AO 2;52>
// => =5 40;LH5 =0G0;0 AB@>:8
while(posEnd >= 0 && (false
|| p_params[posEnd] == '\r'
|| p_params[posEnd] == '\n'
|| p_params[posEnd] == '\t'
|| p_params[posEnd] == ' ')) {
posEnd--;
}
// A;8 40;LH5 84QB >4=0 70?OB0O, B> 5IQ A428305<AO 2;52>
if(p_params[posEnd] == ',') posEnd--;
// K@5705< =57=0G0ICN ?@02CN G0ABL AB@>:8 8=8F80;870F88
p_params = StringSubstr(p_params, 0, posEnd + 1);
}
//+------------------------------------------------------------------+
//| >8A: ?0@=>9 70:@K20NI59 A:>1:8 2 AB@>:5 8=8F80;870F88 |
//+------------------------------------------------------------------+
int CFactorable::FindCloseBracket(string &p_params, char closeBraket) {
// CGQBG8: A:>1>:
int count = 0;
// 0@=0O A:>1:0
char openBraket = (closeBraket == ')' ? '(' : '[');
// 0E>48< ?5@2CN >B:@K20NICN A:>1:C
int pos;
for(pos = 0; pos < StringLen(p_params); pos++) {
if(p_params[pos] == openBraket) break;
}
// 0;55 C25;8G8205< AGQBG8: 4;O >B:@K20NI8E 8 C<5=LH05< 4;O 70:@K20NI8E
for(; pos < StringLen(p_params); pos++) {
if(p_params[pos] == openBraket ) count++;
if(p_params[pos] == closeBraket) count--;
// >340 AGQBG8: AB0; @025= 0, B> <K =0H;8 ?0@=CN 70:@K20NICN A:>1:C
if(count == 0) {
return pos;
}
}
// =0G5 A:>1:0 =5 =0945=0
return -1;
}
//+------------------------------------------------------------------+
//| G8AB:0 AB@>:8 8=8F80;870F88 A ?@>25@:>9 =0 8A?@02=>ABL |
//| B5:CI53> >1J5:B0 |
//+------------------------------------------------------------------+
bool CFactorable::CheckTrimParams(string &p_params) {
// A;8 B5:CI89 >1J5:B C65 2 =58A?@02=>< A>AB>O=88, B> 25@=CBL false
if(!IsValid()) return false;
// G8AB8< AB@>:C 8=8F80;870F88
Trim(p_params);
// 5@=Q< @57C;LB0B ?@>25@:8, GB> AB@>:0 8=8F80;870F88 =5 ?CAB0O
return (p_params != NULL && p_params != "");
}
//+------------------------------------------------------------------+
//| #AB0=>2:0 B5:CI53> >1J5:B0 2 =58A?@02=>5 A>AB>O=85 |
//+------------------------------------------------------------------+
void CFactorable::SetInvalid(string function, string message) {
// A;8 >1J5:B 5IQ 2 8A?@02=>< A>AB>O=88,
if(IsValid()) {
// B> CAB0=02;8205< 53> 2 =58A?@02=>5 A>AB>O=85
m_isValid = false;
if(function != NULL) {
// !>>1I05< >1 >H81:5, 5A;8 ?5@540==> 8<O 2K7K20NI59 DC=:F88
PrintFormat("%s | ERROR: %s", function, message);
}
} else {
// =0G5 ?@>AB> A>>1I05< >1 >H81:5, 5A;8 ?5@540==> 8<O 2K7K20NI59 DC=:F88
if(function != NULL) {
PrintFormat("%s | ERROR: Object is invalid already", function);
}
}
}
//+------------------------------------------------------------------+
//| 1J5:B 8A?@02=K9? |
//+------------------------------------------------------------------+
bool CFactorable::IsValid() {
return m_isValid;
}
//+------------------------------------------------------------------+
//| !B@>:0 8=8F80;070F88 =0G8=05BAO A >?@545;5=8O >1J5:B0? |
//+------------------------------------------------------------------+
bool CFactorable::IsObject(string &p_params, const string className = "") {
// >72@0I05< @57C;LB0B ?@>25@:8, GB> 2 =0G0;5 845B A;>2> 'class'
// A 2>7<>6=K< 8<5=5< :;0AA0 ?>A;5 >4=>3> ?@>15;0
return (StringFind(p_params, "class " + className) == 0);
}
//+------------------------------------------------------------------+
//| !B@>:0 8=8F80;070F88 =0G8=05BAO A >?@545;5=8O >1J5:B0 |
//| =C6=>3> :;0AA0? |
//+------------------------------------------------------------------+
bool CFactorable::IsObjectOf(string &p_params, const string className) {
return IsObject(p_params, className);
}
//+------------------------------------------------------------------+
//| 'B5=85 8<5=8 :;0AA0 >1J5:B0 87 AB@>:8 8=8F80;870F88 |
//+------------------------------------------------------------------+
string CFactorable::ReadClassName(string &p_params,
bool p_removeClassName = true) {
// G8I05< ?CABK5 A8<2>;K 2 =0G0;5 8 :>=F5
Trim(p_params);
// A;8 AB@>:0 8=8F80;870F88 ?CAB0O, B> =8G53> =5 45;05<
if(p_params == NULL || p_params == "") {
return NULL;
}
string res = NULL;
// 0G0;L=0O ?>78F8O - 4;8=0 A;>20 'class '
int posBeg = 6;
// >=5G=0O ?>78F8O - >B:@K20NI0O A:>1:0 ?>A;5 8<5=8 :;0AA0
int posEnd = StringFind(p_params, "(");
// A;8 2 AB@>:5 5ABL 8<O :;0AA0 8 ?0@0<5B@K 2 A:>1:0E
if(IsObject(p_params) && posEnd != -1) {
// K@5705< 8<O :;0AA0 2 :0G5AB25 @57C;LB0B0
res = StringSubstr(p_params, posBeg, posEnd - posBeg);
// A;8 2 AB@>:5 8=8F80;870F88 =04> >AB028BL B>;L:> ?0@0<5B@K, B>
if(p_removeClassName) {
// #18@05< 87 AB@>:8 8=8F80;870F88 8<O :;0AA0 A> A:>1:0<8
p_params = StringSubstr(p_params, posEnd + 1, StringLen(p_params) - posEnd - 2);
}
}
// >72@0I05< @57C;LB0B
return res;
}
//+------------------------------------------------------------------+
//| 'B5=85 >1J5:B0 87 AB@>:8 8=8F80;870F88 |
//+------------------------------------------------------------------+
string CFactorable::ReadObject(string &p_params) {
// A;8 AB@>:0 8=8F80;870F88 =5 ?CAB0O 8 B5:CI89 >1J5:B 5IQ 2 8A?@02=>< A>AB>O=88
if(CheckTrimParams(p_params)) {
// A;8 AB@>:0 8=8F80;870F88 A>45@68B >?8A0=85 >1J5:B0
if(IsObject(p_params)) {
// 0E>48< ?>;>65=85 A:>1:8, 70:@K20NI59 >?8A0=85 ?0@0<5B@>2 >1J5:B0
int posEnd = FindCloseBracket(p_params, ')');
if(posEnd != -1) {
// AQ 4> MB>9 A:>1:8 2:;NG8B5;L=> 15@Q< 2 :0G5AB25 @57C;LB0B0
string res = StringSubstr(p_params, 0, posEnd + 1);
// #18@05< 2>72@0I05<CN G0ABL 87 AB@>:8 8=8F80;870F88
p_params = StringSubstr(p_params, posEnd + 1);
if(p_params == "") p_params = NULL;
// >72@0I05< @57C;LB0B
return res;
}
}
}
// =0G5 CAB0=02;8205< B5:CI89 >1J5:B 2 =58A?@02=>5 A>AB>O=85 8 A>>1I05< >1 >H81:5
SetInvalid(__FUNCTION__, StringFormat("Expected Object in Params:\n%s", p_params));
return NULL;
}
//+------------------------------------------------------------------+
//| 'B5=85 <0AA820 87 AB@>:8 8=8F80;870F88 2 2845 AB@>:8 |
//+------------------------------------------------------------------+
string CFactorable::ReadArrayString(string &p_params) {
// A;8 AB@>:0 8=8F80;870F88 =5 ?CAB0O 8 B5:CI89 >1J5:B 5IQ 2 8A?@02=>< A>AB>O=88
if(CheckTrimParams(p_params)) {
// >78F8O :>=F0 >?8A0=8O <0AA820
int posEnd = -1;
// A;8 2 =0G0;5 84QB >B:@20NI0O <0AA82 A:>1:0, B>
if(p_params[0] == '[') {
// 0E>48< ?>78F8N 70:@K20NI59 A:>1:8
posEnd = FindCloseBracket(p_params, ']');
// A;8 =0H;8, B>
if(posEnd != -1) {
// AQ 4> MB>9 A:>1:8 =5 4>E>4O 15@Q< 2 :0G5AB25 @57C;LB0B0
string res = StringSubstr(p_params, 1, posEnd - 1);
// G8I05< ?CABK5 A8<2>;K 2 =0G0;5 8 :>=F5
Trim(res);
if(res == "") res = NULL;
// #18@05< 2>72@0I05<CN G0ABL 2<5AB5 A> A:>1:>9 87 AB@>:8 8=8F80;870F88
p_params = StringSubstr(p_params, posEnd + 1);
if(p_params == "") p_params = NULL;
// >72@0I05< @57C;LB0B
return res;
}
}
}
// =0G5 CAB0=02;8205< B5:CI89 >1J5:B 2 =58A?@02=>5 A>AB>O=85 8 A>>1I05< >1 >H81:5
SetInvalid(__FUNCTION__, StringFormat("Expected Array in Params:\n%s", p_params));
return NULL;
}
//+------------------------------------------------------------------+
//| 'B5=85 AB@>:8 87 AB@>:8 8=8F80;870F88 |
//+------------------------------------------------------------------+
string CFactorable::ReadString(string &p_params) {
// A;8 AB@>:0 8=8F80;870F88 =5 ?CAB0O 8 B5:CI89 >1J5:B 5IQ 2 8A?@02=>< A>AB>O=88
if(CheckTrimParams(p_params)) {
// A;8 MB> =5 >?8A0=85 <0AA820 8 =5 >?8A0=85 >1J5:B0
if(p_params[0] != '[' && !IsObject(p_params)) {
// >78F8O >:>=G0=8O G8B05<>9 AB@>:8
int posEnd = -1;
// !B@>:0 845B 2 :02KG:0E?
int quoted = (p_params[0] == '"' ? 1 : 0);
// A;8 2 :02KG:0E, B>
if(quoted) {
// 0E>48< A;54CNI89 A8<2>; :02KG5:
posEnd = StringFind(p_params, "\"", 1);
// A;8 =5 =0945=, B> CAB0=02;8205< B5:CI89 >1J5:B 2 =58A?@02=>5 A>AB>O=85 A A>>1I5=85< >1 >H81:5
if(posEnd == -1) {
SetInvalid(__FUNCTION__, StringFormat("Closed quote not found in Params:\n%s", p_params));
return NULL;
}
// BABC?05< 2;52> >B 70:@K20NI59 :02KG:8
posEnd--;
} else {
// =0G5 =0E>48< ?5@2CN A;54CNICN 70?OBCN
posEnd = StringFind(p_params, ",");
}
// AQ <564C 42C<O =0945==K<8 ?>78F8O<8 15@Q< 2 :0G5AB25 @57C;LB0B0
string res = StringSubstr(p_params, 0 + quoted, posEnd);
// #18@05< 2>72@0I05<CN G0ABL 2<5AB5 A :02KG:0<8 87 AB@>:8 8=8F80;870F88
p_params = StringSubstr(p_params, posEnd + quoted + 1);
if(p_params == "") {
p_params = NULL;
}
// >72@0I05< @57C;LB0B
return res;
}
}
// =0G5 CAB0=02;8205< B5:CI89 >1J5:B 2 =58A?@02=>5 A>AB>O=85 8 A>>1I05< >1 >H81:5
SetInvalid(__FUNCTION__, StringFormat("Expected String in Params:\n%s", p_params));
return NULL;
}
//+------------------------------------------------------------------+
//| 'B5=85 G8A;0 87 AB@>:8 8=8F80;870F88 2 2845 AB@>:8 |
//+------------------------------------------------------------------+
string CFactorable::ReadNumber(string &p_params) {
// A;8 AB@>:0 8=8F80;870F88 =5 ?CAB0O 8 B5:CI89 >1J5:B 5IQ 2 8A?@02=>< A>AB>O=88
if(CheckTrimParams(p_params)) {
// A;8 MB> =5 >?8A0=85 <0AA820, =5 >?8A0=85 AB@>:8 8 =5 >?8A0=85 >1J5:B0
if(p_params[0] != '['
&& p_params[0] != '"'
&& !IsObject(p_params)) {
// 0E>48< ?>78F8N >:>=G0=8O G8B05<>3> G8A;0 ?> A;54CNI59 70?OB>9
int posEnd = StringFind(p_params, ",");
// AQ >B =0G0;0 4> =0945==>9 ?>78F88 15@Q< 2 :0G5AB25 @57C;LB0B0
string res = StringSubstr(p_params, 0, posEnd);
// #18@05< 2>72@0I05<CN G0ABL 87 AB@>:8 8=8F80;870F88
p_params = StringSubstr(p_params, posEnd + 1);
if(posEnd == -1) {
p_params = NULL;
}
// >72@0I05< @57C;LB0B
return res;
}
}
// =0G5 CAB0=02;8205< B5:CI89 >1J5:B 2 =58A?@02=>5 A>AB>O=85 8 A>>1I05< >1 >H81:5
SetInvalid(__FUNCTION__, StringFormat("Expected Number in Params:\n%s", p_params));
return NULL;
}
//+------------------------------------------------------------------+
//| 'B5=85 25I5AB25==>3> G8A;0 87 AB@>:8 8=8F80;870F88 |
//+------------------------------------------------------------------+
double CFactorable::ReadDouble(string &p_params) {
return StringToDouble(ReadNumber(p_params));
}
//+------------------------------------------------------------------+
//| 'B5=85 F5;>3> G8A;0 87 AB@>:8 8=8F80;870F88 |
//+------------------------------------------------------------------+
long CFactorable::ReadLong(string &p_params) {
return StringToInteger(ReadNumber(p_params));
}
//+------------------------------------------------------------------+
//| KG8A;5=85 MD5-E5H0 AB@>:8 |
//+------------------------------------------------------------------+
string CFactorable::Hash(string p_params, string p_delimeter = "") {
uchar hash[], key[], data[];
// KG8A;O5< E5H >B AB@>:8 8=8F80;870F88
StringToCharArray(p_params, data);
CryptEncode(CRYPT_HASH_MD5, data, key, hash);
// 5@52>48< 53> 87 <0AA820 G8A5; 2 AB@>:C A H5AB=04F0B5@8G=>9 70?8ALN
string res = "";
FOREACH(hash) {
res += StringFormat("%X", hash[i]);
if(i % 4 == 3 && i < 15) res += p_delimeter;
}
return res;
}
//+------------------------------------------------------------------+
//| !>740=85 >1J5:B0 87 AB@>:8 8=8F80;870F88 |
//+------------------------------------------------------------------+
CFactorable* CFactorable::Create(string p_params) {
// #:070B5;L =0 A>740205<K9 >1J5:B
CFactorable* object = NULL;
// '8B05< 8<O :;0AA0 >1J5:B0
string className = CFactorable::ReadClassName(p_params);
//  7028A8<>AB8 >B 8<5=8 :;0AA0 =0E>48< 8 2K7K205< A>>B25BAB2CNI89 :>=AB@C:B>@
int i;
SEARCH(CFactorableCreator::creators, className == CFactorableCreator::creators[i].m_className, i);
if(i != -1) {
object = CFactorableCreator::creators[i].m_creator(p_params);
}
// A;8 >1J5:B =5 A>740= 8;8 A>740= 2 =58A?@02=>< A>AB>O=88, B> A>>1I05< >1 >H81:5
if(!object) {
PrintFormat(__FUNCTION__" | ERROR: Constructor not found for:\n%s",
p_params);
} else if(!object.IsValid()) {
PrintFormat(__FUNCTION__
" | ERROR: Created object is invalid for:\n%s",
p_params);
delete object; // #40;O5< =58A?@02=K9 >1J5:B
object = NULL;
}
return object;
}
//+------------------------------------------------------------------+