177 lines
4.7 KiB
MQL5
177 lines
4.7 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| Reservoir.mqh |
|
|
//| Copyright 2022, MetaQuotes Ltd. |
|
|
//| https://www.mql5.com |
|
|
//| Use resources as universal storage (local clipboard) for |
|
|
//| applied data (builtin types and simple structs) |
|
|
//+------------------------------------------------------------------+
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Arbitrary data type conversion from/to byte array |
|
|
//+------------------------------------------------------------------+
|
|
template<typename T>
|
|
union ByteOverlay
|
|
{
|
|
uchar buffer[sizeof(T)];
|
|
T value;
|
|
|
|
ByteOverlay(const T &v)
|
|
{
|
|
value = v;
|
|
}
|
|
|
|
ByteOverlay(const uchar &bytes[], const int offset = 0)
|
|
{
|
|
ArrayCopy(buffer, bytes, 0, offset, sizeof(T));
|
|
}
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Save/Restore data to/from resource |
|
|
//+------------------------------------------------------------------+
|
|
class Reservoir
|
|
{
|
|
uint storage[];
|
|
int offset;
|
|
|
|
public:
|
|
Reservoir(): offset(0) { }
|
|
|
|
template<typename T>
|
|
int packArray(const T &data[])
|
|
{
|
|
const int bytesize = ArraySize(data) * sizeof(T); // TODO: check overflow
|
|
uchar buffer[];
|
|
ArrayResize(buffer, bytesize);
|
|
for(int i = 0; i < ArraySize(data); ++i)
|
|
{
|
|
ByteOverlay<T> overlay(data[i]);
|
|
ArrayCopy(buffer, overlay.buffer, i * sizeof(T));
|
|
}
|
|
|
|
const int size = bytesize / sizeof(uint) + (bool)(bytesize % sizeof(uint));
|
|
ArrayResize(storage, offset + size + 1);
|
|
storage[offset] = bytesize;
|
|
for(int i = 0; i < size; ++i)
|
|
{
|
|
ByteOverlay<uint> word(buffer, i * sizeof(uint));
|
|
storage[offset + i + 1] = word.value;
|
|
}
|
|
|
|
offset = ArraySize(storage);
|
|
|
|
return offset;
|
|
}
|
|
|
|
int packString(const string text)
|
|
{
|
|
uchar data[];
|
|
StringToCharArray(text, data, 0, -1, CP_UTF8);
|
|
return packArray(data);
|
|
}
|
|
|
|
template<typename T>
|
|
int packNumber(const T &number)
|
|
{
|
|
T array[1];
|
|
array[0] = number;
|
|
return packArray(array);
|
|
}
|
|
|
|
template<typename T>
|
|
int packNumber(const T number)
|
|
{
|
|
T array[1] = {number};
|
|
return packArray(array);
|
|
}
|
|
|
|
template<typename T>
|
|
int unpackArray(T &output[])
|
|
{
|
|
if(offset >= ArraySize(storage)) return 0; // out of bounds
|
|
const int bytesize = (int)storage[offset];
|
|
if(bytesize <= 0) return 0;
|
|
if(bytesize % sizeof(T) != 0) return 0; // inconsistent data type
|
|
if(bytesize > (ArraySize(storage) - offset) * sizeof(uint)) return 0;
|
|
|
|
uchar buffer[];
|
|
ArrayResize(buffer, bytesize);
|
|
for(int i = 0, k = 0; i < ArraySize(storage) - 1 - offset && k < bytesize; ++i, k += sizeof(uint))
|
|
{
|
|
ByteOverlay<uint> word(storage[i + 1 + offset]);
|
|
ArrayCopy(buffer, word.buffer, k);
|
|
}
|
|
|
|
int n = bytesize / sizeof(T);
|
|
n = ArrayResize(output, n);
|
|
for(int i = 0; i < n; ++i)
|
|
{
|
|
ByteOverlay<T> overlay(buffer, i * sizeof(T));
|
|
output[i] = overlay.value;
|
|
}
|
|
|
|
offset += 1 + bytesize / sizeof(uint) + (bool)(bytesize % sizeof(uint));
|
|
|
|
return offset;
|
|
}
|
|
|
|
int unpackString(string &output)
|
|
{
|
|
uchar bytes[];
|
|
const int p = unpackArray(bytes);
|
|
if(p == offset)
|
|
{
|
|
output = CharArrayToString(bytes, 0, -1, CP_UTF8);
|
|
}
|
|
return p;
|
|
}
|
|
|
|
template<typename T>
|
|
int unpackNumber(T &number)
|
|
{
|
|
T array[1] = {};
|
|
const int p = unpackArray(array);
|
|
number = array[0];
|
|
return p;
|
|
}
|
|
|
|
bool submit(const string resource)
|
|
{
|
|
return ResourceCreate(resource, storage, ArraySize(storage), 1,
|
|
0, 0, 0, COLOR_FORMAT_XRGB_NOALPHA);
|
|
}
|
|
|
|
bool acquire(const string resource)
|
|
{
|
|
if(ArraySize(storage) || offset) return false; // not empty already
|
|
|
|
uint width, height;
|
|
if(ResourceReadImage(resource, storage, width, height))
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
int size() const
|
|
{
|
|
return ArraySize(storage);
|
|
}
|
|
|
|
int cursor() const
|
|
{
|
|
return offset;
|
|
}
|
|
|
|
void clear()
|
|
{
|
|
ArrayFree(storage);
|
|
offset = 0;
|
|
}
|
|
|
|
void rewind()
|
|
{
|
|
offset = 0;
|
|
}
|
|
};
|
|
//+------------------------------------------------------------------+
|