Compare commits
53 Commits
pimap
...
8551499a5e
| Author | SHA1 | Date | |
|---|---|---|---|
| 8551499a5e | |||
|
|
1eaecb288f | ||
|
|
170a713357 | ||
| 54cc6c55b2 | |||
| e6aa3c34d4 | |||
| bb40f69298 | |||
| af9a9e78b9 | |||
| af1264e42b | |||
| eb91fbfc45 | |||
| 4ea5465637 | |||
| ab7769dd5a | |||
| b1e220e454 | |||
| 1b499530c5 | |||
| b0d48caaad | |||
|
|
d6758a8562 | ||
| 97734953dd | |||
| bd98583116 | |||
|
|
ddba8f401b | ||
|
|
4725eb96d6 | ||
|
|
38fd1b5dc4 | ||
| 16c12a2756 | |||
|
|
1b09ad5c27 | ||
|
|
00d06f71ba | ||
|
|
3873f0b03b | ||
| 6ae6e9a540 | |||
|
|
bbc83128b0 | ||
|
|
d13e68c206 | ||
| a4882dc054 | |||
|
|
a1b9b7e1d6 | ||
|
|
e1b89aeca8 | ||
| 242abaaf59 | |||
|
|
0116387fe3 | ||
|
|
f5953a0ba7 | ||
|
|
7aa407264f | ||
|
|
59c7896577 | ||
|
|
a69de63db0 | ||
| e96b399da7 | |||
| 33eefd7453 | |||
| c7fffe1280 | |||
| 1b04d7ecce | |||
| b66272a68a | |||
| f67e3030b9 | |||
| 1028233553 | |||
| ef8ffcd02f | |||
| 0897a8369f | |||
| fa19ad1093 | |||
| 8c6b3613b6 | |||
| a23eb341e2 | |||
| b2bc385397 | |||
| 0f9e592273 | |||
| cf4f58ed95 | |||
| 0243f588bc | |||
| af77974e91 |
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define lapi_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define lcode_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define lctype_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define ldebug_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define ldo_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define ldump_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define lfunc_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define lgc_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define llex_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define lmem_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define lobject_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define lopcodes_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define lparser_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define lstate_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define lstring_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define ltable_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define ltm_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define lundump_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define lvm_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#define lzio_c
|
||||
#define LUA_CORE
|
||||
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.0)
|
||||
cmake_policy(SET CMP0017 NEW) # need include() with .cmake
|
||||
project(pip)
|
||||
set(pip_MAJOR 2)
|
||||
set(pip_MINOR 39)
|
||||
set(pip_MINOR 99)
|
||||
set(pip_REVISION 0)
|
||||
set(pip_SUFFIX )
|
||||
set(pip_COMPANY SHS)
|
||||
|
||||
@@ -20,12 +20,7 @@ main library
|
||||
cmake_policy(SET CMP0011 NEW) # don`t affect includer policies
|
||||
include(SHSTKMacros)
|
||||
|
||||
shstk_set_find_dirs(pip)
|
||||
if(PIP_DIR)
|
||||
list(APPEND pip_LIBDIR "${PIP_DIR}/lib")
|
||||
list(APPEND pip_INCDIR "${PIP_DIR}/include/pip")
|
||||
list(APPEND pip_BINDIR "${PIP_DIR}/bin")
|
||||
endif()
|
||||
shstk_set_find_dirs(pip PIP)
|
||||
|
||||
set(__libs "usb;crypt;console;fftw;compress;io_utils;opencl;cloud;lua")
|
||||
|
||||
|
||||
@@ -2282,7 +2282,7 @@ EXTERNAL_GROUPS = YES
|
||||
# be listed.
|
||||
# The default value is: YES.
|
||||
|
||||
EXTERNAL_PAGES = YES
|
||||
EXTERNAL_PAGES = NO
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the dot tool
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
inline PICout operator <<(PICout s, const PIByteArray & ba) {
|
||||
s.space(); // insert space after previous output
|
||||
s.quote(); // ONLY if you want to quoted your type
|
||||
s.setControl(0, true); // clear all features and
|
||||
s.saveAndSetControls(0); // clear all features and
|
||||
// save them to stack,
|
||||
// now it`s behavior similar to std::cout
|
||||
|
||||
@@ -12,7 +12,7 @@ inline PICout operator <<(PICout s, const PIByteArray & ba) {
|
||||
for (uint i = 0; i < ba.size(); ++i)
|
||||
s << ba[i];
|
||||
|
||||
s.restoreControl(); // restore features from stack
|
||||
s.restoreControls(); // restore features from stack
|
||||
s.quote(); // ONLY if you want to quoted your type
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -7,19 +7,19 @@ class SomeIO: public PIIODevice {
|
||||
public:
|
||||
SomeIO(): PIIODevice() {}
|
||||
protected:
|
||||
bool openDevice() {
|
||||
bool openDevice() override {
|
||||
// open your device here
|
||||
return if_success;
|
||||
}
|
||||
int read(void * read_to, int max_size) {
|
||||
ssize_t readDevice(void * read_to, ssize_t max_size) override {
|
||||
// read from your device here
|
||||
return readed_bytes;
|
||||
}
|
||||
int write(const void * data, int max_size) {
|
||||
ssize_t writeDevice(const void * data, ssize_t max_size) override {
|
||||
// write to your device here
|
||||
return written_bytes;
|
||||
}
|
||||
void configureFromFullPath(const PIString & full_path) {
|
||||
void configureFromFullPathDevice(const PIString & full_path) override {
|
||||
// parse full_path and configure device here
|
||||
}
|
||||
};
|
||||
@@ -38,7 +38,7 @@ ser.configure("example.conf", "dev");
|
||||
//! [configureDevice]
|
||||
class SomeIO: public PIIODevice {
|
||||
...
|
||||
bool configureDevice(const void * e_main, const void * e_parent) {
|
||||
bool configureDevice(const void * e_main, const void * e_parent) override {
|
||||
PIConfig::Entry * em = (PIConfig::Entry * )e_main;
|
||||
PIConfig::Entry * ep = (PIConfig::Entry * )e_parent;
|
||||
setStringParam(readDeviceSetting<PIString>("stringParam", stringParam(), em, ep));
|
||||
|
||||
297
doc/pages/code_model.md
Normal file
297
doc/pages/code_model.md
Normal file
@@ -0,0 +1,297 @@
|
||||
\~english \page code_model Code generation
|
||||
\~russian \page code_model Генерация кода
|
||||
|
||||
\~english
|
||||
|
||||
\~russian
|
||||
|
||||
# Введение
|
||||
|
||||
Кодогенерация помогает в случаях, когда нужен доступ к строковому представлению
|
||||
сущностей (классов, перечислений, ...), либо автоматизированная де/сериализация
|
||||
структур и классов.
|
||||
|
||||
Например, необходимо для создания интерфейса получить в готовом виде список
|
||||
пар "имя" = "значение" от какого-либо перечисления, либо обойти список
|
||||
вложенных в класс структур с дополнительными метками. Или просто описать
|
||||
структуру любой сложности, пометить поля номерами и получить готовые операторы
|
||||
де/сериализации для PIBinaryStream с возможностью будущих изменений и сохранением
|
||||
обратной совместимости.
|
||||
|
||||
# pip_cmg
|
||||
|
||||
PIP предоставляет утилиту, которая берет на вход файлы исходного кода, пути
|
||||
включения, параметры и макросы, и на выходе создает h/cpp пару файлов с
|
||||
необходимым функционалом. В зависимости от параметров, в этих файлах будут
|
||||
присутствовать секции:
|
||||
* метаинформации о сущностях;
|
||||
* операторы де/сериализации;
|
||||
* возможность получить PIVariant любого члена структуры по имени.
|
||||
|
||||
Параметры обработки:
|
||||
* -s - не следовать "#include" внутри файлов;
|
||||
* -I<include_dir> - добавить папку включения (например, -I.. -I../some_dir -I/usr/include);
|
||||
* -D<define> - добавить макрос, PICODE всегда объявлен (например, -DMY_DEFINE добавит макрос MY_DEFINE).
|
||||
|
||||
Параметры создания:
|
||||
* -A - создать всё;
|
||||
* -M - создать метаинформацию (имена и типы всех членов, иерархия включения);
|
||||
* -E - создать перечисления (списки перечислений);
|
||||
* -S - создать операторы де/сериализации;
|
||||
* -G - создать методы получения значений переменных по именам;
|
||||
* -o <output_file> - имя файлов модели без расширения (например, "ccm" - создадутся файлы "ccm.h" и "ccm.cpp")
|
||||
|
||||
# CMake
|
||||
|
||||
Для автоматизации кодогенерации существует CMake макрос pip_code_model, который сам вызывает pip_cmg и
|
||||
следит за актуальностью модели.
|
||||
|
||||
Формат вызова макроса:
|
||||
\code{.cmake}
|
||||
pip_code_model(<out_var> file0 [file1 ...] [OPTIONS opt0 [opt1 ...] ] [NAME name])
|
||||
\endcode
|
||||
|
||||
Параметры:
|
||||
* out_var - имя переменной, куда будут записаны абсолютные пути сгенерённых файлов;
|
||||
* file... - файлы для генерации, допускаются относительные или абсолютные пути;
|
||||
* OPTIONS - передаваемые в pip_cmg параметры, например, "-Es";
|
||||
* NAME - базовое имя файлов модели, если не указано, то используется "ccm_${PROJECT_NAME}".
|
||||
|
||||
Этот макрос сам включает все пути для PIP.
|
||||
|
||||
Для получения актуальных параметров pip_cmg можно вызывать "pip_cmg -v".
|
||||
|
||||
# Подробности
|
||||
|
||||
## Метаинформация
|
||||
|
||||
Метаинформация - это текстовое представление всех членов и методов структуры или класса C++.
|
||||
Для доступа к ним используется PICodeInfo::classesInfo->value("name"), который возвращает
|
||||
указатель на структуру PICodeInfo::ClassInfo, содержащую всю информацию о сущности.
|
||||
|
||||
В любой структуре PICodeInfo есть поле "MetaMap meta", содержащее произвольные
|
||||
данные, видимые для кодогенератора, но невидимые для компилятора.
|
||||
Для этого используется макрос PIMETA(), который необходимо вписать после объявления
|
||||
переменной, метода либо сущности, например:
|
||||
\code{.cpp}
|
||||
struct MyStruct: Header PIMETA(type=in,port=5005) {
|
||||
ushort calcChecksum() const PIMETA(show=true);
|
||||
bool checkChecksum() const;
|
||||
void setChecksum();
|
||||
uchar block_id PIMETA(type=int) = 0;
|
||||
};
|
||||
enum FOV { // Поле зрения
|
||||
fovWide PIMETA(label="Широкое",angle=90),
|
||||
fovNormal PIMETA(label="Нормальное",angle=60),
|
||||
fovNarrow PIMETA(label="Узкое",angle=30)
|
||||
};
|
||||
\endcode
|
||||
В этом примере в каждом месте, где указана PIMETA, её можно будет получить через "MetaMap meta".
|
||||
|
||||
## Перечисления
|
||||
|
||||
Перечисления записываются отдельно, для доступа к ним используется PICodeInfo::enumsInfo->value("name"),
|
||||
который возвращает указатель на структуру PICodeInfo::EnumInfo, содержащую всю информацию о перечеслении.
|
||||
|
||||
## Операторы де/сериализации
|
||||
|
||||
Эти операторы создаются в h файле для всех сутрктур и классов, в которых есть хотя бы один член,
|
||||
доступный для работы. Операторы работают с PIBinaryStream в двух вариантах - простом или через PIChunkStream.
|
||||
|
||||
Для каждой структуры можно указать режим де/сериализации с помощью фиксированного поля в PIMETA:
|
||||
* нет указаний - работа через PIChunkStream;
|
||||
* simple-stream - работа просто через PIBinaryStream;
|
||||
* no-stream - не создавать операторы.
|
||||
|
||||
Например, для структуры
|
||||
\code{.cpp}
|
||||
struct DateTime {
|
||||
uchar seconds;
|
||||
uchar minutes;
|
||||
uchar hours;
|
||||
uchar days;
|
||||
uchar months;
|
||||
uchar years;
|
||||
};
|
||||
\endcode
|
||||
создадутся операторы
|
||||
\code{.cpp}
|
||||
BINARY_STREAM_WRITE(DateTime) {
|
||||
PIChunkStream cs;
|
||||
cs << cs.chunk(1, v.seconds);
|
||||
cs << cs.chunk(2, v.minutes);
|
||||
cs << cs.chunk(3, v.hours);
|
||||
cs << cs.chunk(4, v.days);
|
||||
cs << cs.chunk(5, v.months);
|
||||
cs << cs.chunk(6, v.years);
|
||||
s << cs.data();
|
||||
return s;
|
||||
}
|
||||
BINARY_STREAM_READ (DateTime) {
|
||||
PIByteArray csba; s >> csba;
|
||||
PIChunkStream cs(csba);
|
||||
while (!cs.atEnd()) {
|
||||
switch (cs.read()) {
|
||||
case 1: cs.get(v.seconds); break;
|
||||
case 2: cs.get(v.minutes); break;
|
||||
case 3: cs.get(v.hours); break;
|
||||
case 4: cs.get(v.days); break;
|
||||
case 5: cs.get(v.months); break;
|
||||
case 6: cs.get(v.years); break;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
\endcode
|
||||
, где порядок id последовательнен.
|
||||
|
||||
Для структуры
|
||||
\code{.cpp}
|
||||
struct DateTime PIMETA(simple-stream) {
|
||||
uchar seconds;
|
||||
uchar minutes;
|
||||
uchar hours;
|
||||
uchar days;
|
||||
uchar months;
|
||||
uchar years;
|
||||
};
|
||||
\endcode
|
||||
создадутся операторы
|
||||
\code{.cpp}
|
||||
BINARY_STREAM_WRITE(DateTime) {
|
||||
s << v.seconds;
|
||||
s << v.minutes;
|
||||
s << v.hours;
|
||||
s << v.days;
|
||||
s << v.months;
|
||||
s << v.years;
|
||||
return s;
|
||||
}
|
||||
BINARY_STREAM_READ (DateTime) {
|
||||
s >> v.seconds;
|
||||
s >> v.minutes;
|
||||
s >> v.hours;
|
||||
s >> v.days;
|
||||
s >> v.months;
|
||||
s >> v.years;
|
||||
return s;
|
||||
}
|
||||
\endcode
|
||||
|
||||
Для структуры
|
||||
\code{.cpp}
|
||||
struct DateTime PIMETA(no-stream) {
|
||||
uchar seconds;
|
||||
uchar minutes;
|
||||
uchar hours;
|
||||
uchar days;
|
||||
uchar months;
|
||||
uchar years;
|
||||
};
|
||||
\endcode
|
||||
не создадутся операторы
|
||||
|
||||
В режиме работы через PIChunkStream также можно указать индивидуальные id,
|
||||
что очень полезно для сохранения обратной совместимости структур разных версий:
|
||||
Для структуры
|
||||
\code{.cpp}
|
||||
struct DateTime {
|
||||
PIMETA(id=10) uchar seconds;
|
||||
PIMETA(id=11) uchar minutes;
|
||||
PIMETA(id=12) uchar hours;
|
||||
PIMETA(id=20) uchar days;
|
||||
PIMETA(id=21) uchar months;
|
||||
PIMETA(id=22) uchar years;
|
||||
};
|
||||
\endcode
|
||||
\code{.cpp}
|
||||
BINARY_STREAM_WRITE(DateTime) {
|
||||
PIChunkStream cs;
|
||||
cs << cs.chunk(10, v.seconds);
|
||||
cs << cs.chunk(11, v.minutes);
|
||||
cs << cs.chunk(12, v.hours);
|
||||
cs << cs.chunk(20, v.days);
|
||||
cs << cs.chunk(21, v.months);
|
||||
cs << cs.chunk(22, v.years);
|
||||
s << cs.data();
|
||||
return s;
|
||||
}
|
||||
BINARY_STREAM_READ (DateTime) {
|
||||
PIByteArray csba; s >> csba;
|
||||
PIChunkStream cs(csba);
|
||||
while (!cs.atEnd()) {
|
||||
switch (cs.read()) {
|
||||
case 10: cs.get(v.seconds); break;
|
||||
case 11: cs.get(v.minutes); break;
|
||||
case 12: cs.get(v.hours); break;
|
||||
case 20: cs.get(v.days); break;
|
||||
case 21: cs.get(v.months); break;
|
||||
case 22: cs.get(v.years); break;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
\endcode
|
||||
|
||||
Если в этом режиме какую-либо переменную надо проигнорировать, то вместо
|
||||
числа id можно указать "-":
|
||||
\code{.cpp}
|
||||
struct DateTime {
|
||||
PIMETA(id=10) uchar seconds;
|
||||
PIMETA(id=11) uchar minutes;
|
||||
PIMETA(id=-) uchar hours;
|
||||
PIMETA(id=20) uchar days;
|
||||
PIMETA(id=21) uchar months;
|
||||
PIMETA(id=-) uchar years;
|
||||
};
|
||||
\endcode
|
||||
\code{.cpp}
|
||||
BINARY_STREAM_WRITE(DateTime) {
|
||||
PIChunkStream cs;
|
||||
cs << cs.chunk(10, v.seconds);
|
||||
cs << cs.chunk(11, v.minutes);
|
||||
cs << cs.chunk(20, v.days);
|
||||
cs << cs.chunk(21, v.months);
|
||||
s << cs.data();
|
||||
return s;
|
||||
}
|
||||
BINARY_STREAM_READ (DateTime) {
|
||||
PIByteArray csba; s >> csba;
|
||||
PIChunkStream cs(csba);
|
||||
while (!cs.atEnd()) {
|
||||
switch (cs.read()) {
|
||||
case 10: cs.get(v.seconds); break;
|
||||
case 11: cs.get(v.minutes); break;
|
||||
case 20: cs.get(v.days); break;
|
||||
case 21: cs.get(v.months); break;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
\endcode
|
||||
|
||||
# Интеграция в проект
|
||||
|
||||
При использовании CMake достаточно включить содержимое переменной out_var в приложение
|
||||
или библиотеку, и включить через "#include" сгенерированный заголовочный файл в нужном месте.
|
||||
После этого перечисления и метаинформация будут загружены в момент запуска, до int main(),
|
||||
а операторы станут доступны через заголовочный файл.
|
||||
|
||||
CMakeLists.txt:
|
||||
\code{.cmake}
|
||||
project(myapp)
|
||||
pip_code_model(CCM "structures.h" OPTIONS "-EMs")
|
||||
add_executable(${PROJECT_NAME} ${CPPS} ${CCM})
|
||||
\endcode
|
||||
|
||||
C++:
|
||||
\code{.cpp}
|
||||
#include "ccm_myapp.h"
|
||||
|
||||
...
|
||||
|
||||
PICodeInfo::EnumInfo * ei = PICodeInfo::enumsInfo->value("MyEnum", 0);
|
||||
if (ei) {
|
||||
ei->members.forEach([](const PICodeInfo::EnumeratorInfo & e){piCout << e.name << "=" << e.value;});
|
||||
}
|
||||
\endcode
|
||||
117
doc/pages/iostream.md
Normal file
117
doc/pages/iostream.md
Normal file
@@ -0,0 +1,117 @@
|
||||
\~english \page iostream Input/Output stream
|
||||
\~russian \page iostream Поток ввода/вывода
|
||||
|
||||
\~english
|
||||
\~russian
|
||||
%PIBinaryStream представляет собой интерфейс бинарной сериализации.
|
||||
Не может быть использован в чистом виде, только в виде миксина или
|
||||
готовых классов: PIByteArray и PIIOBinaryStream.
|
||||
|
||||
|
||||
Используется для сохранения или чтения любых данных. Простые типы читаются/пишутся
|
||||
как блоки памяти, если не созданы конкретные операторы. Сложные типы
|
||||
([нетривиальные](https://ru.cppreference.com/w/cpp/types/is_trivially_copyable))
|
||||
обязаны иметь операторы ввода/вывода, иначе возникнет ошибка компиляции.
|
||||
|
||||
Также поддерживаются контейнеры с типами по таким же правилам.
|
||||
|
||||
Перечисления интерпретируются как int, логические типы как один байт.
|
||||
|
||||
Операторы сохранения добавляют данные в конец потока, а операторы извлечения
|
||||
берут данные из его начала.
|
||||
|
||||
Для облегчения написания операторов есть макросы:
|
||||
* BINARY_STREAM_FRIEND(T) - объявить операторы с доступом к приватному
|
||||
содержимому типа T, необязателен;
|
||||
* BINARY_STREAM_WRITE(T) - запись в поток, "s" - объект потока, "v" - объект типа T;
|
||||
* BINARY_STREAM_READ(T) - чтение из потока, "s" - объект потока, "v" - объект типа T.
|
||||
|
||||
Пример:
|
||||
\~\code{.cpp}
|
||||
#include <pibytearray.h>
|
||||
|
||||
class MyType {
|
||||
BINARY_STREAM_FRIEND(MyType);
|
||||
public:
|
||||
|
||||
void setInt(int v) {m_i = v;}
|
||||
int getInt() const {return m_i;}
|
||||
|
||||
void setString(PIString v) {m_s = v;}
|
||||
PIString getString() const {return m_s;}
|
||||
|
||||
private:
|
||||
int m_i = 0;
|
||||
PIString m_s;
|
||||
|
||||
};
|
||||
|
||||
BINARY_STREAM_WRITE(MyType) {s << v.m_i << v.m_s; return s;}
|
||||
BINARY_STREAM_READ (MyType) {s >> v.m_i >> v.m_s; return s;}
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
MyType t_read, t_write;
|
||||
t_write.setInt(10);
|
||||
t_write.setString("text");
|
||||
|
||||
PIByteArray data;
|
||||
data << t_write;
|
||||
|
||||
piCout << data.toHex();
|
||||
|
||||
data >> t_read;
|
||||
piCout << t_read.getInt() << t_read.getString();
|
||||
|
||||
piCout << data.toHex();
|
||||
}
|
||||
\endcode
|
||||
|
||||
\~english Result:
|
||||
\~russian Результат:
|
||||
\~\code{.cpp}
|
||||
0a000000040000007400650078007400
|
||||
10 text
|
||||
|
||||
\endcode
|
||||
|
||||
|
||||
\~english
|
||||
For store/restore custom data blocks this is PIMemoryBlock class. Stream
|
||||
operators of this class simply store/restore data block to/from stream:
|
||||
|
||||
\~russian
|
||||
Для сохранения/извлечения блоков произвольных данных используется класс PIMemoryBlock.
|
||||
Потоковые операторы для него просто сохраняют/извлекают блоки байтов в/из потока:
|
||||
|
||||
\~\code{.cpp}
|
||||
float a_read[10], a_write[10];
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
a_read [i] = 0.f;
|
||||
a_write[i] = i / 10.f;
|
||||
}
|
||||
|
||||
PIByteArray data;
|
||||
data << PIMemoryBlock(a_write, 10 * sizeof(float));
|
||||
|
||||
piCout << data.toHex();
|
||||
|
||||
data >> PIMemoryBlock(a_read, 10 * sizeof(float));
|
||||
for (int i = 0; i < 10; ++i)
|
||||
piCout << a_read[i];
|
||||
\endcode
|
||||
|
||||
\~english Result:
|
||||
\~russian Результат:
|
||||
\~\code{.cpp}
|
||||
00000000cdcccc3dcdcc4c3e9a99993ecdcccc3e0000003f9a99193f3333333fcdcc4c3f6666663f
|
||||
0
|
||||
0.1
|
||||
0.2
|
||||
0.3
|
||||
0.4
|
||||
0.5
|
||||
0.6
|
||||
0.7
|
||||
0.8
|
||||
0.9
|
||||
\endcode
|
||||
@@ -6,7 +6,7 @@
|
||||
* direct output to console (\a PICout)
|
||||
* containers (\a PIVector, \a PIDeque, \a PIVector2D, \a PIStack, \a PIQueue, \a PIMap, \a PISet)
|
||||
* byte array (\a PIByteArray)
|
||||
* serialization (\a PIChunkStream)
|
||||
* serialization (\a PIBinaryStream, \a PITextStream, \a PIIOBinaryStream, \a PIIOTextStream, \a PIChunkStream)
|
||||
* string (\a PIConstChars, \a PIString, \a PIStringList)
|
||||
* base object (events and handlers) (\a PIObject)
|
||||
* multithreading
|
||||
@@ -57,7 +57,7 @@
|
||||
* общение с консолью (\a PICout)
|
||||
* контейнеры (\a PIVector, \a PIDeque, \a PIVector2D, \a PIStack, \a PIQueue, \a PIMap, \a PISet)
|
||||
* байтовый массив (\a PIByteArray)
|
||||
* сериализация (\a PIChunkStream)
|
||||
* сериализация (\a PIBinaryStream, \a PITextStream, \a PIIOBinaryStream, \a PIIOTextStream, \a PIChunkStream)
|
||||
* строка (\a PIConstChars, \a PIString, \a PIStringList)
|
||||
* базовый объект (события и обработчики) (\a PIObject)
|
||||
* многопоточность
|
||||
|
||||
@@ -28,7 +28,7 @@ PICloudClient::PICloudClient(const PIString & path, PIIODevice::DeviceMode mode)
|
||||
is_deleted = false;
|
||||
// setReopenEnabled(false);
|
||||
CONNECTL(ð, connected, [this](){opened_ = true; tcp.sendStart();});
|
||||
CONNECTU(&streampacker, packetReceiveEvent, this, _readed);
|
||||
CONNECT1(void, PIByteArray, &streampacker, packetReceiveEvent, this, _readed);
|
||||
CONNECTL(ð, disconnected, [this](bool){
|
||||
if (is_deleted) return;
|
||||
bool need_disconn = is_connected;
|
||||
@@ -104,11 +104,11 @@ bool PICloudClient::closeDevice() {
|
||||
}
|
||||
|
||||
|
||||
int PICloudClient::readDevice(void * read_to, int max_size) {
|
||||
ssize_t PICloudClient::readDevice(void * read_to, ssize_t max_size) {
|
||||
if (is_deleted) return -1;
|
||||
//piCoutObj << "readDevice";
|
||||
if (!is_connected && eth.isClosed()) openDevice();
|
||||
int sz = -1;
|
||||
ssize_t sz = -1;
|
||||
mutex_buff.lock();
|
||||
cond_buff.wait(mutex_buff, [this](){return !buff.isEmpty() || !is_connected;});
|
||||
if (is_connected) {
|
||||
@@ -123,7 +123,7 @@ int PICloudClient::readDevice(void * read_to, int max_size) {
|
||||
}
|
||||
|
||||
|
||||
int PICloudClient::writeDevice(const void * data, int size) {
|
||||
ssize_t PICloudClient::writeDevice(const void * data, ssize_t size) {
|
||||
if (is_deleted) return -1;
|
||||
// piCoutObj << "writeDevice";
|
||||
return tcp.sendData(PIByteArray(data, size));
|
||||
|
||||
@@ -25,7 +25,7 @@ PICloudServer::PICloudServer(const PIString & path, PIIODevice::DeviceMode mode)
|
||||
tcp.setRole(PICloud::TCP::Server);
|
||||
tcp.setServerName(server_name);
|
||||
setName("cloud_server__" + server_name);
|
||||
CONNECTU(&streampacker, packetReceiveEvent, this, _readed);
|
||||
CONNECT1(void, PIByteArray, &streampacker, packetReceiveEvent, this, _readed);
|
||||
CONNECTL(ð, connected, [this](){opened_ = true; piCoutObj << "connected"; tcp.sendStart();});
|
||||
CONNECTL(ð, disconnected, [this](bool){
|
||||
piCoutObj << "disconnected";
|
||||
@@ -88,7 +88,7 @@ bool PICloudServer::closeDevice() {
|
||||
}
|
||||
|
||||
|
||||
int PICloudServer::readDevice(void * read_to, int max_size) {
|
||||
ssize_t PICloudServer::readDevice(void * read_to, ssize_t max_size) {
|
||||
//piCoutObj << "readDevice";
|
||||
if (!opened_) openDevice();
|
||||
else piMSleep(eth.readTimeout());
|
||||
@@ -96,7 +96,7 @@ int PICloudServer::readDevice(void * read_to, int max_size) {
|
||||
}
|
||||
|
||||
|
||||
int PICloudServer::writeDevice(const void * data, int max_size) {
|
||||
ssize_t PICloudServer::writeDevice(const void * data, ssize_t max_size) {
|
||||
//piCoutObj << "writeDevice";
|
||||
return -1;
|
||||
}
|
||||
@@ -145,9 +145,9 @@ bool PICloudServer::Client::closeDevice() {
|
||||
}
|
||||
|
||||
|
||||
int PICloudServer::Client::readDevice(void * read_to, int max_size) {
|
||||
ssize_t PICloudServer::Client::readDevice(void * read_to, ssize_t max_size) {
|
||||
if (!is_connected) return -1;
|
||||
int sz = -1;
|
||||
ssize_t sz = -1;
|
||||
mutex_buff.lock();
|
||||
cond_buff.wait(mutex_buff, [this](){return !buff.isEmpty() || !is_connected;});
|
||||
if (is_connected) {
|
||||
@@ -160,7 +160,7 @@ int PICloudServer::Client::readDevice(void * read_to, int max_size) {
|
||||
}
|
||||
|
||||
|
||||
int PICloudServer::Client::writeDevice(const void * data, int size) {
|
||||
ssize_t PICloudServer::Client::writeDevice(const void * data, ssize_t size) {
|
||||
return server->sendData(PIByteArray(data, size), client_id);
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@ void PICloudServer::_readed(PIByteArray & ba) {
|
||||
} else {
|
||||
//piCoutObj << "new Client" << id;
|
||||
Client * c = new Client(this, id);
|
||||
CONNECTU(c, deleted, this, clientDeleted);
|
||||
CONNECT1(void, PIObject *, c, deleted, this, clientDeleted);
|
||||
clients_mutex.lock();
|
||||
clients_ << c;
|
||||
index_clients.insert(id, c);
|
||||
|
||||
@@ -168,14 +168,14 @@ PIByteArray PICloud::TCP::parseConnect_d(PIByteArray & ba) {
|
||||
|
||||
|
||||
uint PICloud::TCP::parseConnect(PIByteArray & ba) {
|
||||
uint ret;
|
||||
uint ret = 0;
|
||||
ba >> ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
uint PICloud::TCP::parseDisconnect(PIByteArray & ba) {
|
||||
uint ret;
|
||||
uint ret = 0;
|
||||
ba >> ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ PIByteArray piCompress(const PIByteArray & ba, int level) {
|
||||
|
||||
PIByteArray piDecompress(const PIByteArray & zba) {
|
||||
#ifdef PIP_COMPRESS
|
||||
ullong sz;
|
||||
ullong sz = 0;
|
||||
if (zba.size() < sizeof(ullong)) {
|
||||
piCout << "[PICompress]" << "Error: invalid input";
|
||||
return zba;
|
||||
|
||||
@@ -51,6 +51,18 @@ PRIVATE_DEFINITION_END(PIScreen::SystemConsole)
|
||||
PIScreen::SystemConsole::SystemConsole() {
|
||||
width = height = pwidth = pheight = 0;
|
||||
mouse_x = mouse_y = -1;
|
||||
}
|
||||
|
||||
|
||||
PIScreen::SystemConsole::~SystemConsole() {
|
||||
#ifdef WINDOWS
|
||||
SetConsoleMode(PRIVATE->hOut, PRIVATE->smode);
|
||||
SetConsoleTextAttribute(PRIVATE->hOut, PRIVATE->dattr);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void PIScreen::SystemConsole::begin() {
|
||||
int w, h;
|
||||
#ifdef WINDOWS
|
||||
PRIVATE->ulcoord.X = 0;
|
||||
@@ -74,18 +86,6 @@ PIScreen::SystemConsole::SystemConsole() {
|
||||
# endif
|
||||
#endif
|
||||
resize(w, h);
|
||||
}
|
||||
|
||||
|
||||
PIScreen::SystemConsole::~SystemConsole() {
|
||||
#ifdef WINDOWS
|
||||
SetConsoleMode(PRIVATE->hOut, PRIVATE->smode);
|
||||
SetConsoleTextAttribute(PRIVATE->hOut, PRIVATE->dattr);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void PIScreen::SystemConsole::begin() {
|
||||
#ifdef WINDOWS
|
||||
SetConsoleMode(PRIVATE->hOut, ENABLE_WRAP_AT_EOL_OUTPUT);
|
||||
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi);
|
||||
@@ -93,6 +93,7 @@ void PIScreen::SystemConsole::begin() {
|
||||
PRIVATE->bc.Y = 0;
|
||||
#endif
|
||||
clear();
|
||||
clearScreen();
|
||||
hideCursor();
|
||||
}
|
||||
|
||||
@@ -391,18 +392,17 @@ PIScreen::PIScreen(bool startNow, PIKbdListener::KBFunc slot): PIThread(), drawe
|
||||
needLockRun(true);
|
||||
mouse_ = false;
|
||||
ret_func = slot;
|
||||
tile_focus = tile_dialog = 0;
|
||||
tile_focus = tile_dialog = nullptr;
|
||||
root.screen = this;
|
||||
listener = new PIKbdListener(key_eventS, this, startNow);
|
||||
CONNECTU(listener, mouseEvent, this, mouse_event);
|
||||
CONNECTU(listener, wheelEvent, this, wheel_event);
|
||||
CONNECT1(void, PIKbdListener::MouseEvent, listener, mouseEvent, this, mouse_event);
|
||||
CONNECT1(void, PIKbdListener::WheelEvent, listener, wheelEvent, this, wheel_event);
|
||||
if (startNow) start();
|
||||
}
|
||||
|
||||
|
||||
PIScreen::~PIScreen() {
|
||||
if (isRunning())
|
||||
stop();
|
||||
if (isRunning()) stop();
|
||||
PIThread::waitForFinish(10);
|
||||
listener->waitForFinish(10);
|
||||
delete listener;
|
||||
|
||||
@@ -538,12 +538,11 @@ TilePICout::TilePICout(const PIString & n): TileList(n) {
|
||||
max_lines = 1024;
|
||||
selection_mode = TileList::SingleSelection;
|
||||
PICout::setOutputDevices(PICout::Buffer);
|
||||
PICout::setBufferActive(true);
|
||||
}
|
||||
|
||||
|
||||
void TilePICout::drawEvent(PIScreenDrawer * d) {
|
||||
PIString out = PICout::buffer(true);
|
||||
PIString out = PICout::getBufferAndClear();
|
||||
if (!out.isEmpty()) {
|
||||
PIStringList l = out.split("\n");
|
||||
bool scroll = (cur == content.size_s() - 1) || !has_focus;
|
||||
|
||||
@@ -151,7 +151,7 @@ void PIBroadcast::initAll(PIVector<PIEthernet::Address> al) {
|
||||
//piCout << "mcast " << ce->readAddress() << ce->sendAddress();
|
||||
if (ce->open()) {
|
||||
eth_mcast << ce;
|
||||
CONNECTU(ce, threadedReadEvent, this, mcastRead);
|
||||
CONNECT2(void, const uchar *, ssize_t, ce, threadedReadEvent, this, mcastRead);
|
||||
} else {
|
||||
delete ce;
|
||||
}
|
||||
@@ -173,7 +173,7 @@ void PIBroadcast::initAll(PIVector<PIEthernet::Address> al) {
|
||||
//piCout << "bcast " << ce->readAddress() << ce->sendAddress();
|
||||
if (ce->open()) {
|
||||
eth_mcast << ce;
|
||||
CONNECTU(ce, threadedReadEvent, this, mcastRead);
|
||||
CONNECT2(void, const uchar *, ssize_t, ce, threadedReadEvent, this, mcastRead);
|
||||
} else {
|
||||
delete ce;
|
||||
}
|
||||
@@ -189,7 +189,7 @@ void PIBroadcast::initAll(PIVector<PIEthernet::Address> al) {
|
||||
eth_lo->setName("PIMulticast_loopback");
|
||||
if (!_send_only) {
|
||||
eth_lo->setParameter(PIEthernet::ReuseAddress, false);
|
||||
CONNECTU(eth_lo, threadedReadEvent, this, mcastRead);
|
||||
CONNECT2(void, const uchar *, ssize_t, eth_lo, threadedReadEvent, this, mcastRead);
|
||||
for (int i = 0; i < lo_pcnt; ++i) {
|
||||
eth_lo->setReadAddress("127.0.0.1", lo_port + i);
|
||||
if (eth_lo->open()) {
|
||||
@@ -248,7 +248,7 @@ void PIBroadcast::reinit() {
|
||||
}
|
||||
|
||||
|
||||
void PIBroadcast::mcastRead(uchar * data, int size) {
|
||||
void PIBroadcast::mcastRead(const uchar * data, ssize_t size) {
|
||||
PIByteArray cd = decryptData(PIByteArray(data, size));
|
||||
if (cd.isEmpty()) return;
|
||||
received(cd);
|
||||
|
||||
@@ -111,7 +111,7 @@ void PIStreamPacker::send(const PIByteArray & data) {
|
||||
}
|
||||
|
||||
|
||||
void PIStreamPacker::received(uchar * readed, int size) {
|
||||
void PIStreamPacker::received(const uchar * readed, ssize_t size) {
|
||||
received(PIByteArray(readed, size));
|
||||
}
|
||||
|
||||
@@ -195,8 +195,9 @@ void PIStreamPacker::received(const PIByteArray & data) {
|
||||
|
||||
void PIStreamPacker::assignDevice(PIIODevice * dev) {
|
||||
if (!dev) return;
|
||||
if (!dev->infoFlags()[PIIODevice::Reliable])
|
||||
if (!dev->infoFlags()[PIIODevice::Reliable]) {
|
||||
piCoutObj << "Warning! Not recommended to use with non-reliable" << dev;
|
||||
CONNECTU(dev, threadedReadEvent, this, received);
|
||||
CONNECTU(this, sendRequest, dev, write);
|
||||
}
|
||||
CONNECT2(void, const uchar *, ssize_t, dev, threadedReadEvent, this, received);
|
||||
CONNECT1(void, PIByteArray, this, sendRequest, dev, write);
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
class PIP_CLOUD_EXPORT PICloudClient: public PIIODevice, public PICloudBase
|
||||
{
|
||||
PIIODEVICE(PICloudClient, "")
|
||||
PIIODEVICE(PICloudClient, "");
|
||||
public:
|
||||
explicit PICloudClient(const PIString & path = PIString(), PIIODevice::DeviceMode mode = PIIODevice::ReadWrite);
|
||||
virtual ~PICloudClient();
|
||||
@@ -42,16 +42,17 @@ public:
|
||||
void setServerName(const PIString & server_name);
|
||||
void setKeepConnection(bool on);
|
||||
bool isConnected() const {return is_connected;}
|
||||
ssize_t bytesAvailable() const override {return buff.size();}
|
||||
|
||||
EVENT(connected)
|
||||
EVENT(disconnected)
|
||||
EVENT(connected);
|
||||
EVENT(disconnected);
|
||||
|
||||
protected:
|
||||
bool openDevice();
|
||||
bool closeDevice();
|
||||
int readDevice(void * read_to, int max_size);
|
||||
int writeDevice(const void * data, int size);
|
||||
DeviceInfoFlags deviceInfoFlags() const {return PIIODevice::Reliable;}
|
||||
bool openDevice() override;
|
||||
bool closeDevice() override;
|
||||
ssize_t readDevice(void * read_to, ssize_t max_size) override;
|
||||
ssize_t writeDevice(const void * data, ssize_t size) override;
|
||||
DeviceInfoFlags deviceInfoFlags() const override {return PIIODevice::Reliable;}
|
||||
|
||||
private:
|
||||
EVENT_HANDLER1(void, _readed, PIByteArray &, data);
|
||||
|
||||
@@ -32,24 +32,25 @@
|
||||
|
||||
class PIP_CLOUD_EXPORT PICloudServer: public PIIODevice, public PICloudBase
|
||||
{
|
||||
PIIODEVICE(PICloudServer, "")
|
||||
PIIODEVICE(PICloudServer, "");
|
||||
public:
|
||||
//! PICloudServer
|
||||
explicit PICloudServer(const PIString & path = PIString(), PIIODevice::DeviceMode mode = PIIODevice::ReadWrite);
|
||||
virtual ~PICloudServer();
|
||||
|
||||
class Client : public PIIODevice {
|
||||
PIIODEVICE(PICloudServer::Client, "")
|
||||
PIIODEVICE(PICloudServer::Client, "");
|
||||
friend class PICloudServer;
|
||||
public:
|
||||
Client(PICloudServer * srv = nullptr, uint id = 0);
|
||||
virtual ~Client();
|
||||
protected:
|
||||
bool openDevice();
|
||||
bool closeDevice();
|
||||
int readDevice(void * read_to, int max_size);
|
||||
int writeDevice(const void * data, int size);
|
||||
DeviceInfoFlags deviceInfoFlags() const {return PIIODevice::Reliable;}
|
||||
bool openDevice() override;
|
||||
bool closeDevice() override;
|
||||
ssize_t readDevice(void * read_to, ssize_t max_size) override;
|
||||
ssize_t writeDevice(const void * data, ssize_t size) override;
|
||||
DeviceInfoFlags deviceInfoFlags() const override {return PIIODevice::Reliable;}
|
||||
ssize_t bytesAvailable() const override {return buff.size();}
|
||||
|
||||
private:
|
||||
void pushBuffer(const PIByteArray & ba);
|
||||
@@ -65,13 +66,13 @@ public:
|
||||
|
||||
PIVector<PICloudServer::Client *> clients() const;
|
||||
|
||||
EVENT1(newConnection, PICloudServer::Client * , client)
|
||||
EVENT1(newConnection, PICloudServer::Client * , client);
|
||||
|
||||
protected:
|
||||
bool openDevice();
|
||||
bool closeDevice();
|
||||
int readDevice(void * read_to, int max_size);
|
||||
int writeDevice(const void * data, int max_size);
|
||||
bool openDevice() override;
|
||||
bool closeDevice() override;
|
||||
ssize_t readDevice(void * read_to, ssize_t max_size) override;
|
||||
ssize_t writeDevice(const void * data, ssize_t max_size) override;
|
||||
|
||||
private:
|
||||
EVENT_HANDLER1(void, _readed, PIByteArray &, ba);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*! \file picodeinfo.h
|
||||
* \ingroup Code
|
||||
* \~\brief
|
||||
* \~english C++ code info structs
|
||||
* \~russian Структуры для C++ кода
|
||||
* \~english C++ code info structs. See \ref code_model.
|
||||
* \~russian Структуры для C++ кода. Подробнее \ref code_model.
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
@@ -34,17 +34,24 @@
|
||||
|
||||
class PIVariant;
|
||||
|
||||
//! \~english Namespace contains structures for code generation. See \ref code_model.
|
||||
//! \~russian Пространство имен содержит структуры для кодогенерации. Подробнее \ref code_model.
|
||||
namespace PICodeInfo {
|
||||
|
||||
|
||||
//! \~english
|
||||
//! Type modifiers
|
||||
//! \~russian
|
||||
//! Модификаторы типа
|
||||
enum TypeFlag {
|
||||
NoFlag,
|
||||
Const = 0x01,
|
||||
Static = 0x02,
|
||||
Mutable = 0x04,
|
||||
Volatile = 0x08,
|
||||
Inline = 0x10,
|
||||
Virtual = 0x20,
|
||||
Extern = 0x40
|
||||
Const /** const */ = 0x01,
|
||||
Static /** static */ = 0x02,
|
||||
Mutable /** mutable */ = 0x04,
|
||||
Volatile /** volatile */ = 0x08,
|
||||
Inline /** inline */ = 0x10,
|
||||
Virtual /** virtual */ = 0x20,
|
||||
Extern /** extern */ = 0x40
|
||||
};
|
||||
|
||||
typedef PIFlags<PICodeInfo::TypeFlag> TypeFlags;
|
||||
@@ -52,49 +59,145 @@ typedef PIMap<PIString, PIString> MetaMap;
|
||||
typedef PIByteArray(*AccessValueFunction)(const void *, const char *);
|
||||
typedef const char*(*AccessTypeFunction)(const char *);
|
||||
|
||||
|
||||
//! \~english Type information
|
||||
//! \~russian Информация о типе
|
||||
struct PIP_EXPORT TypeInfo {
|
||||
TypeInfo(const PIConstChars & n = PIConstChars(), const PIConstChars & t = PIConstChars(), PICodeInfo::TypeFlags f = 0, int b = -1) {name = n; type = t; flags = f; bits = b;}
|
||||
|
||||
//! \~english Returns if variable if bitfield
|
||||
//! \~russian Возвращает битовым ли полем является переменная
|
||||
bool isBitfield() const {return bits > 0;}
|
||||
|
||||
//! \~english Custom PIMETA content
|
||||
//! \~russian Произвольное содержимое PIMETA
|
||||
MetaMap meta;
|
||||
|
||||
//! \~english Name
|
||||
//! \~russian Имя
|
||||
PIConstChars name;
|
||||
|
||||
//! \~english Type
|
||||
//! \~russian Тип
|
||||
PIConstChars type;
|
||||
|
||||
//! \~english Modifiers
|
||||
//! \~russian Модификаторы
|
||||
PICodeInfo::TypeFlags flags;
|
||||
|
||||
//! \~english Bitfield variable bit count
|
||||
//! \~russian Количество бит битового поля
|
||||
int bits;
|
||||
};
|
||||
|
||||
|
||||
//! \~english Method information
|
||||
//! \~russian Информация о методе
|
||||
struct PIP_EXPORT FunctionInfo {
|
||||
|
||||
//! \~english Custom PIMETA content
|
||||
//! \~russian Произвольное содержимое PIMETA
|
||||
MetaMap meta;
|
||||
|
||||
//! \~english Name
|
||||
//! \~russian Имя
|
||||
PIConstChars name;
|
||||
|
||||
//! \~english Return type
|
||||
//! \~russian Возвращаемые тип
|
||||
TypeInfo return_type;
|
||||
|
||||
//! \~english Arguments types
|
||||
//! \~russian Типы аргументов
|
||||
PIVector<PICodeInfo::TypeInfo> arguments;
|
||||
};
|
||||
|
||||
|
||||
//! \~english Class or struct information
|
||||
//! \~russian Информация о классе или структуре
|
||||
struct PIP_EXPORT ClassInfo {
|
||||
ClassInfo() {has_name = true;}
|
||||
|
||||
//! \~english Custom PIMETA content
|
||||
//! \~russian Произвольное содержимое PIMETA
|
||||
MetaMap meta;
|
||||
|
||||
//! \~english Has name or not
|
||||
//! \~russian Имеет или нет имя
|
||||
bool has_name;
|
||||
|
||||
//! \~english Type
|
||||
//! \~russian Тип
|
||||
PIConstChars type;
|
||||
|
||||
//! \~english Name
|
||||
//! \~russian Имя
|
||||
PIConstChars name;
|
||||
|
||||
//! \~english Parent names
|
||||
//! \~russian Имена родителей
|
||||
PIVector<PIConstChars> parents;
|
||||
|
||||
//! \~english Variables
|
||||
//! \~russian Переменные
|
||||
PIVector<PICodeInfo::TypeInfo> variables;
|
||||
|
||||
//! \~english Methods
|
||||
//! \~russian Методы
|
||||
PIVector<PICodeInfo::FunctionInfo> functions;
|
||||
|
||||
//! \~english Subclass list
|
||||
//! \~russian Список наследников
|
||||
PIVector<PICodeInfo::ClassInfo * > children_info;
|
||||
};
|
||||
|
||||
|
||||
//! \~english Enumerator information
|
||||
//! \~russian Информация об элементе перечисления
|
||||
struct PIP_EXPORT EnumeratorInfo {
|
||||
EnumeratorInfo(const PIConstChars & n = PIConstChars(), int v = 0) {name = n; value = v;}
|
||||
PIVariantTypes::Enumerator toPIVariantEnumerator() {return PIVariantTypes::Enumerator(value, name.toString());}
|
||||
|
||||
//! \~english Custom PIMETA content
|
||||
//! \~russian Произвольное содержимое PIMETA
|
||||
MetaMap meta;
|
||||
|
||||
//! \~english Name
|
||||
//! \~russian Имя
|
||||
PIConstChars name;
|
||||
|
||||
//! \~english Value
|
||||
//! \~russian Значение
|
||||
int value;
|
||||
};
|
||||
|
||||
|
||||
//! \~english Enum information
|
||||
//! \~russian Информация о перечислении
|
||||
struct PIP_EXPORT EnumInfo {
|
||||
|
||||
//! \~english Returns member name with value "value"
|
||||
//! \~russian Возвращает имя элемента со значением "value"
|
||||
PIString memberName(int value) const;
|
||||
|
||||
//! \~english Returns member value with name "name"
|
||||
//! \~russian Возвращает значение элемента с именем "name"
|
||||
int memberValue(const PIString & name) const;
|
||||
|
||||
//! \~english Returns as PIVariantTypes::Enum
|
||||
//! \~russian Возвращает как PIVariantTypes::Enum
|
||||
PIVariantTypes::Enum toPIVariantEnum();
|
||||
|
||||
//! \~english Custom PIMETA content
|
||||
//! \~russian Произвольное содержимое PIMETA
|
||||
MetaMap meta;
|
||||
|
||||
//! \~english Name
|
||||
//! \~russian Имя
|
||||
PIConstChars name;
|
||||
|
||||
//! \~english Members
|
||||
//! \~russian Элементы
|
||||
PIVector<PICodeInfo::EnumeratorInfo> members;
|
||||
};
|
||||
|
||||
@@ -115,7 +218,7 @@ inline PICout operator <<(PICout s, const PICodeInfo::TypeInfo & v) {
|
||||
inline PICout operator <<(PICout s, const PICodeInfo::EnumeratorInfo & v) {s << v.name << " = " << v.value << " Meta" << v.meta; return s;}
|
||||
|
||||
inline PICout operator <<(PICout s, const PICodeInfo::ClassInfo & v) {
|
||||
s.setControl(0, true);
|
||||
s.saveAndSetControls(0);
|
||||
s << "class " << v.name;
|
||||
if (!v.parents.isEmpty()) {
|
||||
s << ": ";
|
||||
@@ -143,12 +246,12 @@ inline PICout operator <<(PICout s, const PICodeInfo::ClassInfo & v) {
|
||||
s << PICoutManipulators::Tab << i << " Meta" << i.meta << ";\n";
|
||||
}
|
||||
s << "}\n";
|
||||
s.restoreControl();
|
||||
s.restoreControls();
|
||||
return s;
|
||||
}
|
||||
|
||||
inline PICout operator <<(PICout s, const PICodeInfo::EnumInfo & v) {
|
||||
s.setControl(0, true);
|
||||
s.saveAndSetControls(0);
|
||||
s << "enum " << v.name << " Meta" << v.meta << " {\n";
|
||||
for (const auto & i: v.members) {
|
||||
bool f = true;
|
||||
@@ -157,13 +260,21 @@ inline PICout operator <<(PICout s, const PICodeInfo::EnumInfo & v) {
|
||||
s << PICoutManipulators::Tab << i << "\n";
|
||||
}
|
||||
s << "}\n";
|
||||
s.restoreControl();
|
||||
s.restoreControls();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
//! \~english Pointer to single storage of PICodeInfo::ClassInfo, access by name
|
||||
//! \~russian Указатель на единое хренилище PICodeInfo::ClassInfo, доступ по имени
|
||||
extern PIP_EXPORT PIMap<PIConstChars, PICodeInfo::ClassInfo * > * classesInfo;
|
||||
|
||||
//! \~english Pointer to single storage of PICodeInfo::EnumInfo, access by name
|
||||
//! \~russian Указатель на единое хренилище PICodeInfo::EnumInfo, доступ по имени
|
||||
extern PIP_EXPORT PIMap<PIConstChars, PICodeInfo::EnumInfo * > * enumsInfo;
|
||||
|
||||
extern PIP_EXPORT PIMap<PIConstChars, PICodeInfo::AccessValueFunction> * accessValueFunctions;
|
||||
|
||||
extern PIP_EXPORT PIMap<PIConstChars, PICodeInfo::AccessTypeFunction> * accessTypeFunctions;
|
||||
|
||||
inline PIByteArray getMemberValue(const void * p, const char * class_name, const char * member_name) {
|
||||
|
||||
@@ -35,9 +35,11 @@
|
||||
//!
|
||||
//! \~english
|
||||
//! These files provides parsing C++ code and storage to use results of \a pip_cmg utility.
|
||||
//! See \ref code_model.
|
||||
//!
|
||||
//! \~russian
|
||||
//! Эти файлы обеспечивают разбор C++ кода и хранение результатов работы утилиты \a pip_cmg.
|
||||
//! Подробнее \ref code_model.
|
||||
//!
|
||||
//! \~\authors
|
||||
//! \~english
|
||||
|
||||
@@ -1050,7 +1050,7 @@ PIString PICodeParser::procMacros(PIString fc) {
|
||||
if (ifcnt > 0) ifcnt--;
|
||||
else {
|
||||
//piCout << "main endif" << skip << grab;
|
||||
if (grab) pfc << procMacros(nfc);
|
||||
if (grab) pfc += procMacros(nfc);
|
||||
skip = grab = false;
|
||||
continue;
|
||||
}
|
||||
@@ -1059,7 +1059,7 @@ PIString PICodeParser::procMacros(PIString fc) {
|
||||
//piCout << "main elif" << skip << grab << cond_ok;
|
||||
if (cond_ok) {
|
||||
if (grab) {
|
||||
pfc << procMacros(nfc);
|
||||
pfc += procMacros(nfc);
|
||||
skip = true; grab = false;
|
||||
}
|
||||
continue;
|
||||
@@ -1075,12 +1075,12 @@ PIString PICodeParser::procMacros(PIString fc) {
|
||||
}
|
||||
if (mif.left(4) == s_else && ifcnt == 0) {
|
||||
//piCout << "main else" << skip << grab;
|
||||
if (grab) pfc << procMacros(nfc);
|
||||
if (grab) pfc += procMacros(nfc);
|
||||
if (skip && !cond_ok) {skip = false; grab = true;}
|
||||
else {skip = true; grab = false;}
|
||||
continue;
|
||||
}
|
||||
if (grab) nfc << line << '\n';
|
||||
if (grab) nfc += line + '\n';
|
||||
continue;
|
||||
}
|
||||
if (mif.left(2) == s_if) {
|
||||
@@ -1095,8 +1095,8 @@ PIString PICodeParser::procMacros(PIString fc) {
|
||||
//return false; /// WARNING: now skip errors
|
||||
}
|
||||
} else {
|
||||
if (grab) nfc << line << '\n';
|
||||
else if (!skip) pfc << line << '\n';
|
||||
if (grab) nfc += line + '\n';
|
||||
else if (!skip) pfc += line + '\n';
|
||||
}
|
||||
}
|
||||
return pfc;
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
class PIP_EXPORT PIKbdListener: public PIThread
|
||||
{
|
||||
PIOBJECT_SUBCLASS(PIKbdListener, PIThread)
|
||||
PIOBJECT_SUBCLASS(PIKbdListener, PIThread);
|
||||
friend class PIConsole;
|
||||
friend class PITerminal;
|
||||
public:
|
||||
@@ -176,9 +176,9 @@ public:
|
||||
EVENT_HANDLER(void, setActive) {setActive(true);}
|
||||
EVENT_HANDLER1(void, setActive, bool, yes);
|
||||
|
||||
EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void * , data)
|
||||
EVENT2(mouseEvent, PIKbdListener::MouseEvent, mouse, void * , data)
|
||||
EVENT2(wheelEvent, PIKbdListener::WheelEvent, wheel, void * , data)
|
||||
EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void * , data);
|
||||
EVENT2(mouseEvent, PIKbdListener::MouseEvent, mouse, void * , data);
|
||||
EVENT2(wheelEvent, PIKbdListener::WheelEvent, wheel, void * , data);
|
||||
|
||||
//! \handlers
|
||||
//! \{
|
||||
@@ -205,9 +205,9 @@ public:
|
||||
static PIKbdListener * instance() {return _object;}
|
||||
|
||||
private:
|
||||
void begin();
|
||||
void run() {readKeyboard();}
|
||||
void end();
|
||||
void begin() override;
|
||||
void run() override {readKeyboard();}
|
||||
void end() override;
|
||||
|
||||
#ifndef WINDOWS
|
||||
struct PIP_EXPORT EscSeq {
|
||||
@@ -247,13 +247,27 @@ private:
|
||||
};
|
||||
|
||||
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIKbdListener::KeyEvent & v) {s << v.key << v.modifiers; return s;}
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIKbdListener::MouseEvent & v) {s << v.x << v.y << (int)v.action << v.buttons << v.modifiers; return s;}
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIKbdListener::WheelEvent & v) {s << (*(PIKbdListener::MouseEvent*)&v) << (uchar)v.direction; return s;}
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Store operator
|
||||
//! \~russian Оператор сохранения
|
||||
BINARY_STREAM_WRITE(PIKbdListener::MouseEvent) {s << v.x << v.y << v.action << v.buttons << v.modifiers; return s;}
|
||||
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Restore operator
|
||||
//! \~russian Оператор извлечения
|
||||
BINARY_STREAM_READ (PIKbdListener::MouseEvent) {s >> v.x >> v.y >> v.action >> v.buttons >> v.modifiers; return s;}
|
||||
|
||||
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Store operator
|
||||
//! \~russian Оператор сохранения
|
||||
BINARY_STREAM_WRITE(PIKbdListener::WheelEvent) {s << (*(PIKbdListener::MouseEvent*)&v) << v.direction; return s;}
|
||||
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Restore operator
|
||||
//! \~russian Оператор извлечения
|
||||
BINARY_STREAM_READ (PIKbdListener::WheelEvent) {s >> (*(PIKbdListener::MouseEvent*)&v) >> v.direction; return s;}
|
||||
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIKbdListener::KeyEvent & v) {s >> v.key >> v.modifiers; return s;}
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIKbdListener::MouseEvent & v) {int a(0); s >> v.x >> v.y >> a >> v.buttons >> v.modifiers; v.action = (PIKbdListener::MouseAction)a; return s;}
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIKbdListener::WheelEvent & v) {uchar d(0); s >> (*(PIKbdListener::MouseEvent*)&v) >> d; v.direction = d; return s;}
|
||||
|
||||
REGISTER_PIVARIANTSIMPLE(PIKbdListener::KeyEvent)
|
||||
REGISTER_PIVARIANTSIMPLE(PIKbdListener::MouseEvent)
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
class PIP_CONSOLE_EXPORT PIScreen: public PIThread, public PIScreenTypes::PIScreenBase
|
||||
{
|
||||
PIOBJECT_SUBCLASS(PIScreen, PIThread)
|
||||
PIOBJECT_SUBCLASS(PIScreen, PIThread);
|
||||
class SystemConsole;
|
||||
public:
|
||||
|
||||
@@ -76,8 +76,8 @@ public:
|
||||
EVENT_HANDLER0(void, stop) {stop(false);}
|
||||
EVENT_HANDLER1(void, stop, bool, clear);
|
||||
|
||||
EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void * , data)
|
||||
EVENT2(tileEvent, PIScreenTile * , tile, PIScreenTypes::TileEvent, e)
|
||||
EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void * , data);
|
||||
EVENT2(tileEvent, PIScreenTile * , tile, PIScreenTypes::TileEvent, e);
|
||||
|
||||
//! \handlers
|
||||
//! \{
|
||||
@@ -134,9 +134,9 @@ private:
|
||||
PIVector<PIVector<PIScreenTypes::Cell> > cells, pcells;
|
||||
};
|
||||
|
||||
void begin();
|
||||
void run();
|
||||
void end();
|
||||
void begin() override;
|
||||
void run() override;
|
||||
void end() override;
|
||||
void key_event(PIKbdListener::KeyEvent key);
|
||||
EVENT_HANDLER1(void, mouse_event, PIKbdListener::MouseEvent, me);
|
||||
EVENT_HANDLER1(void, wheel_event, PIKbdListener::WheelEvent, we);
|
||||
@@ -145,9 +145,9 @@ private:
|
||||
PIVector<PIScreenTile*> prepareMouse(PIKbdListener::MouseEvent * e);
|
||||
PIVector<PIScreenTile*> tilesUnderMouse(int x, int y);
|
||||
bool nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key = PIKbdListener::KeyEvent());
|
||||
void tileEventInternal(PIScreenTile * t, PIScreenTypes::TileEvent e);
|
||||
void tileRemovedInternal(PIScreenTile * t);
|
||||
void tileSetFocusInternal(PIScreenTile * t);
|
||||
void tileEventInternal(PIScreenTile * t, PIScreenTypes::TileEvent e) override;
|
||||
void tileRemovedInternal(PIScreenTile * t) override;
|
||||
void tileSetFocusInternal(PIScreenTile * t) override;
|
||||
|
||||
bool mouse_;
|
||||
SystemConsole console;
|
||||
|
||||
@@ -64,8 +64,8 @@ protected:
|
||||
};
|
||||
PIVector<Variable> variables;
|
||||
PIScreenTypes::Alignment alignment;
|
||||
void sizeHint(int & w, int & h) const;
|
||||
void drawEvent(PIScreenDrawer * d);
|
||||
void sizeHint(int & w, int & h) const override;
|
||||
void drawEvent(PIScreenDrawer * d) override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ class PIScreenDrawer;
|
||||
|
||||
class PIP_CONSOLE_EXPORT PIScreenTile: public PIObject {
|
||||
friend class PIScreen;
|
||||
PIOBJECT_SUBCLASS(PIScreenTile, PIObject)
|
||||
PIOBJECT_SUBCLASS(PIScreenTile, PIObject);
|
||||
public:
|
||||
PIScreenTile(const PIString & n = PIString(), PIScreenTypes::Direction d = PIScreenTypes::Vertical, PIScreenTypes::SizePolicy p = PIScreenTypes::Preferred);
|
||||
virtual ~PIScreenTile();
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
|
||||
class PIP_CONSOLE_EXPORT TileSimple: public PIScreenTile {
|
||||
PIOBJECT_SUBCLASS(TileSimple, PIScreenTile)
|
||||
PIOBJECT_SUBCLASS(TileSimple, PIScreenTile);
|
||||
public:
|
||||
typedef PIPair<PIString, PIScreenTypes::CellFormat> Row;
|
||||
TileSimple(const PIString & n = PIString());
|
||||
@@ -40,15 +40,15 @@ public:
|
||||
PIVector<Row> content;
|
||||
PIScreenTypes::Alignment alignment;
|
||||
protected:
|
||||
void sizeHint(int & w, int & h) const;
|
||||
void drawEvent(PIScreenDrawer * d);
|
||||
void sizeHint(int & w, int & h) const override;
|
||||
void drawEvent(PIScreenDrawer * d) override;
|
||||
};
|
||||
|
||||
|
||||
class TileList;
|
||||
|
||||
class PIP_CONSOLE_EXPORT TileScrollBar: public PIScreenTile {
|
||||
PIOBJECT_SUBCLASS(TileScrollBar, PIScreenTile)
|
||||
PIOBJECT_SUBCLASS(TileScrollBar, PIScreenTile);
|
||||
friend class TileList;
|
||||
public:
|
||||
TileScrollBar(const PIString & n = PIString());
|
||||
@@ -62,16 +62,16 @@ public:
|
||||
int thickness;
|
||||
protected:
|
||||
void _check();
|
||||
void sizeHint(int & w, int & h) const;
|
||||
void drawEvent(PIScreenDrawer * d);
|
||||
bool mouseEvent(PIKbdListener::MouseEvent me);
|
||||
void sizeHint(int & w, int & h) const override;
|
||||
void drawEvent(PIScreenDrawer * d) override;
|
||||
bool mouseEvent(PIKbdListener::MouseEvent me) override;
|
||||
int minimum_, maximum_, value_;
|
||||
PIChar line_char;
|
||||
};
|
||||
|
||||
|
||||
class PIP_CONSOLE_EXPORT TileList: public PIScreenTile {
|
||||
PIOBJECT_SUBCLASS(TileList, PIScreenTile)
|
||||
PIOBJECT_SUBCLASS(TileList, PIScreenTile);
|
||||
public:
|
||||
enum SelectionMode {
|
||||
NoSelection,
|
||||
@@ -93,19 +93,19 @@ public:
|
||||
PISet<int> selected;
|
||||
int lhei, cur, offset;
|
||||
protected:
|
||||
void sizeHint(int & w, int & h) const;
|
||||
void resizeEvent(int w, int h);
|
||||
void drawEvent(PIScreenDrawer * d);
|
||||
bool keyEvent(PIKbdListener::KeyEvent key);
|
||||
bool mouseEvent(PIKbdListener::MouseEvent me);
|
||||
bool wheelEvent(PIKbdListener::WheelEvent we);
|
||||
void sizeHint(int & w, int & h) const override;
|
||||
void resizeEvent(int w, int h) override;
|
||||
void drawEvent(PIScreenDrawer * d) override;
|
||||
bool keyEvent(PIKbdListener::KeyEvent key) override;
|
||||
bool mouseEvent(PIKbdListener::MouseEvent me) override;
|
||||
bool wheelEvent(PIKbdListener::WheelEvent we) override;
|
||||
TileScrollBar * scroll;
|
||||
bool mouse_sel;
|
||||
};
|
||||
|
||||
|
||||
class PIP_CONSOLE_EXPORT TileButton: public PIScreenTile {
|
||||
PIOBJECT_SUBCLASS(TileButton, PIScreenTile)
|
||||
PIOBJECT_SUBCLASS(TileButton, PIScreenTile);
|
||||
public:
|
||||
TileButton(const PIString & n = PIString());
|
||||
virtual ~TileButton() {}
|
||||
@@ -115,17 +115,17 @@ public:
|
||||
PIScreenTypes::CellFormat format;
|
||||
PIString text;
|
||||
protected:
|
||||
void sizeHint(int & w, int & h) const;
|
||||
void drawEvent(PIScreenDrawer * d);
|
||||
bool keyEvent(PIKbdListener::KeyEvent key);
|
||||
bool mouseEvent(PIKbdListener::MouseEvent me);
|
||||
void sizeHint(int & w, int & h) const override;
|
||||
void drawEvent(PIScreenDrawer * d) override;
|
||||
bool keyEvent(PIKbdListener::KeyEvent key) override;
|
||||
bool mouseEvent(PIKbdListener::MouseEvent me) override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
class PIP_CONSOLE_EXPORT TileButtons: public PIScreenTile {
|
||||
PIOBJECT_SUBCLASS(TileButtons, PIScreenTile)
|
||||
PIOBJECT_SUBCLASS(TileButtons, PIScreenTile);
|
||||
public:
|
||||
TileButtons(const PIString & n = PIString());
|
||||
virtual ~TileButtons() {}
|
||||
@@ -137,10 +137,10 @@ public:
|
||||
PIVector<Button> content;
|
||||
int cur;
|
||||
protected:
|
||||
void sizeHint(int & w, int & h) const;
|
||||
void drawEvent(PIScreenDrawer * d);
|
||||
bool keyEvent(PIKbdListener::KeyEvent key);
|
||||
bool mouseEvent(PIKbdListener::MouseEvent me);
|
||||
void sizeHint(int & w, int & h) const override;
|
||||
void drawEvent(PIScreenDrawer * d) override;
|
||||
bool keyEvent(PIKbdListener::KeyEvent key) override;
|
||||
bool mouseEvent(PIKbdListener::MouseEvent me) override;
|
||||
struct Rect {
|
||||
Rect(int _x0 = 0, int _y0 = 0, int _x1 = 0, int _y1 = 0): x0(_x0),y0(_y0),x1(_x1),y1(_y1) {}
|
||||
int x0,y0,x1,y1;
|
||||
@@ -150,7 +150,7 @@ protected:
|
||||
|
||||
|
||||
class PIP_CONSOLE_EXPORT TileCheck: public PIScreenTile {
|
||||
PIOBJECT_SUBCLASS(TileCheck, PIScreenTile)
|
||||
PIOBJECT_SUBCLASS(TileCheck, PIScreenTile);
|
||||
public:
|
||||
TileCheck(const PIString & n = PIString());
|
||||
virtual ~TileCheck() {}
|
||||
@@ -161,15 +161,15 @@ public:
|
||||
PIString text;
|
||||
bool toggled;
|
||||
protected:
|
||||
void sizeHint(int & w, int & h) const;
|
||||
void drawEvent(PIScreenDrawer * d);
|
||||
bool keyEvent(PIKbdListener::KeyEvent key);
|
||||
bool mouseEvent(PIKbdListener::MouseEvent me);
|
||||
void sizeHint(int & w, int & h) const override;
|
||||
void drawEvent(PIScreenDrawer * d) override;
|
||||
bool keyEvent(PIKbdListener::KeyEvent key) override;
|
||||
bool mouseEvent(PIKbdListener::MouseEvent me) override;
|
||||
};
|
||||
|
||||
|
||||
class PIP_CONSOLE_EXPORT TileProgress: public PIScreenTile {
|
||||
PIOBJECT_SUBCLASS(TileProgress, PIScreenTile)
|
||||
PIOBJECT_SUBCLASS(TileProgress, PIScreenTile);
|
||||
public:
|
||||
TileProgress(const PIString & n = PIString());
|
||||
virtual ~TileProgress() {}
|
||||
@@ -179,26 +179,26 @@ public:
|
||||
double maximum;
|
||||
double value;
|
||||
protected:
|
||||
void sizeHint(int & w, int & h) const;
|
||||
void drawEvent(PIScreenDrawer * d);
|
||||
void sizeHint(int & w, int & h) const override;
|
||||
void drawEvent(PIScreenDrawer * d) override;
|
||||
};
|
||||
|
||||
|
||||
class PIP_CONSOLE_EXPORT TilePICout: public TileList {
|
||||
PIOBJECT_SUBCLASS(TilePICout, PIScreenTile)
|
||||
PIOBJECT_SUBCLASS(TilePICout, PIScreenTile);
|
||||
public:
|
||||
TilePICout(const PIString & n = PIString());
|
||||
virtual ~TilePICout() {}
|
||||
PIScreenTypes::CellFormat format;
|
||||
int max_lines;
|
||||
protected:
|
||||
void drawEvent(PIScreenDrawer * d);
|
||||
bool keyEvent(PIKbdListener::KeyEvent key);
|
||||
void drawEvent(PIScreenDrawer * d) override;
|
||||
bool keyEvent(PIKbdListener::KeyEvent key) override;
|
||||
};
|
||||
|
||||
|
||||
class PIP_CONSOLE_EXPORT TileInput: public PIScreenTile {
|
||||
PIOBJECT_SUBCLASS(TileInput, PIScreenTile)
|
||||
PIOBJECT_SUBCLASS(TileInput, PIScreenTile);
|
||||
public:
|
||||
TileInput(const PIString & n = PIString());
|
||||
virtual ~TileInput() {}
|
||||
@@ -206,9 +206,9 @@ public:
|
||||
PIString text;
|
||||
int max_length;
|
||||
protected:
|
||||
void sizeHint(int & w, int & h) const;
|
||||
void drawEvent(PIScreenDrawer * d);
|
||||
bool keyEvent(PIKbdListener::KeyEvent key);
|
||||
void sizeHint(int & w, int & h) const override;
|
||||
void drawEvent(PIScreenDrawer * d) override;
|
||||
bool keyEvent(PIKbdListener::KeyEvent key) override;
|
||||
void reserCursor();
|
||||
int cur, offset;
|
||||
bool inv;
|
||||
|
||||
@@ -143,11 +143,30 @@ namespace PIScreenTypes {
|
||||
}
|
||||
|
||||
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIScreenTypes::Cell & v) {s << v.format.raw_format << v.symbol; return s;}
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIScreenTypes::Cell & v) {s >> v.format.raw_format >> v.symbol; return s;}
|
||||
//inline PIByteArray & operator <<(PIByteArray & s, const PIScreenTypes::Cell & v) {s << v.format.raw_format << v.symbol; return s;}
|
||||
//inline PIByteArray & operator >>(PIByteArray & s, PIScreenTypes::Cell & v) {s >> v.format.raw_format >> v.symbol; return s;}
|
||||
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Store operator
|
||||
//! \~russian Оператор сохранения
|
||||
BINARY_STREAM_WRITE(PIScreenTypes::Cell) {s << v.format.raw_format << v.symbol; return s;}
|
||||
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Restore operator
|
||||
//! \~russian Оператор извлечения
|
||||
BINARY_STREAM_READ (PIScreenTypes::Cell) {s >> v.format.raw_format >> v.symbol; return s;}
|
||||
|
||||
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Store operator
|
||||
//! \~russian Оператор сохранения
|
||||
BINARY_STREAM_WRITE(PIScreenTypes::TileEvent) {s << v.type << v.data; return s;}
|
||||
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Restore operator
|
||||
//! \~russian Оператор извлечения
|
||||
BINARY_STREAM_READ (PIScreenTypes::TileEvent) {s >> v.type >> v.data; return s;}
|
||||
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIScreenTypes::TileEvent & v) {s << v.type << v.data; return s;}
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIScreenTypes::TileEvent & v) {s >> v.type >> v.data; return s;}
|
||||
|
||||
REGISTER_PIVARIANTSIMPLE(PIScreenTypes::TileEvent)
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
class PIP_CONSOLE_EXPORT PITerminal: public PIThread
|
||||
{
|
||||
PIOBJECT_SUBCLASS(PITerminal, PIThread)
|
||||
PIOBJECT_SUBCLASS(PITerminal, PIThread);
|
||||
public:
|
||||
|
||||
//! Constructs %PITerminal
|
||||
@@ -58,7 +58,7 @@ private:
|
||||
void readConsole();
|
||||
void getCursor(int & x, int & y);
|
||||
uchar invertColor(uchar c);
|
||||
void run();
|
||||
void run() override;
|
||||
#ifndef WINDOWS
|
||||
void parseInput(const PIString & s);
|
||||
bool isCompleteEscSeq(const PIString & es);
|
||||
|
||||
@@ -20,11 +20,11 @@
|
||||
#include "picontainers.h"
|
||||
|
||||
|
||||
const ssize_t minAlloc = 64;
|
||||
const size_t minAlloc = 64;
|
||||
|
||||
|
||||
ssize_t _PIContainerConstantsBase::calcMinCountPoT(ssize_t szof) {
|
||||
ssize_t ret = 0, elc = 1;
|
||||
size_t _PIContainerConstantsBase::calcMinCountPoT(size_t szof) {
|
||||
size_t ret = 0, elc = 1;
|
||||
while (elc * szof < minAlloc) {
|
||||
elc *= 2;
|
||||
++ret;
|
||||
|
||||
@@ -65,13 +65,13 @@ private:
|
||||
|
||||
class PIP_EXPORT _PIContainerConstantsBase {
|
||||
public:
|
||||
static ssize_t calcMinCountPoT(ssize_t szof);
|
||||
static size_t calcMinCountPoT(size_t szof);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class _PIContainerConstants {
|
||||
public:
|
||||
static ssize_t minCountPoT() {static ssize_t ret = _PIContainerConstantsBase::calcMinCountPoT(sizeof(T)); return ret;}
|
||||
static size_t minCountPoT() {static size_t ret = _PIContainerConstantsBase::calcMinCountPoT(sizeof(T)); return ret;}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -645,7 +645,7 @@ public:
|
||||
inline size_t length() const {return pid_size;}
|
||||
|
||||
//! \~english Number of elements that the container has currently allocated space for.
|
||||
//! \~russian Количество элементов, для которого сейчас выделена память контейнером.
|
||||
//! \~russian Количество элементов, для которого сейчас выделена память массивом.
|
||||
//! \~\details
|
||||
//! \~english To find out the actual number of items, use the function \a size().
|
||||
//! \~russian Чтобы узнать фактическое количество элементов используйте функцию \a size().
|
||||
@@ -655,18 +655,18 @@ public:
|
||||
inline size_t _start() const {return pid_start;}
|
||||
|
||||
//! \~english Checks if the container has no elements.
|
||||
//! \~russian Проверяет пуст ли контейнер.
|
||||
//! \~russian Проверяет пуст ли массив.
|
||||
//! \~\return
|
||||
//! \~english **true** if the container is empty, **false** otherwise
|
||||
//! \~russian **true** если контейнер пуст, **false** иначе.
|
||||
//! \~russian **true** если массив пуст, **false** иначе.
|
||||
//! \~\sa \a size(), \a size_s(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
|
||||
inline bool isEmpty() const {return (pid_size == 0);}
|
||||
|
||||
//! \~english Checks if the container has elements.
|
||||
//! \~russian Проверяет не пуст ли контейнер.
|
||||
//! \~russian Проверяет не пуст ли массив.
|
||||
//! \~\return
|
||||
//! \~english **true** if the container is not empty, **false** otherwise
|
||||
//! \~russian **true** если контейнер не пуст, **false** иначе.
|
||||
//! \~russian **true** если массив не пуст, **false** иначе.
|
||||
//! \~\sa \a size(), \a size_s(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
|
||||
inline bool isNotEmpty() const {return (pid_size > 0);}
|
||||
|
||||
@@ -689,7 +689,7 @@ public:
|
||||
//! \endcode
|
||||
//! \~\sa \a every(), \a contains(), \a entries(), \a forEach()
|
||||
inline bool any(std::function<bool(const T & e)> test) const {
|
||||
for (ssize_t i = pid_start; i < pid_start + (ssize_t)pid_size; ++i) {
|
||||
for (size_t i = pid_start; i < pid_start + pid_size; ++i) {
|
||||
if (test(pid_data[i])) return true;
|
||||
}
|
||||
return false;
|
||||
@@ -714,7 +714,7 @@ public:
|
||||
//! \endcode
|
||||
//! \~\sa \a any(), \a contains(), \a entries(), \a forEach()
|
||||
inline bool every(std::function<bool(const T & e)> test) const {
|
||||
for (ssize_t i = pid_start; i < pid_start + (ssize_t)pid_size; ++i) {
|
||||
for (size_t i = pid_start; i < pid_start + pid_size; ++i) {
|
||||
if (!test(pid_data[i])) return false;
|
||||
}
|
||||
return true;
|
||||
@@ -825,7 +825,7 @@ public:
|
||||
start = pid_size + start;
|
||||
if (start < 0) start = 0;
|
||||
}
|
||||
for (ssize_t i = pid_start + start; i < pid_start + (ssize_t)pid_size; ++i) {
|
||||
for (size_t i = pid_start + size_t(start); i < pid_start + pid_size; ++i) {
|
||||
if (e == pid_data[i]) return true;
|
||||
}
|
||||
return false;
|
||||
@@ -856,13 +856,13 @@ public:
|
||||
//! piCout << v.entries(2, -4); // 2
|
||||
//! \endcode
|
||||
//! \~\sa \a every(), \a any(), \a contains(), \a forEach(), \a indexOf()
|
||||
inline int entries(const T & e, size_t start = 0) const {
|
||||
inline int entries(const T & e, ssize_t start = 0) const {
|
||||
int ec = 0;
|
||||
if (start < 0) {
|
||||
start = pid_size + start;
|
||||
if (start < 0) start = 0;
|
||||
}
|
||||
for (ssize_t i = pid_start + start; i < pid_start + (ssize_t)pid_size; ++i) {
|
||||
for (size_t i = pid_start + size_t(start); i < pid_start + pid_size; ++i) {
|
||||
if (e == pid_data[i]) ++ec;
|
||||
}
|
||||
return ec;
|
||||
@@ -890,13 +890,13 @@ public:
|
||||
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу.
|
||||
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
|
||||
//! \~\sa \a every(), \a any(), \a contains(), \a forEach(), \a indexWhere()
|
||||
inline int entries(std::function<bool(const T & e)> test, size_t start = 0) const {
|
||||
inline int entries(std::function<bool(const T & e)> test, ssize_t start = 0) const {
|
||||
int ec = 0;
|
||||
if (start < 0) {
|
||||
start = pid_size + start;
|
||||
if (start < 0) start = 0;
|
||||
}
|
||||
for (ssize_t i = pid_start + start; i < pid_start + (ssize_t)pid_size; ++i) {
|
||||
for (size_t i = pid_start + size_t(start); i < pid_start + pid_size; ++i) {
|
||||
if (test(pid_data[i])) ++ec;
|
||||
}
|
||||
return ec;
|
||||
@@ -931,14 +931,14 @@ public:
|
||||
//! piCout << v.indexOf(2, -3); // 0
|
||||
//! \endcode
|
||||
//! \~\sa \a indexWhere(), \a lastIndexOf(), \a lastIndexWhere(), \a contains()
|
||||
inline ssize_t indexOf(const T & e, size_t start = 0) const {
|
||||
inline ssize_t indexOf(const T & e, ssize_t start = 0) const {
|
||||
if (start < 0) {
|
||||
start = pid_size + start;
|
||||
if (start < 0) start = 0;
|
||||
}
|
||||
for (ssize_t i = pid_start + start; i < pid_start + (ssize_t)pid_size; ++i) {
|
||||
for (size_t i = pid_start + size_t(start); i < pid_start + pid_size; ++i) {
|
||||
if (e == pid_data[i]) {
|
||||
return i - pid_start;
|
||||
return ssize_t(i) - pid_start;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
@@ -972,14 +972,14 @@ public:
|
||||
//! piCout << v.indexWhere([](const PIString & s){return s.startsWith('k');}); // -1
|
||||
//! \endcode
|
||||
//! \~\sa \a indexOf(), \a lastIndexOf(), \a lastIndexWhere(), \a contains()
|
||||
inline ssize_t indexWhere(std::function<bool(const T & e)> test, size_t start = 0) const {
|
||||
inline ssize_t indexWhere(std::function<bool(const T & e)> test, ssize_t start = 0) const {
|
||||
if (start < 0) {
|
||||
start = pid_size + start;
|
||||
if (start < 0) start = 0;
|
||||
}
|
||||
for (ssize_t i = pid_start + start; i < pid_start + (ssize_t)pid_size; ++i) {
|
||||
for (size_t i = pid_start + size_t(start); i < pid_start + pid_size; ++i) {
|
||||
if (test(pid_data[i])) {
|
||||
return i - pid_start;
|
||||
return ssize_t(i) - pid_start;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
@@ -1022,9 +1022,9 @@ public:
|
||||
inline ssize_t lastIndexOf(const T & e, ssize_t start = -1) const {
|
||||
if (start >= size_s()) start = pid_size - 1;
|
||||
if (start < 0) start = pid_size + start;
|
||||
for (ssize_t i = pid_start + start; i >= pid_start; --i) {
|
||||
for (size_t i = pid_start + size_t(start); i >= pid_start; --i) {
|
||||
if (e == pid_data[i]) {
|
||||
return i - pid_start;
|
||||
return ssize_t(i) - pid_start;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
@@ -1058,9 +1058,9 @@ public:
|
||||
inline ssize_t lastIndexWhere(std::function<bool(const T & e)> test, ssize_t start = -1) const {
|
||||
if (start >= size_s()) start = pid_size - 1;
|
||||
if (start < 0) start = pid_size + start;
|
||||
for (ssize_t i = pid_start + start; i >= pid_start; --i) {
|
||||
for (size_t i = pid_start + size_t(start); i >= pid_start; --i) {
|
||||
if (test(pid_data[i])) {
|
||||
return i - pid_start;
|
||||
return ssize_t(i) - pid_start;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
@@ -1406,7 +1406,7 @@ public:
|
||||
inline PIDeque<T> & insert(size_t index, std::initializer_list<T> init_list) {
|
||||
bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false);
|
||||
if (dir) {
|
||||
ssize_t os = pid_size - index;
|
||||
ssize_t os = ssize_t(pid_size) - index;
|
||||
alloc_forward(pid_size + init_list.size());
|
||||
if (os > 0) {
|
||||
memmove((void*)(&(pid_data[index + pid_start + init_list.size()])), (const void*)(&(pid_data[index + pid_start])), os * sizeof(T));
|
||||
@@ -1461,7 +1461,7 @@ public:
|
||||
piSwap<T*>(pid_data, other.pid_data);
|
||||
piSwap<size_t>(pid_size, other.pid_size);
|
||||
piSwap<size_t>(pid_rsize, other.pid_rsize);
|
||||
piSwap<ssize_t>(pid_start, other.pid_start);
|
||||
piSwap<size_t>(pid_start, other.pid_start);
|
||||
}
|
||||
|
||||
//! \~english Sorts the elements in non-descending order.
|
||||
@@ -1572,10 +1572,10 @@ public:
|
||||
//! Если `add_size < 0`, то с конца массива удаляются элементы.
|
||||
//! Если `add_size < 0` и в массиве меньше элементов чем указано, то массив становится пустым.
|
||||
//! \~\sa \a resize()
|
||||
inline PIDeque<T> & enlarge(llong pid_size) {
|
||||
llong ns = size_s() + pid_size;
|
||||
inline PIDeque<T> & enlarge(ssize_t add_size, const T & e = T()) {
|
||||
ssize_t ns = size_s() + add_size;
|
||||
if (ns <= 0) clear();
|
||||
else resize(size_t(ns));
|
||||
else resize(size_t(ns), e);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -1608,7 +1608,7 @@ public:
|
||||
//! \endcode
|
||||
//! \~\sa \a remove(), \a removeOne(), \a removeWhere()
|
||||
inline PIDeque<T> & removeAll(const T & e) {
|
||||
for (ssize_t i = 0; i < ssize_t(pid_size); ++i) {
|
||||
for (size_t i = 0; i < pid_size; ++i) {
|
||||
if (pid_data[i + pid_start] == e) {
|
||||
remove(i);
|
||||
--i;
|
||||
@@ -1629,7 +1629,7 @@ public:
|
||||
//! \endcode
|
||||
//! \~\sa \a remove(), \a removeOne(), \a removeWhere()
|
||||
inline PIDeque<T> & removeWhere(std::function<bool(const T & e)> test) {
|
||||
for (ssize_t i = 0; i < ssize_t(pid_size); ++i) {
|
||||
for (size_t i = 0; i < pid_size; ++i) {
|
||||
if (test(pid_data[i + pid_start])) {
|
||||
remove(i);
|
||||
--i;
|
||||
@@ -1938,7 +1938,7 @@ public:
|
||||
//! Добавляет элементы из
|
||||
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
|
||||
//! \~\sa \a append()
|
||||
inline PIDeque<T> & prepend(std::initializer_list<T> init_list) {return prepend(init_list);}
|
||||
inline PIDeque<T> & prepend(std::initializer_list<T> init_list) {return push_front(init_list);}
|
||||
|
||||
//! \~english Remove one element from the end of the array.
|
||||
//! \~russian Удаляет один элемент с конца массива.
|
||||
@@ -2280,7 +2280,8 @@ private:
|
||||
if (pid_rsize + pid_rsize >= size_t(s) && pid_rsize < size_t(s)) {
|
||||
return pid_rsize + pid_rsize;
|
||||
}
|
||||
ssize_t t = _PIContainerConstants<T>::minCountPoT(), s_ = s - 1;
|
||||
size_t t = _PIContainerConstants<T>::minCountPoT();
|
||||
size_t s_ = s - 1;
|
||||
while (s_ >> t)
|
||||
++t;
|
||||
return (1 << t);
|
||||
@@ -2348,8 +2349,8 @@ private:
|
||||
inline void checkMove() {
|
||||
if (pid_size >= 4) {
|
||||
if (pid_size < pid_rsize / 6) {
|
||||
if (pid_start < ssize_t(pid_size + pid_size) || pid_start > (ssize_t(pid_rsize) - ssize_t(pid_size) - ssize_t(pid_size))) {
|
||||
ssize_t ns = (pid_rsize - pid_size) / 2;
|
||||
if (pid_start < (pid_size + pid_size) || ssize_t(pid_start) > (ssize_t(pid_rsize) - ssize_t(pid_size) - ssize_t(pid_size))) {
|
||||
size_t ns = (pid_rsize - pid_size) / 2;
|
||||
if (pid_start != ns) {
|
||||
memmove((void*)(pid_data + ns), (const void*)(pid_data + pid_start), pid_size * sizeof(T));
|
||||
pid_start = ns;
|
||||
@@ -2357,7 +2358,7 @@ private:
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ssize_t ns = (pid_rsize - pid_size) / 2;
|
||||
size_t ns = (pid_rsize - pid_size) / 2;
|
||||
if (pid_start != ns) {
|
||||
memmove((void*)(pid_data + ns), (const void*)(pid_data + pid_start), pid_size * sizeof(T));
|
||||
pid_start = ns;
|
||||
@@ -2387,14 +2388,14 @@ private:
|
||||
}
|
||||
inline void alloc_backward(size_t new_size, ssize_t start_offset = 0) { //alloc backward
|
||||
size_t as;
|
||||
if (pid_start + start_offset < 0) {
|
||||
if (ssize_t(pid_start) + start_offset < 0) {
|
||||
as = asize(pid_rsize - start_offset);
|
||||
} else {
|
||||
as = pid_rsize;
|
||||
}
|
||||
if (as > pid_rsize) {
|
||||
T * td = (T*)(malloc(as * sizeof(T)));
|
||||
ssize_t ns = pid_start + as - pid_rsize;
|
||||
size_t ns = pid_start + as - pid_rsize;
|
||||
PIINTROSPECTION_CONTAINER_ALLOC(T, (as-pid_rsize))
|
||||
if (pid_rsize > 0 && pid_data != 0) {
|
||||
memcpy((void*)(td + ns), (const void*)(pid_data + pid_start), pid_size * sizeof(T));
|
||||
@@ -2410,8 +2411,9 @@ private:
|
||||
}
|
||||
|
||||
T * pid_data;
|
||||
size_t pid_size, pid_rsize;
|
||||
ssize_t pid_start;
|
||||
size_t pid_size;
|
||||
size_t pid_rsize;
|
||||
size_t pid_start;
|
||||
};
|
||||
|
||||
|
||||
@@ -2437,14 +2439,14 @@ inline std::ostream & operator <<(std::ostream & s, const PIDeque<T> & v) {
|
||||
template<typename T>
|
||||
inline PICout operator <<(PICout s, const PIDeque<T> & v) {
|
||||
s.space();
|
||||
s.setControl(0, true);
|
||||
s.saveAndSetControls(0);
|
||||
s << "{";
|
||||
for (size_t i = 0; i < v.size(); ++i) {
|
||||
s << v[i];
|
||||
if (i < v.size() - 1) s << ", ";
|
||||
}
|
||||
s << "}";
|
||||
s.restoreControl();
|
||||
s.restoreControls();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
|
||||
* \fn PIMap::PIMap(const PIMap & other);
|
||||
* \brief Contructs a copy of "other"
|
||||
*
|
||||
*
|
||||
*
|
||||
|
||||
* \fn PIMapIterator PIMap::makeIterator() const
|
||||
* \brief Returns PIMapIterator for this map
|
||||
|
||||
@@ -1,8 +1,17 @@
|
||||
/*! \file pimap.h
|
||||
* \brief Associative array with custom types of key and value
|
||||
*
|
||||
* This file declares PIMap
|
||||
*/
|
||||
//! \addtogroup Containers
|
||||
//! \{
|
||||
//! \file pideque.h
|
||||
//! \brief
|
||||
//! \~english Declares \a PIMap
|
||||
//! \~russian Объявление \a PIMap
|
||||
//! \~\authors
|
||||
//! \~english
|
||||
//! Ivan Pelipenko peri4ko@yandex.ru;
|
||||
//! Andrey Bychkov work.a.b@yandex.ru;
|
||||
//! \~russian
|
||||
//! Иван Пелипенко peri4ko@yandex.ru;
|
||||
//! Андрей Бычков work.a.b@yandex.ru;
|
||||
//! \~\}
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Associative array with custom types of key and value
|
||||
@@ -30,60 +39,85 @@
|
||||
#include "pipair.h"
|
||||
|
||||
|
||||
template<class T>
|
||||
void piQuickSort(T * a, ssize_t N) {
|
||||
if (N < 1) return;
|
||||
if (N < 46) {
|
||||
T tmp;
|
||||
ssize_t i,j;
|
||||
for(i=1; i<=N; i++) {
|
||||
tmp = a[i];
|
||||
j = i-1;
|
||||
while(tmp<a[j] && j>=0) {
|
||||
a[j+1] = a[j];
|
||||
j = j-1;
|
||||
}
|
||||
a[j+1] = tmp;
|
||||
}
|
||||
} else {
|
||||
ssize_t i = 0, j = N;
|
||||
T & p(a[N >> 1]);
|
||||
do {
|
||||
while (a[i] < p) i++;
|
||||
while (a[j] > p) j--;
|
||||
if (i <= j) {
|
||||
if (i != j) {
|
||||
//piCout << "swap" << i << j << a[i] << a[j];
|
||||
piSwap<T>(a[i], a[j]);
|
||||
}
|
||||
i++; j--;
|
||||
}
|
||||
} while (i <= j);
|
||||
if (j > 0) piQuickSort(a, j);
|
||||
if (N > i) piQuickSort(a + i, N - i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename Key, typename T>
|
||||
class PIMapIterator;
|
||||
template <typename Key, typename T> class PIMapIteratorConst;
|
||||
template <typename Key, typename T> class PIMapIteratorConstReverse;
|
||||
template <typename Key, typename T> class PIMapIterator;
|
||||
template <typename Key, typename T> class PIMapIteratorReverse;
|
||||
|
||||
|
||||
//! \addtogroup Containers
|
||||
//! \{
|
||||
//! \class PIMap
|
||||
//! \brief
|
||||
//! \~english Associative array.
|
||||
//! \~russian Словарь.
|
||||
//! \~\}
|
||||
//! \details
|
||||
//! \~english
|
||||
//! A collection of key/value pairs, from which you retrieve a value using its associated key.
|
||||
//! There is a finite number of keys in the map, and each key has exactly one value associated with it.
|
||||
//! \a value() returns value for key and leave map
|
||||
//! unchaged in any case. \a operator [] create entry in map if
|
||||
//! there is no entry for given key. You can retrieve all
|
||||
//! keys by method \a keys() and all values by methos \a values().
|
||||
//! To iterate all entries use class PIMapIterator, or methods
|
||||
//! \a makeIterator() and \a makeReverseIterator().
|
||||
//! A key in the Map may only occur once.
|
||||
//! \~russian
|
||||
//! Словари, в принципе, похожи на обычные, используемые в повседневной жизни.
|
||||
//! Они хранят элементы одного и того же типа, индексируемые ключевыми значениями.
|
||||
//! Достоинство словаря в том, что он позволяет быстро получать значение,
|
||||
//! ассоциированное с заданным ключом.
|
||||
//! Ключи должны быть уникальными.
|
||||
//! Элемент
|
||||
//! В контейнеры этого типа заносятся элементы вместе с ключами,
|
||||
//! по которым их можно найти, которыми могут выступать значения любого типа.
|
||||
//! \a operator [] позволяет получить доступ к элементу по ключу,
|
||||
//! и если такого эелемента не было, то он будет создан.
|
||||
template <typename Key, typename T>
|
||||
class PIMap {
|
||||
template <typename Key1, typename T1> friend PIByteArray & operator >>(PIByteArray & s, PIMap<Key1, T1> & v);
|
||||
template <typename Key1, typename T1> friend PIByteArray & operator <<(PIByteArray & s, const PIMap<Key1, T1> & v);
|
||||
template <typename Key1, typename T1> friend class PIMapIteratorConst;
|
||||
template <typename Key1, typename T1> friend class PIMapIteratorConstReverse;
|
||||
template <typename Key1, typename T1> friend class PIMapIterator;
|
||||
template <typename Key1, typename T1> friend class PIMapIteratorReverse;
|
||||
template <typename P, typename Key1, typename T1>
|
||||
friend PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIMap<Key1, T1> & v);
|
||||
template <typename P, typename Key1, typename T1>
|
||||
friend PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIMap<Key1, T1> & v);
|
||||
public:
|
||||
PIMap() {;}
|
||||
PIMap(const PIMap<Key, T> & other) {*this = other;}
|
||||
PIMap(PIMap<Key, T> && other) : pim_content(std::move(other.pim_content)), pim_index(std::move(other.pim_index)) {}
|
||||
PIMap(std::initializer_list<std::pair<Key, T>> init_list) {
|
||||
for (auto i: init_list)
|
||||
insert(std::get<0>(i), std::get<1>(i));
|
||||
}
|
||||
virtual ~PIMap() {;}
|
||||
typedef T mapped_type;
|
||||
typedef Key key_type;
|
||||
typedef PIPair<Key, T> value_type;
|
||||
|
||||
//! \~english Constructs an empty map.
|
||||
//! \~russian Создает пустой словарь.
|
||||
PIMap() {}
|
||||
|
||||
//! \~english Copy constructor.
|
||||
//! \~russian Копирующий конструктор.
|
||||
PIMap(const PIMap<Key, T> & other) {*this = other;}
|
||||
|
||||
//! \~english Move constructor.
|
||||
//! \~russian Перемещающий конструктор.
|
||||
PIMap(PIMap<Key, T> && other) : pim_content(std::move(other.pim_content)), pim_index(std::move(other.pim_index)) {}
|
||||
|
||||
//! \~english Contructs map from
|
||||
//! [C++11 initializer list](https://en.cppreference.com/w/cpp/utility/initializer_list).
|
||||
//! \~russian Создает словарь из
|
||||
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
|
||||
//! \~\details
|
||||
//! \~\code
|
||||
//! PIMap <int, PIString> m{{1, "a"}, {2, "b"}};
|
||||
//! piCout << m; // {1, 2, 3}
|
||||
//! \endcode
|
||||
PIMap(std::initializer_list<std::pair<Key, T>> init_list) {
|
||||
for (auto i: init_list) {
|
||||
insert(std::get<0>(i), std::get<1>(i));
|
||||
}
|
||||
}
|
||||
|
||||
//! \~english Assign operator.
|
||||
//! \~russian Оператор присваивания.
|
||||
PIMap<Key, T> & operator =(const PIMap<Key, T> & other) {
|
||||
if (this == &other) return *this;
|
||||
clear();
|
||||
@@ -92,14 +126,12 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Assign move operator.
|
||||
//! \~russian Оператор перемещающего присваивания.
|
||||
PIMap<Key, T> & operator =(PIMap<Key, T> && other) {
|
||||
swap(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
typedef T mapped_type;
|
||||
typedef Key key_type;
|
||||
typedef PIPair<Key, T> value_type;
|
||||
|
||||
class iterator {
|
||||
friend class PIMap<Key, T>;
|
||||
@@ -108,10 +140,12 @@ public:
|
||||
const PIMap<Key, T> * parent;
|
||||
ssize_t pos;
|
||||
public:
|
||||
iterator(): parent(0), pos(0) {}
|
||||
iterator(): parent(nullptr), pos(0) {}
|
||||
const Key & key() const {return const_cast<PIMap<Key, T> * >(parent)->_key(pos);}
|
||||
T & value() {return const_cast<PIMap<Key, T> * >(parent)->_value(pos);}
|
||||
inline PIPair<Key, T> operator *() const {return PIPair<Key, T>(const_cast<PIMap<Key, T> * >(parent)->_key(pos), const_cast<PIMap<Key, T> * >(parent)->_value(pos));}
|
||||
inline PIPair<Key, T> operator *() const {
|
||||
return PIPair<Key, T>(const_cast<PIMap<Key, T> * >(parent)->_key(pos), const_cast<PIMap<Key, T> * >(parent)->_value(pos));
|
||||
}
|
||||
void operator ++() {++pos;}
|
||||
void operator ++(int) {++pos;}
|
||||
void operator --() {--pos;}
|
||||
@@ -127,10 +161,12 @@ public:
|
||||
const PIMap<Key, T> * parent;
|
||||
ssize_t pos;
|
||||
public:
|
||||
reverse_iterator(): parent(0), pos(0) {}
|
||||
reverse_iterator(): parent(nullptr), pos(0) {}
|
||||
const Key & key() const {return const_cast<PIMap<Key, T> * >(parent)->_key(pos);}
|
||||
T & value() const {return const_cast<PIMap<Key, T> * >(parent)->_value(pos);}
|
||||
inline PIPair<Key, T> operator *() const {return PIPair<Key, T>(const_cast<PIMap<Key, T> * >(parent)->_key(pos), const_cast<PIMap<Key, T> * >(parent)->_value(pos));}
|
||||
inline PIPair<Key, T> operator *() const {
|
||||
return PIPair<Key, T>(const_cast<PIMap<Key, T> * >(parent)->_key(pos), const_cast<PIMap<Key, T> * >(parent)->_value(pos));
|
||||
}
|
||||
void operator ++() {--pos;}
|
||||
void operator ++(int) {--pos;}
|
||||
void operator --() {++pos;}
|
||||
@@ -146,9 +182,8 @@ public:
|
||||
const PIMap<Key, T> * parent;
|
||||
ssize_t pos;
|
||||
public:
|
||||
const_iterator(): parent(0), pos(0) {}
|
||||
const_iterator(): parent(nullptr), pos(0) {}
|
||||
const value_type operator *() const {return parent->_pair(pos);}
|
||||
const value_type* operator ->() const {cval = parent->_pair(pos); return &cval;}
|
||||
const Key & key() const {return const_cast<PIMap<Key, T> * >(parent)->_key(pos);}
|
||||
const T & value() const {return const_cast<PIMap<Key, T> * >(parent)->_value(pos);}
|
||||
void operator ++() {++pos;}
|
||||
@@ -157,7 +192,6 @@ public:
|
||||
void operator --(int) {--pos;}
|
||||
bool operator ==(const const_iterator & it) const {return (pos == it.pos);}
|
||||
bool operator !=(const const_iterator & it) const {return (pos != it.pos);}
|
||||
mutable value_type cval;
|
||||
};
|
||||
|
||||
class const_reverse_iterator {
|
||||
@@ -167,38 +201,62 @@ public:
|
||||
const PIMap<Key, T> * parent;
|
||||
ssize_t pos;
|
||||
public:
|
||||
const_reverse_iterator(): parent(0), pos(0) {}
|
||||
const_reverse_iterator(): parent(nullptr), pos(0) {}
|
||||
const value_type operator *() const {return parent->_pair(pos);}
|
||||
const value_type* operator ->() const {cval = parent->_pair(pos); return &cval;}
|
||||
void operator ++() {--pos;}
|
||||
void operator ++(int) {--pos;}
|
||||
void operator --() {++pos;}
|
||||
void operator --(int) {++pos;}
|
||||
bool operator ==(const const_reverse_iterator & it) const {return (pos == it.pos);}
|
||||
bool operator !=(const const_reverse_iterator & it) const {return (pos != it.pos);}
|
||||
mutable value_type cval;
|
||||
};
|
||||
|
||||
|
||||
iterator begin() {return iterator(this, 0);}
|
||||
|
||||
iterator end() {return iterator(this, size());}
|
||||
|
||||
const_iterator begin() const {return const_iterator(this, 0);}
|
||||
|
||||
const_iterator end() const {return const_iterator(this, size());}
|
||||
|
||||
const_iterator constBegin() const {return const_iterator(this, 0);}
|
||||
|
||||
const_iterator constEnd() const {return const_iterator(this, size());}
|
||||
|
||||
reverse_iterator rbegin() {return reverse_iterator(this, size() - 1);}
|
||||
|
||||
reverse_iterator rend() {return reverse_iterator(this, -1);}
|
||||
|
||||
const_reverse_iterator rbegin() const {return const_reverse_iterator(this, size() - 1);}
|
||||
|
||||
const_reverse_iterator rend() const {return const_reverse_iterator(this, -1);}
|
||||
|
||||
const_reverse_iterator constRbegin() const {return const_reverse_iterator(this, size() - 1);}
|
||||
|
||||
const_reverse_iterator constRend() const {return const_reverse_iterator(this, -1);}
|
||||
|
||||
PIMapIterator<Key, T> makeIterator() const {return PIMapIterator<Key, T>(*this);}
|
||||
PIMapIterator<Key, T> makeReverseIterator() const {return PIMapIterator<Key, T>(*this, true);}
|
||||
//! \relatesalso PIMapIteratorConst
|
||||
PIMapIteratorConst<Key, T> makeIterator() const {return PIMapIteratorConst<Key, T>(*this);}
|
||||
|
||||
//! \relatesalso PIMapIterator
|
||||
PIMapIterator<Key, T> makeIterator() {return PIMapIterator<Key, T>(*this);}
|
||||
|
||||
//! \relatesalso PIMapIteratorConstReverse
|
||||
PIMapIteratorConstReverse<Key, T> makeReverseIterator() const {return PIMapIteratorConstReverse<Key, T>(*this);}
|
||||
|
||||
//! \relatesalso PIMapIteratorReverse
|
||||
PIMapIteratorReverse<Key, T> makeReverseIterator() {return PIMapIteratorReverse<Key, T>(*this);}
|
||||
|
||||
size_t size() const {return pim_content.size();}
|
||||
|
||||
int size_s() const {return pim_content.size_s();}
|
||||
|
||||
size_t length() const {return pim_content.size();}
|
||||
|
||||
bool isEmpty() const {return (pim_content.size() == 0);}
|
||||
|
||||
bool isNotEmpty() const {return (pim_content.size() > 0);}
|
||||
|
||||
T & operator [](const Key & key) {
|
||||
bool f(false);
|
||||
@@ -208,8 +266,16 @@ public:
|
||||
pim_index.insert(i, MapIndex(key, pim_content.size() - 1));
|
||||
return pim_content.back();
|
||||
}
|
||||
const T operator [](const Key & key) const {bool f(false); ssize_t i = _find(key, f); if (f) return pim_content[pim_index[i].index]; return T();}
|
||||
const T at(const Key & key) const {return (*this)[key];}
|
||||
T at(const Key & key) const {return value(key);}
|
||||
|
||||
T take(const Key & key) const {
|
||||
bool f(false);
|
||||
ssize_t i = _find(key, f);
|
||||
if (!f) return T();
|
||||
T ret(pim_content[pim_index[i].index]);
|
||||
_remove(i);
|
||||
return ret;
|
||||
}
|
||||
|
||||
PIMap<Key, T> & operator <<(const PIMap<Key, T> & other) {
|
||||
#ifndef NDEBUG
|
||||
@@ -219,23 +285,66 @@ public:
|
||||
#endif
|
||||
assert(&other != this);
|
||||
if (other.isEmpty()) return *this;
|
||||
if (other.size() == 1) {insert(other.pim_index[0].key, other.pim_content[0]); return *this;}
|
||||
if (other.size() == 2) {insert(other.pim_index[0].key, other.pim_content[0]); insert(other.pim_index[1].key, other.pim_content[1]); return *this;}
|
||||
for (int i = 0; i < other.pim_index.size_s(); ++i)
|
||||
if (other.size() == 1) {
|
||||
insert(other.pim_index[0].key, other.pim_content[0]);
|
||||
return *this;
|
||||
}
|
||||
if (other.size() == 2) {
|
||||
insert(other.pim_index[0].key, other.pim_content[0]);
|
||||
insert(other.pim_index[1].key, other.pim_content[1]);
|
||||
return *this;
|
||||
}
|
||||
for (int i = 0; i < other.pim_index.size_s(); ++i) {
|
||||
insert(other.pim_index[i].key, other.pim_content[other.pim_index[i].index]);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator ==(const PIMap<Key, T> & t) const {return (pim_content == t.pim_content && pim_index == t.pim_index);}
|
||||
bool operator !=(const PIMap<Key, T> & t) const {return (pim_content != t.pim_content || pim_index != t.pim_index);}
|
||||
bool contains(const Key & key) const {bool f(false); _find(key, f); return f;}
|
||||
bool operator ==(const PIMap<Key, T> & t) const {
|
||||
return (pim_content == t.pim_content && pim_index == t.pim_index);
|
||||
}
|
||||
bool operator !=(const PIMap<Key, T> & t) const {
|
||||
return (pim_content != t.pim_content || pim_index != t.pim_index);
|
||||
}
|
||||
bool contains(const Key & key) const {
|
||||
bool f(false); _find(key, f);
|
||||
return f;
|
||||
}
|
||||
|
||||
PIMap<Key, T> & reserve(size_t new_size) {pim_content.reserve(new_size); pim_index.reserve(new_size); return *this;}
|
||||
bool containsValue(const T & value) const {
|
||||
return pim_content.contains(value);
|
||||
}
|
||||
|
||||
PIMap<Key, T> & removeOne(const Key & key) {bool f(false); ssize_t i = _find(key, f); if (f) _remove(i); return *this;}
|
||||
PIMap<Key, T> & remove(const Key & key) {return removeOne(key);}
|
||||
PIMap<Key, T> & erase(const Key & key) {return removeOne(key);}
|
||||
PIMap<Key, T> & clear() {pim_content.clear(); pim_index.clear(); return *this;}
|
||||
PIMap<Key, T> & reserve(size_t new_size) {
|
||||
pim_content.reserve(new_size);
|
||||
pim_index.reserve(new_size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
PIMap<Key, T> & remove(const Key & key) {
|
||||
bool f(false);
|
||||
ssize_t i = _find(key, f);
|
||||
if (f) _remove(i);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PIMap<Key, T> & removeWhere(std::function<bool(const Key & key, const T & value)> test) {
|
||||
for (int i = 0; i < pim_index.size_s(); ++i) {
|
||||
if (pim_index[i].key, pim_content[pim_index[i].index]) {
|
||||
_remove(i);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PIMap<Key, T> & erase(const Key & key) {return remove(key);}
|
||||
|
||||
PIMap<Key, T> & clear() {
|
||||
pim_content.clear();
|
||||
pim_index.clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(PIMap<Key, T> & other) {
|
||||
pim_content.swap(other.pim_content);
|
||||
@@ -245,7 +354,6 @@ public:
|
||||
PIMap<Key, T> & insert(const Key & key, const T & value) {
|
||||
bool f(false);
|
||||
ssize_t i = _find(key, f);
|
||||
//piCout << "insert key=" << key << "found=" << f << "index=" << i << "value=" << value;
|
||||
if (f) {
|
||||
pim_content[pim_index[i].index] = value;
|
||||
} else {
|
||||
@@ -257,7 +365,6 @@ public:
|
||||
PIMap<Key, T> & insert(const Key & key, T && value) {
|
||||
bool f(false);
|
||||
ssize_t i = _find(key, f);
|
||||
//piCout << "insert key=" << key << "found=" << f << "index=" << i << "value=" << value;
|
||||
if (f) {
|
||||
pim_content[pim_index[i].index] = std::move(value);
|
||||
} else {
|
||||
@@ -266,28 +373,85 @@ public:
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
const T value(const Key & key, const T & default_ = T()) const {bool f(false); ssize_t i = _find(key, f); if (!f) return default_; return pim_content[pim_index[i].index];}
|
||||
PIMap<Key, T> & insert(const PIPair<Key, T> & pair) {
|
||||
bool f(false);
|
||||
ssize_t i = _find(pair.first, f);
|
||||
if (f) {
|
||||
pim_content[pim_index[i].index] = pair.second;
|
||||
} else {
|
||||
pim_content.push_back(pair.second);
|
||||
pim_index.insert(i, MapIndex(pair.first, pim_content.size() - 1));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
PIMap<Key, T> & insert(PIPair<Key, T> && pair) {
|
||||
bool f(false);
|
||||
Key k(std::move(pair.first));
|
||||
ssize_t i = _find(k, f);
|
||||
if (f) {
|
||||
pim_content[pim_index[i].index] = std::move(pair.second);
|
||||
} else {
|
||||
pim_content.push_back(std::move(pair.second));
|
||||
pim_index.insert(i, MapIndex(k, pim_content.size() - 1));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
T value(const Key & key, const T & default_ = T()) const {
|
||||
bool f(false);
|
||||
ssize_t i = _find(key, f);
|
||||
if (!f) return default_;
|
||||
return pim_content[pim_index[i].index];
|
||||
}
|
||||
|
||||
PIVector<T> values() const {return pim_content;}
|
||||
Key key(const T & value_, const Key & default_ = Key()) const {for (int i = 0; i < pim_index.size_s(); ++i) if (pim_content[pim_index[i].index] == value_) return pim_index[i].key; return default_;}
|
||||
|
||||
Key key(const T & value_, const Key & default_ = Key()) const {
|
||||
for (int i = 0; i < pim_index.size_s(); ++i) {
|
||||
if (pim_content[pim_index[i].index] == value_) {
|
||||
return pim_index[i].key;
|
||||
}
|
||||
}
|
||||
return default_;
|
||||
}
|
||||
|
||||
PIVector<Key> keys() const {
|
||||
PIVector<Key> ret;
|
||||
for (int i = 0; i < pim_index.size_s(); ++i)
|
||||
ret.reserve(pim_index.size());
|
||||
for (int i = 0; i < pim_index.size_s(); ++i) {
|
||||
ret << pim_index[i].key;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void forEach(std::function<void(const Key & key, const T & value)> f) const {
|
||||
for (int i = 0; i < pim_index.size_s(); ++i) {
|
||||
f(pim_index[i].key, pim_content[pim_index[i].index]);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Key2, typename T2>
|
||||
inline PIMap<Key2, T2> map(std::function<PIPair<Key2, T2>(const Key & key, const T & value)> f) const {
|
||||
PIMap<Key2, T2> ret; ret.reserve(size());
|
||||
for (int i = 0; i < pim_index.size_s(); ++i) {
|
||||
ret.insert(f(pim_index[i].key, pim_content[pim_index[i].index]));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename ST>
|
||||
inline PIVector<ST> map(std::function<ST(const Key & key, const T & value)> f) const {
|
||||
PIVector<ST> ret; ret.reserve(size());
|
||||
for (int i = 0; i < pim_index.size_s(); ++i) {
|
||||
ret << f(pim_index[i].key, pim_content[pim_index[i].index]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dump() {
|
||||
piCout << "PIMap" << size() << "entries" << PICoutManipulators::NewLine << "content:";
|
||||
for (size_t i = 0; i < pim_content.size(); ++i)
|
||||
piCout << PICoutManipulators::Tab << i << ":" << pim_content[i];
|
||||
piCout << "index:";
|
||||
for (size_t i = 0; i < pim_index.size(); ++i)
|
||||
piCout << PICoutManipulators::Tab << i << ":" << pim_index[i].key << "->" << pim_index[i].index;
|
||||
}
|
||||
|
||||
protected:
|
||||
private:
|
||||
struct MapIndex {
|
||||
MapIndex(Key k = Key(), size_t i = 0): key(k), index(i) {;}
|
||||
MapIndex(const Key & k = Key(), size_t i = 0): key(k), index(i) {}
|
||||
MapIndex(Key && k, size_t i = 0): key(std::move(k)), index(i) {}
|
||||
Key key;
|
||||
size_t index;
|
||||
bool operator ==(const MapIndex & s) const {return key == s.key;}
|
||||
@@ -295,10 +459,13 @@ protected:
|
||||
bool operator <(const MapIndex & s) const {return key < s.key;}
|
||||
bool operator >(const MapIndex & s) const {return key > s.key;}
|
||||
};
|
||||
template <typename Key1, typename T1> friend PIByteArray & operator >>(PIByteArray & s, PIDeque<typename PIMap<Key1, T1>::MapIndex> & v);
|
||||
template <typename Key1, typename T1> friend PIByteArray & operator <<(PIByteArray & s, const PIDeque<typename PIMap<Key1, T1>::MapIndex> & v);
|
||||
|
||||
ssize_t binarySearch(ssize_t first, ssize_t last, const Key & key, bool & found) const {
|
||||
template <typename P, typename Key1, typename T1>
|
||||
friend PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIDeque<typename PIMap<Key1, T1>::MapIndex> & v);
|
||||
template <typename P, typename Key1, typename T1>
|
||||
friend PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIDeque<typename PIMap<Key1, T1>::MapIndex> & v);
|
||||
|
||||
ssize_t _binarySearch(ssize_t first, ssize_t last, const Key & key, bool & found) const {
|
||||
ssize_t mid;
|
||||
while (first <= last) {
|
||||
mid = (first + last) / 2;
|
||||
@@ -309,83 +476,353 @@ protected:
|
||||
found = false;
|
||||
return first;
|
||||
}
|
||||
void _sort() {piQuickSort<MapIndex>(pim_index.data(), pim_index.size_s() - 1);}
|
||||
|
||||
ssize_t _find(const Key & k, bool & found) const {
|
||||
if (pim_index.isEmpty()) {
|
||||
found = false;
|
||||
return 0;
|
||||
}
|
||||
return binarySearch(0, pim_index.size_s() - 1, k, found);
|
||||
return _binarySearch(0, pim_index.size_s() - 1, k, found);
|
||||
}
|
||||
|
||||
void _remove(ssize_t index) {
|
||||
//if (index >= pim_index.size()) return;
|
||||
size_t ci = pim_index[index].index, bi = pim_index.size() - 1;
|
||||
pim_index.remove(index);
|
||||
for (size_t i = 0; i < pim_index.size(); ++i)
|
||||
for (size_t i = 0; i < pim_index.size(); ++i) {
|
||||
if (pim_index[i].index == bi) {
|
||||
pim_index[i].index = ci;
|
||||
break;
|
||||
}
|
||||
}
|
||||
piSwap<T>(pim_content[ci], pim_content.back());
|
||||
pim_content.resize(pim_index.size());
|
||||
}
|
||||
|
||||
const value_type _pair(ssize_t index) const {
|
||||
if (index < 0 || index >= pim_index.size_s())
|
||||
return value_type();
|
||||
//piCout << "_pair" << index << pim_index[index].index;
|
||||
if (index < 0 || index >= pim_index.size_s()) return value_type();
|
||||
return value_type(pim_index[index].key, pim_content[pim_index[index].index]);
|
||||
}
|
||||
|
||||
Key & _key(ssize_t index) {return pim_index[index].key;}
|
||||
|
||||
const Key & _key(ssize_t index) const {return pim_index[index].key;}
|
||||
|
||||
T & _value(ssize_t index) {return pim_content[pim_index[index].index];}
|
||||
|
||||
const T & _value(ssize_t index) const {return pim_content[pim_index[index].index];}
|
||||
|
||||
|
||||
PIVector<T> pim_content;
|
||||
PIDeque<MapIndex> pim_index;
|
||||
};
|
||||
|
||||
|
||||
//! \addtogroup Containers
|
||||
//! \{
|
||||
//! \class PIMapIteratorConst
|
||||
//! \brief
|
||||
//! \~english Java-style iterator for \a PIMap.
|
||||
//! \~russian Итератор Java стиля для \a PIMap.
|
||||
//! \~\}
|
||||
//! \details
|
||||
//! \~english
|
||||
//! This class used to easy serial access keys and values in PIMap with read only permitions.
|
||||
//! Use constructor to create iterator, or use \a PIMap::makeIterator()
|
||||
//! \~russian
|
||||
//! Этот класс используется для удобного перебора ключей и значений всего словаря только для чтения.
|
||||
//! Можно использовать конструктор, в который передаётся словарь, или функцию словаря \a PIMap::makeIterator().
|
||||
//! \~
|
||||
//! \code
|
||||
//! PIMap<int, PIString> m;
|
||||
//! m[1] = "one";
|
||||
//! m[2] = "two";
|
||||
//! m[4] = "four";
|
||||
//! auto it = m.makeIterator();
|
||||
//! while (it.next()) {
|
||||
//! piCout << it.key() << it.value();
|
||||
//! }
|
||||
//! // 1 one
|
||||
//! // 2 two
|
||||
//! // 4 four
|
||||
//! \endcode
|
||||
template <typename Key, typename T>
|
||||
class PIMapIterator {
|
||||
class PIMapIteratorConst {
|
||||
typedef PIMap<Key, T> MapType;
|
||||
public:
|
||||
PIMapIterator(const PIMap<Key, T> & map, bool reverse = false): m(map), pos(-1), rev(reverse) {
|
||||
if (rev) pos = m.size_s();
|
||||
PIMapIteratorConst(const PIMap<Key, T> & map): m(map), pos(-1) {}
|
||||
|
||||
//! \~english Returns current key.
|
||||
//! \~russian Возвращает ключ текущего элемента.
|
||||
//! \~\sa \a value()
|
||||
const Key & key() const {
|
||||
return m._key(pos);
|
||||
}
|
||||
const Key & key() const {return const_cast<MapType & >(m)._key(pos);}
|
||||
const T & value() const {return const_cast<MapType & >(m)._value(pos);}
|
||||
T & valueRef() const {return const_cast<MapType & >(m)._value(pos);}
|
||||
|
||||
//! \~english Returns current value.
|
||||
//! \~russian Возвращает значение текущего элемента.
|
||||
//! \~\sa \a key()
|
||||
const T & value() const {
|
||||
return m._value(pos);
|
||||
}
|
||||
|
||||
|
||||
//! \~english Returns true if iterator can jump to next entry
|
||||
//! \~russian Возвращает true если итератор может перейти к следующему элементу.
|
||||
//! \~\sa \a next()
|
||||
inline bool hasNext() const {
|
||||
if (rev) {
|
||||
return pos > 0;
|
||||
} else {
|
||||
return pos < (m.size_s() - 1);
|
||||
}
|
||||
return false;
|
||||
return pos < (m.size_s() - 1);
|
||||
}
|
||||
|
||||
//! \~english Jump to next entry and return true if new position is valid.
|
||||
//! \~russian Переходит к следующему элементу и возвращает true если он существует.
|
||||
//! \~\sa \a hasNext(), \a reset()
|
||||
inline bool next() {
|
||||
if (rev) {
|
||||
--pos;
|
||||
return pos >= 0;
|
||||
} else {
|
||||
++pos;
|
||||
return pos < m.size_s();
|
||||
}
|
||||
return false;
|
||||
++pos;
|
||||
return pos < m.size_s();
|
||||
}
|
||||
|
||||
//! \~english Reset iterator to initial position.
|
||||
//! \~russian Переходит на начало.
|
||||
//! \~\sa \a next()
|
||||
inline void reset() {
|
||||
if (rev) {
|
||||
pos = m.size_s();
|
||||
} else {
|
||||
pos = -1;
|
||||
}
|
||||
pos = -1;
|
||||
}
|
||||
private:
|
||||
const MapType & m;
|
||||
ssize_t pos;
|
||||
bool rev;
|
||||
};
|
||||
|
||||
|
||||
//! \addtogroup Containers
|
||||
//! \{
|
||||
//! \class PIMapIteratorConstReverse
|
||||
//! \brief
|
||||
//! \~english Java-style reverse iterator for \a PIMap.
|
||||
//! \~russian Итератор Java стиля для \a PIMap в обратном порядке.
|
||||
//! \~\}
|
||||
//! \details
|
||||
//! \~english
|
||||
//! This class used to easy serial reverse access keys and values in PIMap with read only permitions.
|
||||
//! Use constructor to create iterator, or use \a PIMap::makeReverseIterator().
|
||||
//! \~russian
|
||||
//! Этот класс используется для удобного перебора ключей и значений всего словаря в обратном порядке только для чтения.
|
||||
//! Можно использовать конструктор, в который передаётся словарь, или функцию словаря \a PIMap::makeReverseIterator().
|
||||
//! \~
|
||||
//! \code
|
||||
//! PIMap<int, PIString> m;
|
||||
//! m[1] = "one";
|
||||
//! m[2] = "two";
|
||||
//! m[4] = "four";
|
||||
//! auto it = m.makeReverseIterator();
|
||||
//! while (it.next()) {
|
||||
//! piCout << it.key() << it.value();
|
||||
//! }
|
||||
//! // 4 four
|
||||
//! // 2 two
|
||||
//! // 1 one
|
||||
//! \endcode
|
||||
template <typename Key, typename T>
|
||||
class PIMapIteratorConstReverse {
|
||||
typedef PIMap<Key, T> MapType;
|
||||
public:
|
||||
PIMapIteratorConstReverse(const PIMap<Key, T> & map): m(map), pos(m.size_s()) {}
|
||||
|
||||
//! \~english Returns current key.
|
||||
//! \~russian Возвращает ключ текущего элемента.
|
||||
//! \~\sa \a value()
|
||||
const Key & key() const {
|
||||
return m._key(pos);
|
||||
}
|
||||
|
||||
//! \~english Returns current value.
|
||||
//! \~russian Возвращает значение текущего элемента.
|
||||
//! \~\sa \a key()
|
||||
const T & value() const {
|
||||
return m._value(pos);
|
||||
}
|
||||
|
||||
//! \~english Returns true if iterator can jump to next entry
|
||||
//! \~russian Возвращает true если итератор может перейти к следующему элементу.
|
||||
//! \~\sa \a next()
|
||||
inline bool hasNext() const {
|
||||
return pos > 0;
|
||||
}
|
||||
|
||||
//! \~english Jump to next entry and return true if new position is valid.
|
||||
//! \~russian Переходит к следующему элементу и возвращает true если он существует.
|
||||
//! \~\sa \a hasNext(), \a reset()
|
||||
inline bool next() {
|
||||
--pos;
|
||||
return pos >= 0;
|
||||
}
|
||||
|
||||
//! \~english Reset iterator to initial position.
|
||||
//! \~russian Переходит на начало.
|
||||
//! \~\sa \a next()
|
||||
inline void reset() {
|
||||
pos = m.size_s();
|
||||
}
|
||||
private:
|
||||
const MapType & m;
|
||||
ssize_t pos;
|
||||
};
|
||||
|
||||
|
||||
//! \addtogroup Containers
|
||||
//! \{
|
||||
//! \class PIMapIterator
|
||||
//! \brief
|
||||
//! \~english Java-style iterator for \a PIMap.
|
||||
//! \~russian Итератор Java стиля для \a PIMap.
|
||||
//! \~\}
|
||||
//! \details
|
||||
//! \~english
|
||||
//! This class used to easy serial access keys and values in PIMap with write permitions.
|
||||
//! Use constructor to create iterator, or use \a PIMap::makeIterator()
|
||||
//! \~russian
|
||||
//! Этот класс используется для удобного перебора ключей и значений всего словаря с доступом на запись.
|
||||
//! Можно использовать конструктор, в который передаётся словарь, или функцию словаря \a PIMap::makeIterator().
|
||||
//! \~
|
||||
//! \code
|
||||
//! PIMap<int, PIString> m;
|
||||
//! m[1] = "one";
|
||||
//! m[2] = "two";
|
||||
//! m[4] = "four";
|
||||
//! auto it = m.makeIterator();
|
||||
//! while (it.next()) {
|
||||
//! it.value().append("_!");
|
||||
//! piCout << it.key() << it.value();
|
||||
//! }
|
||||
//! // 1 one_!
|
||||
//! // 2 two_!
|
||||
//! // 4 four_!
|
||||
//! \endcode
|
||||
template <typename Key, typename T>
|
||||
class PIMapIterator {
|
||||
typedef PIMap<Key, T> MapType;
|
||||
public:
|
||||
PIMapIterator(PIMap<Key, T> & map): m(map), pos(-1) {}
|
||||
|
||||
//! \~english Returns current key.
|
||||
//! \~russian Возвращает ключ текущего элемента.
|
||||
//! \~\sa \a value()
|
||||
const Key & key() const {
|
||||
return m._key(pos);
|
||||
}
|
||||
|
||||
//! \~english Returns current value.
|
||||
//! \~russian Возвращает значение текущего элемента.
|
||||
//! \~\sa \a key()
|
||||
T & value() {
|
||||
return m._value(pos);
|
||||
}
|
||||
|
||||
//! \~english Returns true if iterator can jump to next entry
|
||||
//! \~russian Возвращает true если итератор может перейти к следующему элементу.
|
||||
//! \~\sa \a next()
|
||||
inline bool hasNext() const {
|
||||
return pos < (m.size_s() - 1);
|
||||
}
|
||||
|
||||
//! \~english Jump to next entry and return true if new position is valid.
|
||||
//! \~russian Переходит к следующему элементу и возвращает true если он существует.
|
||||
//! \~\sa \a hasNext(), \a reset()
|
||||
inline bool next() {
|
||||
++pos;
|
||||
return pos < m.size_s();
|
||||
}
|
||||
|
||||
//! \~english Reset iterator to initial position.
|
||||
//! \~russian Переходит на начало.
|
||||
//! \~\sa \a next()
|
||||
inline void reset() {
|
||||
pos = -1;
|
||||
}
|
||||
private:
|
||||
MapType & m;
|
||||
ssize_t pos;
|
||||
};
|
||||
|
||||
|
||||
//! \addtogroup Containers
|
||||
//! \{
|
||||
//! \class PIMapIteratorReverse
|
||||
//! \brief
|
||||
//! \~english Java-style reverse iterator for \a PIMap.
|
||||
//! \~russian Итератор Java стиля для \a PIMap в обратном порядке.
|
||||
//! \~\}
|
||||
//! \details
|
||||
//! \~english
|
||||
//! This class used to easy serial reverse access keys and values in PIMap with write permitions.
|
||||
//! Use constructor to create iterator, or use \a PIMap::makeReverseIterator().
|
||||
//! \~russian
|
||||
//! Этот класс используется для удобного перебора ключей и значений всего словаря в обратном порядке с доступом на запись.
|
||||
//! Можно использовать конструктор, в который передаётся словарь, или функцию словаря \a PIMap::makeReverseIterator().
|
||||
//! \~
|
||||
//! \code
|
||||
//! PIMap<int, PIString> m;
|
||||
//! m[1] = "one";
|
||||
//! m[2] = "two";
|
||||
//! m[4] = "four";
|
||||
//! auto it = m.makeReverseIterator();
|
||||
//! while (it.next()) {
|
||||
//! it.value().append("_!");
|
||||
//! piCout << it.key() << it.value();
|
||||
//! }
|
||||
//! // 4 four_!
|
||||
//! // 2 two_!
|
||||
//! // 1 one_!
|
||||
//! \endcode
|
||||
template <typename Key, typename T>
|
||||
class PIMapIteratorReverse {
|
||||
typedef PIMap<Key, T> MapType;
|
||||
public:
|
||||
PIMapIteratorReverse(PIMap<Key, T> & map): m(map), pos(m.size_s()) {}
|
||||
|
||||
//! \~english Returns current key.
|
||||
//! \~russian Возвращает ключ текущего элемента.
|
||||
//! \~\sa \a value()
|
||||
const Key & key() const {
|
||||
return m._key(pos);
|
||||
}
|
||||
|
||||
//! \~english Returns current value.
|
||||
//! \~russian Возвращает значение текущего элемента.
|
||||
//! \~\sa \a key()
|
||||
T & value() {
|
||||
return m._value(pos);
|
||||
}
|
||||
|
||||
//! \~english Returns true if iterator can jump to next entry
|
||||
//! \~russian Возвращает true если итератор может перейти к следующему элементу.
|
||||
//! \~\sa \a next()
|
||||
inline bool hasNext() const {
|
||||
return pos > 0;
|
||||
}
|
||||
|
||||
//! \~english Jump to next entry and return true if new position is valid.
|
||||
//! \~russian Переходит к следующему элементу и возвращает true если он существует.
|
||||
//! \~\sa \a hasNext(), \a reset()
|
||||
inline bool next() {
|
||||
--pos;
|
||||
return pos >= 0;
|
||||
}
|
||||
|
||||
//! \~english Reset iterator to initial position.
|
||||
//! \~russian Переходит на начало.
|
||||
//! \~\sa \a next()
|
||||
inline void reset() {
|
||||
pos = m.size_s();
|
||||
}
|
||||
private:
|
||||
MapType & m;
|
||||
ssize_t pos;
|
||||
};
|
||||
|
||||
|
||||
#ifdef PIP_STD_IOSTREAM
|
||||
//! \~english Output operator to [std::ostream](https://en.cppreference.com/w/cpp/io/basic_ostream).
|
||||
//! \~russian Оператор вывода в [std::ostream](https://ru.cppreference.com/w/cpp/io/basic_ostream).
|
||||
template<typename Key, typename Type>
|
||||
inline std::ostream & operator <<(std::ostream & s, const PIMap<Key, Type> & v) {
|
||||
s << "{";
|
||||
@@ -394,31 +831,36 @@ inline std::ostream & operator <<(std::ostream & s, const PIMap<Key, Type> & v)
|
||||
if (!first)
|
||||
s << ", ";
|
||||
first = false;
|
||||
s << i->first << ": " << i->second;
|
||||
s << i.key() << ": " << i.value();
|
||||
}
|
||||
s << "}";
|
||||
return s;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//! \relatesalso PICout
|
||||
//! \~english Output operator to \a PICout
|
||||
//! \~russian Оператор вывода в \a PICout
|
||||
template<typename Key, typename Type>
|
||||
inline PICout operator <<(PICout s, const PIMap<Key, Type> & v) {
|
||||
s.space();
|
||||
s.setControl(0, true);
|
||||
s.saveAndSetControls(0);
|
||||
s << "{";
|
||||
bool first = true;
|
||||
for (typename PIMap<Key, Type>::const_iterator i = v.begin(); i != v.end(); ++i) {
|
||||
if (!first)
|
||||
s << ", ";
|
||||
first = false;
|
||||
s << i->first << ": " << i->second;
|
||||
s << i.key() << ": " << i.value();
|
||||
}
|
||||
s << "}";
|
||||
s.restoreControl();
|
||||
s.restoreControls();
|
||||
return s;
|
||||
}
|
||||
|
||||
template<typename Key, typename Type> inline void piSwap(PIMap<Key, Type> & f, PIMap<Key, Type> & s) {f.swap(s);}
|
||||
template<typename Key, typename Type>
|
||||
inline void piSwap(PIMap<Key, Type> & f, PIMap<Key, Type> & s) {f.swap(s);}
|
||||
|
||||
|
||||
#endif // PIMAP_H
|
||||
|
||||
@@ -114,9 +114,9 @@ inline std::ostream & operator <<(std::ostream & s, const PIPair<Type0, Type1> &
|
||||
template<typename Type0, typename Type1>
|
||||
inline PICout operator <<(PICout s, const PIPair<Type0, Type1> & v) {
|
||||
s.space();
|
||||
s.setControl(0, true);
|
||||
s.saveAndSetControls(0);
|
||||
s << "(" << v.first << ", " << v.second << ")";
|
||||
s.restoreControl();
|
||||
s.restoreControls();
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -133,6 +133,7 @@ PIPair<T1,T2> createPIPair(const T1 & f, const T2 & s) {
|
||||
return PIPair<T1,T2>(f, s);
|
||||
}
|
||||
|
||||
|
||||
//! \~english Creates \a PIPair object, deducing the target type from the types of arguments.
|
||||
//! \~russian Создает \a PIPair выводя типы из аргументов.
|
||||
//! \sa \a createPIPair()
|
||||
@@ -141,4 +142,5 @@ PIPair<T1,T2> createPIPair(T1 && f, T2 && s) {
|
||||
return PIPair<T1,T2>(std::move(f), std::move(s));
|
||||
}
|
||||
|
||||
|
||||
#endif // PIPAIR_H
|
||||
|
||||
@@ -87,14 +87,14 @@ public:
|
||||
//! Unite set with "v"
|
||||
PISet<T> & unite(const PISet<T> & v) {
|
||||
for (typename PIMap<T, uchar>::const_iterator i = v.begin(); i != v.end(); ++i)
|
||||
_CSet::insert(i->first, 0);
|
||||
_CSet::insert(i.key(), 0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Subtract set with "v"
|
||||
PISet<T> & subtract(const PISet<T> & v) {
|
||||
for (typename PIMap<T, uchar>::const_iterator i = v.begin(); i != v.end(); ++i)
|
||||
_CSet::remove(i->first);
|
||||
_CSet::remove(i.key());
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -121,10 +121,10 @@ public:
|
||||
PISet<T> & operator &=(const PISet<T> & v) {return intersect(v);}
|
||||
|
||||
//! Returns content of set as PIVector
|
||||
PIVector<T> toVector() const {PIVector<T> ret; for (typename _CSet::const_iterator i = _CSet::begin(); i != _CSet::end(); ++i) ret << (*i).first; return ret;}
|
||||
PIVector<T> toVector() const {PIVector<T> ret; for (typename _CSet::const_iterator i = _CSet::begin(); i != _CSet::end(); ++i) ret << i.key(); return ret;}
|
||||
|
||||
//! Returns content of set as PIDeque
|
||||
PIDeque<T> toDeque() const {PIDeque<T> ret; for (typename _CSet::const_iterator i = _CSet::begin(); i != _CSet::end(); ++i) ret << (*i).first; return ret;}
|
||||
PIDeque<T> toDeque() const {PIDeque<T> ret; for (typename _CSet::const_iterator i = _CSet::begin(); i != _CSet::end(); ++i) ret << i.key(); return ret;}
|
||||
|
||||
};
|
||||
|
||||
@@ -145,17 +145,17 @@ template <typename T> PISet<T> operator &(const PISet<T> & v0, const PISet<T> &
|
||||
template<typename Type>
|
||||
inline PICout operator <<(PICout s, const PISet<Type> & v) {
|
||||
s.space();
|
||||
s.setControl(0, true);
|
||||
s.saveAndSetControls(0);
|
||||
s << "{";
|
||||
bool first = true;
|
||||
for (typename PIMap<Type, uchar>::const_iterator i = v.begin(); i != v.end(); ++i) {
|
||||
if (!first)
|
||||
s << ", ";
|
||||
first = false;
|
||||
s << i->first;
|
||||
s << i.key();
|
||||
}
|
||||
s << "}";
|
||||
s.restoreControl();
|
||||
s.restoreControls();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,13 +37,7 @@ public:
|
||||
T pop() {return PIVector<T>::take_back();}
|
||||
T & top() {return PIVector<T>::back();}
|
||||
const T & top() const {return PIVector<T>::back();}
|
||||
PIVector<T> toVector() {
|
||||
PIVector<T> v;
|
||||
v.reserve(PIVector<T>::size());
|
||||
for (uint i = 0; i < PIVector<T>::size(); ++i)
|
||||
v.push_back(PIVector<T>::at(i));
|
||||
return v;
|
||||
}
|
||||
PIVector<T> toVector() {return PIVector<T>(*this);}
|
||||
};
|
||||
|
||||
#endif // PISTACK_H
|
||||
|
||||
@@ -645,7 +645,7 @@ public:
|
||||
inline size_t length() const {return piv_size;}
|
||||
|
||||
//! \~english Number of elements that the container has currently allocated space for.
|
||||
//! \~russian Количество элементов, для которого сейчас выделена память контейнером.
|
||||
//! \~russian Количество элементов, для которого сейчас выделена память массивом.
|
||||
//! \~\details
|
||||
//! \~english To find out the actual number of items, use the function \a size().
|
||||
//! \~russian Чтобы узнать фактическое количество элементов используйте функцию \a size().
|
||||
@@ -653,18 +653,18 @@ public:
|
||||
inline size_t capacity() const {return piv_rsize;}
|
||||
|
||||
//! \~english Checks if the container has no elements.
|
||||
//! \~russian Проверяет пуст ли контейнер.
|
||||
//! \~russian Проверяет пуст ли массив.
|
||||
//! \~\return
|
||||
//! \~english **true** if the container is empty, **false** otherwise
|
||||
//! \~russian **true** если контейнер пуст, **false** иначе.
|
||||
//! \~russian **true** если массив пуст, **false** иначе.
|
||||
//! \~\sa \a size(), \a size_s(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
|
||||
inline bool isEmpty() const {return (piv_size == 0);}
|
||||
|
||||
//! \~english Checks if the container has elements.
|
||||
//! \~russian Проверяет не пуст ли контейнер.
|
||||
//! \~russian Проверяет не пуст ли массив.
|
||||
//! \~\return
|
||||
//! \~english **true** if the container is not empty, **false** otherwise
|
||||
//! \~russian **true** если контейнер не пуст, **false** иначе.
|
||||
//! \~russian **true** если массив не пуст, **false** иначе.
|
||||
//! \~\sa \a size(), \a size_s(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
|
||||
inline bool isNotEmpty() const {return (piv_size > 0);}
|
||||
|
||||
@@ -1512,8 +1512,8 @@ public:
|
||||
//! Если `add_size < 0`, то с конца массива удаляются элементы.
|
||||
//! Если `add_size < 0` и в массиве меньше элементов чем указано, то массив становится пустым.
|
||||
//! \~\sa \a resize()
|
||||
inline PIVector<T> & enlarge(llong add_size, const T & e = T()) {
|
||||
llong ns = size_s() + add_size;
|
||||
inline PIVector<T> & enlarge(ssize_t add_size, const T & e = T()) {
|
||||
ssize_t ns = size_s() + add_size;
|
||||
if (ns <= 0) clear();
|
||||
else resize(size_t(ns), e);
|
||||
return *this;
|
||||
@@ -2316,7 +2316,7 @@ inline std::ostream & operator <<(std::ostream & s, const PIVector<T> & v) {
|
||||
template<typename T>
|
||||
inline PICout operator <<(PICout s, const PIVector<T> & v) {
|
||||
s.space();
|
||||
s.setControl(0, true);
|
||||
s.saveAndSetControls(0);
|
||||
s << "{";
|
||||
for (size_t i = 0; i < v.size(); ++i) {
|
||||
s << v[i];
|
||||
@@ -2325,7 +2325,7 @@ inline PICout operator <<(PICout s, const PIVector<T> & v) {
|
||||
}
|
||||
}
|
||||
s << "}";
|
||||
s.restoreControl();
|
||||
s.restoreControls();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
@@ -292,7 +292,7 @@ protected:
|
||||
|
||||
template<typename T>
|
||||
inline PICout operator <<(PICout s, const PIVector2D<T> & v) {
|
||||
s.setControl(0, true);
|
||||
s.saveAndSetControls(0);
|
||||
s << "{";
|
||||
for (size_t i = 0; i < v.rows(); ++i) {
|
||||
s << "{ ";
|
||||
@@ -305,7 +305,7 @@ inline PICout operator <<(PICout s, const PIVector2D<T> & v) {
|
||||
}
|
||||
if (v.isEmpty()) s << "{ }";
|
||||
s << "}";
|
||||
s.restoreControl();
|
||||
s.restoreControls();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
@@ -265,13 +265,15 @@
|
||||
|
||||
#ifdef CC_GCC
|
||||
# undef DEPRECATED
|
||||
# undef DEPRECATEDM
|
||||
# define DEPRECATED __attribute__((deprecated))
|
||||
# define DEPRECATEDM(msg) __attribute__((deprecated(msg)))
|
||||
# if CC_GCC_VERSION > 0x025F // > 2.95
|
||||
# pragma GCC diagnostic warning "-Wdeprecated-declarations"
|
||||
# ifdef LINUX
|
||||
# define HAS_LOCALE
|
||||
# endif
|
||||
# ifdef MAC_OS
|
||||
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
# pragma GCC diagnostic ignored "-Wundefined-bool-conversion"
|
||||
# pragma GCC diagnostic ignored "-Wc++11-extensions"
|
||||
# endif
|
||||
@@ -287,7 +289,9 @@
|
||||
|
||||
#ifdef CC_VC
|
||||
# undef DEPRECATED
|
||||
# define DEPRECATED
|
||||
# undef DEPRECATEDM
|
||||
# define DEPRECATED __declspec(deprecated)
|
||||
# define DEPRECATEDM(msg) __declspec(deprecated(msg))
|
||||
# pragma warning(disable: 4018)
|
||||
# pragma warning(disable: 4061)
|
||||
# pragma warning(disable: 4100)
|
||||
@@ -312,7 +316,9 @@
|
||||
|
||||
#ifdef CC_OTHER
|
||||
# undef DEPRECATED
|
||||
# undef DEPRECATEDM
|
||||
# define DEPRECATED
|
||||
# define DEPRECATEDM(msg)
|
||||
#endif
|
||||
|
||||
#endif //DOXYGEN
|
||||
|
||||
525
libs/main/core/pibinarystream.h
Normal file
525
libs/main/core/pibinarystream.h
Normal file
@@ -0,0 +1,525 @@
|
||||
/*! \file pibinarystream.h
|
||||
* \ingroup Core
|
||||
* \~\brief
|
||||
* \~english Binary serialization interface
|
||||
* \~russian Интерфейс бинарной сериализации
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Binary serialization interface
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIBINARYSTREAM_H
|
||||
#define PIBINARYSTREAM_H
|
||||
|
||||
#include "pimemoryblock.h"
|
||||
#include "pibitarray.h"
|
||||
#include "pimap.h"
|
||||
#include "pivector2d.h"
|
||||
|
||||
#define PIP_BINARY_STREAM
|
||||
|
||||
#define BINARY_STREAM_FRIEND(T) \
|
||||
template<typename P> friend PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const T & v); \
|
||||
template<typename P> friend PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, T & v);
|
||||
#define BINARY_STREAM_WRITE(T) \
|
||||
template<typename P> inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const T & v)
|
||||
#define BINARY_STREAM_READ(T) \
|
||||
template<typename P> inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, T & v)
|
||||
|
||||
|
||||
//! \ingroup Core
|
||||
//! \~\brief
|
||||
//! \~english Binary serialization interface.
|
||||
//! \~russian Интерфейс бинарной сериализации.
|
||||
//! \~\details
|
||||
//! \~english In your class you should implement this methods:
|
||||
//! \~russian В производном классе вы должны реализовать следующие методы:
|
||||
//! \~\code
|
||||
//! bool binaryStreamAppendImp (const void * d, size_t s);
|
||||
//! bool binaryStreamTakeImp (void * d, size_t s);
|
||||
//! ssize_t binaryStreamSizeImp () const;
|
||||
//! \endcode
|
||||
//! \~english Function binaryStreamSizeImp should return -1 if size unknown.
|
||||
//! \~russian Функция binaryStreamSizeImp должна возвращать -1 если нет информации о размере.
|
||||
//! \~english See details \ref iostream.
|
||||
//! \~russian Подробнее \ref iostream.
|
||||
template<typename P>
|
||||
class PIBinaryStream {
|
||||
public:
|
||||
//! \~russian Записать данные
|
||||
bool binaryStreamAppend(const void * d, size_t s) {
|
||||
if (!static_cast<P*>(this)->binaryStreamAppendImp(d, s)) {
|
||||
return false;
|
||||
printf("[PIBinaryStream] binaryStreamAppend() error\n");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//! \~russian Прочитать данные
|
||||
bool binaryStreamTake(void * d, size_t s) {
|
||||
if (!static_cast<P*>(this)->binaryStreamTakeImp(d, s)) {
|
||||
return false;
|
||||
printf("[PIBinaryStream] binaryStreamTake() error\n");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//! \~russian Узнать оставшийся размер
|
||||
//!\~\details
|
||||
//!\~russian Возвращает -1 если нет информации о размере
|
||||
ssize_t binaryStreamSize() const {
|
||||
return static_cast<P*>(this)->binaryStreamSizeImp();
|
||||
}
|
||||
|
||||
//! \~russian Записать данные
|
||||
template<typename T>
|
||||
void binaryStreamAppend(T v) {binaryStreamAppend(&v, sizeof(v));}
|
||||
|
||||
//! \~russian Прочитать int
|
||||
int binaryStreamTakeInt() {
|
||||
int r = 0;
|
||||
binaryStreamTake(&r, sizeof(r));
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// helper class to detect default operators
|
||||
template<typename P>
|
||||
class PIBinaryStreamTrivialRef {
|
||||
public:
|
||||
PIBinaryStreamTrivialRef(PIBinaryStream<P> & s): p(s) {}
|
||||
PIBinaryStream<P> & p;
|
||||
};
|
||||
|
||||
|
||||
template<typename P, typename T> inline PIBinaryStream<P> & operator <<(PIBinaryStreamTrivialRef<P> s, const T & v) {
|
||||
s.p << v;
|
||||
return s.p;
|
||||
}
|
||||
template<typename P, typename T> inline PIBinaryStream<P> & operator >>(PIBinaryStreamTrivialRef<P> s, T & v) {
|
||||
s.p >> v;
|
||||
return s.p;
|
||||
}
|
||||
|
||||
|
||||
// specify types
|
||||
template<typename P> inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const bool v) {
|
||||
s.binaryStreamAppend((uchar)v);
|
||||
return s;
|
||||
}
|
||||
template<typename P> inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, bool & v) {
|
||||
uchar c;
|
||||
s.binaryStreamTake(&c, sizeof(c));
|
||||
v = c;
|
||||
return s;
|
||||
}
|
||||
|
||||
template<typename P> inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIMemoryBlock v) {
|
||||
s.binaryStreamAppend(v.data(), v.size());
|
||||
return s;
|
||||
}
|
||||
template<typename P> inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIMemoryBlock v) {
|
||||
s.binaryStreamTake(v.data(), v.size());
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// store simple types
|
||||
|
||||
|
||||
template<typename P, typename T,
|
||||
typename std::enable_if<std::is_enum<T>::value, int>::type = 0>
|
||||
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const T & v) {
|
||||
//piCout << "<< enum";
|
||||
s.binaryStreamAppend((int)v);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
template<typename P, typename T,
|
||||
typename std::enable_if<!std::is_enum<T>::value, int>::type = 0,
|
||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0>
|
||||
inline PIBinaryStreamTrivialRef<P> operator <<(PIBinaryStream<P> & s, const T & v) {
|
||||
s.binaryStreamAppend(&v, sizeof(v));
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
//! \~english Store operator for PIVector of any trivial copyable type
|
||||
//! \~russian Оператор сохранения для PIVector тривиальных типов
|
||||
template<typename P, typename T,
|
||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
||||
typename std::enable_if< std::is_same<decltype(std::declval<PIBinaryStream<P>&>() << std::declval<const T &>()), PIBinaryStreamTrivialRef<P>>::value, int>::type = 0>
|
||||
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIVector<T> & v) {
|
||||
//piCout << "<< vector trivial default";
|
||||
s.binaryStreamAppend((int)v.size());
|
||||
s.binaryStreamAppend(v.data(), v.size() * sizeof(T));
|
||||
return s;
|
||||
}
|
||||
template<typename P, typename T,
|
||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
||||
typename std::enable_if<!std::is_same<decltype(std::declval<PIBinaryStream<P>&>() << std::declval<const T &>()), PIBinaryStreamTrivialRef<P>>::value, int>::type = 0>
|
||||
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIVector<T> & v) {
|
||||
//piCout << "<< vector trivial custom";
|
||||
s.binaryStreamAppend((int)v.size());
|
||||
for (size_t i = 0; i < v.size(); ++i) s << v[i];
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
//! \~english Store operator for PIDeque of any trivial copyable type
|
||||
//! \~russian Оператор сохранения для PIDeque тривиальных типов
|
||||
template<typename P, typename T,
|
||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
||||
typename std::enable_if< std::is_same<decltype(std::declval<PIBinaryStream<P>&>() << std::declval<const T &>()), PIBinaryStreamTrivialRef<P>>::value, int>::type = 0>
|
||||
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIDeque<T> & v) {
|
||||
//piCout << "<< deque trivial default";
|
||||
s.binaryStreamAppend((int)v.size());
|
||||
s.binaryStreamAppend(v.data(), v.size() * sizeof(T));
|
||||
return s;
|
||||
}
|
||||
template<typename P, typename T,
|
||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
||||
typename std::enable_if<!std::is_same<decltype(std::declval<PIBinaryStream<P>&>() << std::declval<const T &>()), PIBinaryStreamTrivialRef<P>>::value, int>::type = 0>
|
||||
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIDeque<T> & v) {
|
||||
//piCout << "<< deque trivial custom";
|
||||
s.binaryStreamAppend((int)v.size());
|
||||
for (size_t i = 0; i < v.size(); ++i) s << v[i];
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
//! \~english Store operator for PIVector2D of any trivial copyable type
|
||||
//! \~russian Оператор сохранения для PIVector2D тривиальных типов
|
||||
template<typename P, typename T,
|
||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
||||
typename std::enable_if< std::is_same<decltype(std::declval<PIBinaryStream<P>&>() << std::declval<const T &>()), PIBinaryStreamTrivialRef<P>>::value, int>::type = 0>
|
||||
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIVector2D<T> & v) {
|
||||
//piCout << "<< vector2d trivial default";
|
||||
s.binaryStreamAppend((int)v.rows());
|
||||
s.binaryStreamAppend((int)v.cols());
|
||||
s.binaryStreamAppend(v.data(), v.size() * sizeof(T));
|
||||
return s;
|
||||
}
|
||||
template<typename P, typename T,
|
||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
||||
typename std::enable_if<!std::is_same<decltype(std::declval<PIBinaryStream<P>&>() << std::declval<const T &>()), PIBinaryStreamTrivialRef<P>>::value, int>::type = 0>
|
||||
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIVector2D<T> & v) {
|
||||
//piCout << "<< vector2d trivial custom";
|
||||
s.binaryStreamAppend((int)v.rows());
|
||||
s.binaryStreamAppend((int)v.cols());
|
||||
s << v.toPlainVector();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
//! \~english Store operator
|
||||
//! \~russian Оператор сохранения
|
||||
template<typename P>
|
||||
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIBitArray & v) {s << v.size_ << v.data_; return s;}
|
||||
|
||||
|
||||
//! \~english Store operator
|
||||
//! \~russian Оператор сохранения
|
||||
template<typename P, typename Type0, typename Type1>
|
||||
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIPair<Type0, Type1> & v) {s << v.first << v.second; return s;}
|
||||
|
||||
|
||||
|
||||
|
||||
// restore simple types
|
||||
|
||||
|
||||
template<typename P, typename T,
|
||||
typename std::enable_if<std::is_enum<T>::value, int>::type = 0>
|
||||
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, T & v) {
|
||||
//piCout << ">> enum";
|
||||
v = (T)s.binaryStreamTakeInt();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
template<typename P, typename T,
|
||||
typename std::enable_if<!std::is_enum<T>::value, int>::type = 0,
|
||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0>
|
||||
inline PIBinaryStreamTrivialRef<P> operator >>(PIBinaryStream<P> & s, T & v) {
|
||||
if (!s.binaryStreamTake(&v, sizeof(v))) {
|
||||
printf("error with %s\n", __PIP_TYPENAME__(T));
|
||||
assert(false);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
//! \~english Restore operator for PIVector of any trivial copyable type
|
||||
//! \~russian Оператор извлечения для PIVector тривиальных типов
|
||||
template<typename P, typename T,
|
||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
||||
typename std::enable_if< std::is_same<decltype(std::declval<PIBinaryStream<P>&>() >> std::declval<T &>()), PIBinaryStreamTrivialRef<P>>::value, int>::type = 0>
|
||||
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIVector<T> & v) {
|
||||
//piCout << ">> vector trivial default";
|
||||
int sz = s.binaryStreamTakeInt();
|
||||
v._resizeRaw(sz);
|
||||
if (!s.binaryStreamTake(v.data(), sz * sizeof(T))) {
|
||||
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||
assert(false);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
template<typename P, typename T,
|
||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
||||
typename std::enable_if<!std::is_same<decltype(std::declval<PIBinaryStream<P>&>() >> std::declval<T &>()), PIBinaryStreamTrivialRef<P>>::value, int>::type = 0>
|
||||
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIVector<T> & v) {
|
||||
//piCout << ">> vector trivial custom";
|
||||
int sz = s.binaryStreamTakeInt();
|
||||
v._resizeRaw(sz);
|
||||
for (int i = 0; i < sz; ++i) s >> v[i];
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
//! \~english Restore operator for PIDeque of any trivial copyable type
|
||||
//! \~russian Оператор извлечения для PIDeque тривиальных типов
|
||||
template<typename P, typename T,
|
||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
||||
typename std::enable_if< std::is_same<decltype(std::declval<PIBinaryStream<P>&>() >> std::declval<T &>()), PIBinaryStreamTrivialRef<P>>::value, int>::type = 0>
|
||||
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIDeque<T> & v) {
|
||||
//piCout << ">> deque trivial default";
|
||||
int sz = s.binaryStreamTakeInt();
|
||||
v._resizeRaw(sz);
|
||||
if (!s.binaryStreamTake(v.data(), sz * sizeof(T))) {
|
||||
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||
assert(false);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
template<typename P, typename T,
|
||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
||||
typename std::enable_if<!std::is_same<decltype(std::declval<PIBinaryStream<P>&>() >> std::declval<T &>()), PIBinaryStreamTrivialRef<P>>::value, int>::type = 0>
|
||||
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIDeque<T> & v) {
|
||||
//piCout << ">> deque trivial custom";
|
||||
int sz = s.binaryStreamTakeInt();
|
||||
v._resizeRaw(sz);
|
||||
for (int i = 0; i < sz; ++i) s >> v[i];
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
//! \~english Restore operator for PIVector2D of any trivial copyable type
|
||||
//! \~russian Оператор извлечения для PIVector2D тривиальных типов
|
||||
template<typename P, typename T,
|
||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
||||
typename std::enable_if< std::is_same<decltype(std::declval<PIBinaryStream<P>&>() >> std::declval<T &>()), PIBinaryStreamTrivialRef<P>>::value, int>::type = 0>
|
||||
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIVector2D<T> & v) {
|
||||
//piCout << ">> vector2d trivial default";
|
||||
int r, c;
|
||||
r = s.binaryStreamTakeInt();
|
||||
c = s.binaryStreamTakeInt();
|
||||
v._resizeRaw(r, c);
|
||||
if (!s.binaryStreamTake(v.data(), v.size() * sizeof(T))) {
|
||||
printf("error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
|
||||
assert(false);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
template<typename P, typename T,
|
||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
||||
typename std::enable_if<!std::is_same<decltype(std::declval<PIBinaryStream<P>&>() >> std::declval<T &>()), PIBinaryStreamTrivialRef<P>>::value, int>::type = 0>
|
||||
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIVector2D<T> & v) {
|
||||
//piCout << ">> vector2d trivial custom";
|
||||
int r, c;
|
||||
PIVector<T> tmp;
|
||||
r = s.binaryStreamTakeInt();
|
||||
c = s.binaryStreamTakeInt();
|
||||
s >> tmp;
|
||||
v = PIVector2D<T>(r, c, tmp);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
//! \~english Restore operator
|
||||
//! \~russian Оператор извлечения
|
||||
template<typename P>
|
||||
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIBitArray & v) {s >> v.size_ >> v.data_; return s;}
|
||||
|
||||
|
||||
//! \~english Restore operator
|
||||
//! \~russian Оператор извлечения
|
||||
template<typename P, typename Type0, typename Type1>
|
||||
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIPair<Type0, Type1> & v) {s >> v.first >> v.second; return s;}
|
||||
|
||||
|
||||
|
||||
|
||||
// store complex types
|
||||
|
||||
|
||||
//! \~english Store operator for PIVector of any compound type
|
||||
//! \~russian Оператор сохранения для PIVector сложных типов
|
||||
template<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
||||
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIVector<T> & v) {
|
||||
//piCout << "<< vector complex";
|
||||
s.binaryStreamAppend(int(v.size_s()));
|
||||
for (size_t i = 0; i < v.size(); ++i) s << v[i];
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
//! \~english Store operator for PIDeque of any compound type
|
||||
//! \~russian Оператор сохранения для PIDeque сложных типов
|
||||
template<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
||||
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIDeque<T> & v) {
|
||||
//piCout << "<< deque complex";
|
||||
s.binaryStreamAppend(int(v.size_s()));
|
||||
for (size_t i = 0; i < v.size(); ++i) s << v[i];
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
//! \~english Store operator for PIVector2D of any compound type
|
||||
//! \~russian Оператор сохранения для PIVector2D сложных типов
|
||||
template<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
||||
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIVector2D<T> & v) {
|
||||
//piCout << "<< vector2d complex";
|
||||
s.binaryStreamAppend(int(v.rows()));
|
||||
s.binaryStreamAppend(int(v.cols()));
|
||||
s << v.toPlainVector();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// restore complex types
|
||||
|
||||
|
||||
//! \~english Restore operator for PIVector of any compound type
|
||||
//! \~russian Оператор извлечения для PIVector сложных типов
|
||||
template<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
||||
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIVector<T> & v) {
|
||||
//piCout << ">> vector complex";
|
||||
/*if (s.size_s() < 4) {
|
||||
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||
assert(s.size_s() >= 4);
|
||||
}*/
|
||||
v.resize(s.binaryStreamTakeInt());
|
||||
for (size_t i = 0; i < v.size(); ++i) s >> v[i];
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
//! \~english Restore operator for PIDeque of any compound type
|
||||
//! \~russian Оператор извлечения для PIDeque сложных типов
|
||||
template<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
||||
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIDeque<T> & v) {
|
||||
//piCout << ">> deque complex";
|
||||
/*if (s.size_s() < 4) {
|
||||
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||
assert(s.size_s() >= 4);
|
||||
}*/
|
||||
v.resize(s.binaryStreamTakeInt());
|
||||
for (size_t i = 0; i < v.size(); ++i) s >> v[i];
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
//! \~english Restore operator for PIVector2D of any compound type
|
||||
//! \~russian Оператор извлечения для PIVector2D сложных типов
|
||||
template<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
||||
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIVector2D<T> & v) {
|
||||
//piCout << ">> vector2d complex";
|
||||
/*if (s.size_s() < 8) {
|
||||
printf("error with PIVecto2Dr<%s>\n", __PIP_TYPENAME__(T));
|
||||
assert(s.size_s() >= 8);
|
||||
}*/
|
||||
int r, c;
|
||||
PIVector<T> tmp;
|
||||
r = s.binaryStreamTakeInt();
|
||||
c = s.binaryStreamTakeInt();
|
||||
s >> tmp;
|
||||
v = PIVector2D<T>(r, c, tmp);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// other types
|
||||
|
||||
|
||||
//! \~english Store operator
|
||||
//! \~russian Оператор сохранения
|
||||
template <typename P, typename Key, typename T>
|
||||
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIMap<Key, T> & v) {
|
||||
s.binaryStreamAppend((int)v.pim_index.size_s());
|
||||
for (uint i = 0; i < v.size(); ++i) {
|
||||
s.binaryStreamAppend((int)v.pim_index[i].index);
|
||||
s << v.pim_index[i].key;
|
||||
}
|
||||
s << v.pim_content;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
//! \~english Restore operator
|
||||
//! \~russian Оператор извлечения
|
||||
template <typename P, typename Key, typename T>
|
||||
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIMap<Key, T> & v) {
|
||||
/*if (s.size_s() < 4) {
|
||||
printf("error with PIMap<%s, %s>\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
|
||||
assert(s.size_s() >= 4);
|
||||
}*/
|
||||
int sz = s.binaryStreamTakeInt(); v.pim_index.resize(sz);
|
||||
int ind = 0;
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
ind = s.binaryStreamTakeInt();
|
||||
s >> v.pim_index[i].key;
|
||||
v.pim_index[i].index = ind;
|
||||
}
|
||||
s >> v.pim_content;
|
||||
if (v.pim_content.size_s() != v.pim_index.size_s()) {
|
||||
piCout << "Warning: loaded invalid PIMap, clear";
|
||||
v.clear();
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// non-defined complex types
|
||||
|
||||
|
||||
template<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
||||
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const T & ) {
|
||||
static_assert(std::is_trivially_copyable<T>::value, "[PIBinaryStream] Error: using undeclared operator << for complex type!");
|
||||
return s;
|
||||
}
|
||||
|
||||
template<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
||||
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, T & ) {
|
||||
static_assert(std::is_trivially_copyable<T>::value, "[PIBinaryStream] Error: using undeclared operator >> for complex type!");
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -23,12 +23,12 @@
|
||||
|
||||
PICout operator <<(PICout s, const PIBitArray & ba) {
|
||||
s.space();
|
||||
s.setControl(0, true);
|
||||
s.saveAndSetControls(0);
|
||||
for (uint i = 0; i < ba.bitSize(); ++i) {
|
||||
s << int(ba[i]);
|
||||
if (i % 8 == 7) s << ' ';
|
||||
}
|
||||
s.restoreControl();
|
||||
s.restoreControls();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,8 +28,10 @@
|
||||
#include "pivector.h"
|
||||
|
||||
class PIP_EXPORT PIBitArray {
|
||||
friend PIByteArray & operator <<(PIByteArray & s, const PIBitArray & v);
|
||||
friend PIByteArray & operator >>(PIByteArray & s, PIBitArray & v);
|
||||
template <typename P>
|
||||
friend PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIBitArray & v);
|
||||
template <typename P>
|
||||
friend PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIBitArray & v);
|
||||
public:
|
||||
PIBitArray(const int & size = 0) {resize(size);}
|
||||
PIBitArray(uchar val) {resize(sizeof(val) * 8); data_[0] = val;}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "pibytearray.h"
|
||||
#include "pistringlist.h"
|
||||
#include <iostream>
|
||||
#include "picrc.h"
|
||||
|
||||
//! \class PIByteArray pibytearray.h
|
||||
//! \~\details
|
||||
@@ -28,53 +29,30 @@
|
||||
//! It can be constructed from any data and size.
|
||||
//! You can use %PIByteArray as binary stream
|
||||
//! to serialize/deserialize any objects and data.
|
||||
//! This class based on PIDeque<uchar> and provide some handle function
|
||||
//! See details \ref iostream.
|
||||
//! This class use PIDeque<uchar> and provide some handle function
|
||||
//! to manipulate it.
|
||||
//! \~russian
|
||||
//! %PIByteArray используется для хранения байтов.
|
||||
//! Он может быть сконструирован из любых даных.
|
||||
//! Можно использовать %PIByteArray как потоковый объект
|
||||
//! для сериализации/десериализации любых типов и данных.
|
||||
//! Этот класс наследован от PIDeque<uchar> и предоставляет набор
|
||||
//! Подробнее \ref iostream.
|
||||
//! Этот класс использует PIDeque<uchar> и предоставляет набор
|
||||
//! удобных методов для работы с байтами.
|
||||
//!
|
||||
//! \~english \section PIByteArray_sec0 Usage
|
||||
//! \~russian \section PIByteArray_sec0 Использование
|
||||
//! \~english
|
||||
//! %PIByteArray can be used to store custom data and manipulate it. There are many
|
||||
//! stream operators to store/restore common types to byte array. Store operators
|
||||
//! places data at the end of array, restore operators takes data from the beginning
|
||||
//! %PIByteArray subclass PIBinaryStream and can be used to store custom data and manipulate it.
|
||||
//! Store operators places data at the end of array, restore operators takes data from the beginning
|
||||
//! of array.
|
||||
//! In addition there are Hex and Base64 convertions
|
||||
//! In addition there are Hex and Base64 convertions.
|
||||
//! \~russian
|
||||
//! %PIByteArray может быть использован для сохранения любых данных и работы с ними.
|
||||
//! Он предоставляет множество операторов для сохранения/извлечения общих типов.
|
||||
//! %PIByteArray наследован от PIBinaryStream и может быть использован для сохранения любых данных и работы с ними.
|
||||
//! Операторы сохранения добавляют данные в конец массива, а операторы извлечения
|
||||
//! берут данные из его начала.
|
||||
//!
|
||||
//! \~english
|
||||
//! One of the major usage of %PIByteArray is stream functions. You can form binary
|
||||
//! packet from many types (also dynamic types, e.g. PIVector) with one line:
|
||||
//! \~russian
|
||||
//! Один из основных сценариев использования %PIByteArray - это потоковый объект.
|
||||
//! Можно сформировать пакет бинарных данных из многих типов (также и контейнеров,
|
||||
//! например, PIVector) в одну строку:
|
||||
//! \~\snippet pibytearray.cpp 0
|
||||
//!
|
||||
//! \~english
|
||||
//! Or you can descibe stream operator of your own type and store/restore vectors of
|
||||
//! your type:
|
||||
//! \~russian
|
||||
//! Также можно описать операторы сохранения/извлечения для собственных типов:
|
||||
//! \~\snippet pibytearray.cpp 1
|
||||
//!
|
||||
//! \~english
|
||||
//! For store/restore custom data blocks there is PIByteArray::RawData class. Stream
|
||||
//! operators of this class simply store/restore data block to/from byte array:
|
||||
//! \~russian
|
||||
//! Для сохранения/извлечения блоков произвольных данных используется класс PIByteArray::RawData.
|
||||
//! Потоковые операторы для него просто сохраняют/извлекают блоки байтов:
|
||||
//! \~\snippet pibytearray.cpp 2
|
||||
//! Также есть методы для преобразования в Hex и Base64.
|
||||
//!
|
||||
//! \~english \section PIByteArray_sec1 Attention
|
||||
//! \~russian \section PIByteArray_sec1 Внимание
|
||||
@@ -88,7 +66,7 @@
|
||||
//! а не просто добавляет его содержимое в конец. Этот оператор полезен для управляемой
|
||||
//! упаковки произвольных данных в виде %PIByteArray.
|
||||
//! Для добавления содержимого одного байтового массива к другому используется
|
||||
//! метов \a append().
|
||||
//! метод \a append().
|
||||
//! \~\snippet pibytearray.cpp 3
|
||||
//!
|
||||
|
||||
@@ -315,6 +293,19 @@ uchar PIByteArray::checksumPlain8(bool inverse) const {
|
||||
}
|
||||
|
||||
|
||||
uchar PIByteArray::checksumCRC8() const {
|
||||
return standardCRC_8().calculate(data(), size());
|
||||
}
|
||||
|
||||
ushort PIByteArray::checksumCRC16() const {
|
||||
return standardCRC_16().calculate(data(), size());
|
||||
}
|
||||
|
||||
uint PIByteArray::checksumCRC32() const {
|
||||
return standardCRC_32().calculate(data(), size());
|
||||
}
|
||||
|
||||
|
||||
//! \~\details
|
||||
//! \~english
|
||||
//! This is sum of all bytes multiplied by index+1, if inverse then add 1 and inverse.
|
||||
@@ -415,14 +406,14 @@ PIByteArray PIByteArray::fromHex(PIString str) {
|
||||
|
||||
PICout operator <<(PICout s, const PIByteArray & ba) {
|
||||
s.space();
|
||||
s.setControl(0, true);
|
||||
s.saveAndSetControls(0);
|
||||
s << "{";
|
||||
for (uint i = 0; i < ba.size(); ++i) {
|
||||
s << ba[i];
|
||||
if (i < ba.size() - 1) s << ", ";
|
||||
}
|
||||
s << "}";
|
||||
s.restoreControl();
|
||||
s.restoreControls();
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -438,38 +429,3 @@ std::ostream &operator <<(std::ostream & s, const PIByteArray & ba) {
|
||||
return s;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
PIByteArray & operator >>(PIByteArray & s, PIByteArray & v) {
|
||||
if (s.size_s() < 4) {
|
||||
s.clear();
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
assert(s.size_s() >= 4);
|
||||
int sz = 0;
|
||||
s >> sz;
|
||||
if (sz > s.size_s()) {
|
||||
piCout << "[PIByteArray] Warning: operator >> wants too much data, discard!" << sz << s.size_s();
|
||||
s.clear();
|
||||
v.clear();
|
||||
return s;
|
||||
}
|
||||
v.resize(sz);
|
||||
if (sz > 0) {
|
||||
memcpy(v.data(), s.data(), sz);
|
||||
s.remove(0, sz);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
PIByteArray & operator <<(PIByteArray & s, const PIByteArray & v) {
|
||||
s << int(v.size_s());
|
||||
int os = s.size_s();
|
||||
if (v.size_s() > 0) {
|
||||
s.enlarge(v.size_s());
|
||||
memcpy(s.data(os), v.data(), v.size());
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -27,9 +27,7 @@
|
||||
#define PIBYTEARRAY_H
|
||||
|
||||
#include "pichar.h"
|
||||
#include "pibitarray.h"
|
||||
#include "pimap.h"
|
||||
#include "pivector2d.h"
|
||||
#include "pibinarystream.h"
|
||||
#include <stdio.h>
|
||||
|
||||
class PIString;
|
||||
@@ -40,23 +38,24 @@ class PIByteArray;
|
||||
//! \~\brief
|
||||
//! \~english The %PIByteArray class provides an array of bytes.
|
||||
//! \~russian Класс %PIByteArray представляет собой массив байтов.
|
||||
class PIP_EXPORT PIByteArray: public PIDeque<uchar>
|
||||
class PIP_EXPORT PIByteArray: public PIBinaryStream<PIByteArray>
|
||||
{
|
||||
public:
|
||||
typedef ::PIMemoryBlock RawData DEPRECATEDM("use PIMemoryBlock instead");
|
||||
|
||||
//! \~english Constructs an empty byte array
|
||||
//! \~russian Создает пустой байтовый массив
|
||||
PIByteArray() {;}
|
||||
PIByteArray() {}
|
||||
|
||||
//! \~english Constructs copy of byte array "o"
|
||||
//! \~russian Создает копию байтового массива "o"
|
||||
PIByteArray(const PIByteArray & o): PIDeque<uchar>(o) {}
|
||||
PIByteArray(const PIByteArray & o): d(o.d) {}
|
||||
|
||||
//! \~english Constructs copy of byte array "o"
|
||||
//! \~russian Создает копию байтового массива "o"
|
||||
PIByteArray(const PIDeque<uchar> & o): PIDeque<uchar>(o) {}
|
||||
PIByteArray(const PIDeque<uchar> & o): d(o) {}
|
||||
|
||||
PIByteArray(PIByteArray && o): PIDeque<uchar>(std::move(o)) {}
|
||||
PIByteArray(PIByteArray && o): d(std::move(o.d)) {}
|
||||
|
||||
//! \~english Constructs 0-filled byte array with size "size"
|
||||
//! \~russian Создает заполненный "0" байтовый массив размером "size"
|
||||
@@ -64,42 +63,989 @@ public:
|
||||
|
||||
//! \~english Constructs byte array from data "data" and size "size"
|
||||
//! \~russian Создает байтовый массив из данных по указателю "data" размером "size"
|
||||
PIByteArray(const void * data, const uint size): PIDeque<uchar>((const uchar*)data, size_t(size)) {}
|
||||
PIByteArray(const void * data, const uint size): d((const uchar*)data, size_t(size)) {}
|
||||
|
||||
//! \~english Constructs byte array with size "size" filled by "t"
|
||||
//! \~russian Создает заполненный "t" байтовый массив размером "size"
|
||||
PIByteArray(const uint size, uchar t): PIDeque<uchar>(size, t) {}
|
||||
PIByteArray(const uint size, uchar t): d(size, t) {}
|
||||
|
||||
//! \~english Contructs array from
|
||||
//! [C++11 initializer list](https://en.cppreference.com/w/cpp/utility/initializer_list).
|
||||
//! \~russian Создает массив из
|
||||
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
|
||||
//! \~\details
|
||||
//! \~\code
|
||||
//! PIByteArray v{1,2,3};
|
||||
//! piCout << v; // {1, 2, 3}
|
||||
//! \endcode
|
||||
PIByteArray(std::initializer_list<uchar> init_list) : d(init_list) {}
|
||||
|
||||
//! \~english Help struct to store/restore custom blocks of data to/from PIByteArray
|
||||
//! \~russian Вспомогательная структура для сохранения/извлечения произвольного блока данных в/из байтового массива
|
||||
struct RawData {
|
||||
friend PIByteArray & operator <<(PIByteArray & s, const PIByteArray::RawData & v);
|
||||
friend PIByteArray & operator >>(PIByteArray & s, PIByteArray::RawData v);
|
||||
public:
|
||||
//! \~english Constructs data block
|
||||
//! \~russian Создает блок данных
|
||||
RawData(void * data = 0, int size = 0) {d = data; s = size;}
|
||||
RawData(const RawData & o) {d = o.d; s = o.s;}
|
||||
//! \~english Constructs data block
|
||||
//! \~russian Создает блок данных
|
||||
RawData(const void * data, const int size) {d = const_cast<void * >(data); s = size;}
|
||||
RawData & operator =(const RawData & o) {d = o.d; s = o.s; return *this;}
|
||||
private:
|
||||
void * d;
|
||||
int s;
|
||||
};
|
||||
//! \~english Swaps array `v` other with this array.
|
||||
//! \~russian Меняет местами массив `v` с этим массивом.
|
||||
//! \~\details
|
||||
//! \~english This operation is very fast and never fails.
|
||||
//! \~russian Эта операция выполняется мгновенно без копирования памяти и никогда не дает сбоев.
|
||||
inline void swap(PIByteArray & other) {
|
||||
d.swap(other.d);
|
||||
}
|
||||
|
||||
//! \~english Iterator to the first element.
|
||||
//! \~russian Итератор на первый элемент.
|
||||
//! \~\details 
|
||||
//!
|
||||
//! \~english If the array is empty, the returned iterator is equal to \a end().
|
||||
//! \~russian Если массив - пуст, возвращаемый итератор будет равен \a end().
|
||||
//! \~\return \ref stl_iterators
|
||||
//! \~\sa \a end(), \a rbegin(), \a rend()
|
||||
inline PIDeque<uchar>::iterator begin() {return d.begin();}
|
||||
|
||||
//! \~english Iterator to the element following the last element.
|
||||
//! \~russian Итератор на элемент, следующий за последним элементом.
|
||||
//! \~\details 
|
||||
//!
|
||||
//! \~english This element acts as a placeholder;
|
||||
//! attempting to access it results in undefined behavior.
|
||||
//! \~russian Этот элемент существует лишь условно,
|
||||
//! попытка доступа к нему приведёт к выходу за разрешенную память.
|
||||
//! \~\return \ref stl_iterators
|
||||
//! \~\sa \a begin(), \a rbegin(), \a rend()
|
||||
inline PIDeque<uchar>::iterator end() {return d.end();}
|
||||
|
||||
inline PIDeque<uchar>::const_iterator begin() const {return d.begin();}
|
||||
inline PIDeque<uchar>::const_iterator end() const {return d.end();}
|
||||
|
||||
//! \~english Returns a reverse iterator to the first element of the reversed array.
|
||||
//! \~russian Обратный итератор на первый элемент.
|
||||
//! \~\details 
|
||||
//!
|
||||
//! \~english It corresponds to the last element of the non-reversed array.
|
||||
//! If the array is empty, the returned iterator is equal to \a rend().
|
||||
//! \~russian Итератор для прохода массива в обратном порядке.
|
||||
//! Указывает на последний элемент.
|
||||
//! Если массив пустой, то совпадает с итератором \a rend().
|
||||
//! \~\return \ref stl_iterators
|
||||
//! \~\sa \a rend(), \a begin(), \a end()
|
||||
inline PIDeque<uchar>::reverse_iterator rbegin() {return d.rbegin();}
|
||||
|
||||
//! \~english Returns a reverse iterator to the element.
|
||||
//! following the last element of the reversed array.
|
||||
//! \~russian Обратный итератор на элемент, следующий за последним элементом.
|
||||
//! \~\details 
|
||||
//!
|
||||
//! \~english It corresponds to the element preceding the first element of the non-reversed array.
|
||||
//! This element acts as a placeholder, attempting to access it results in undefined behavior.
|
||||
//! \~russian Итератор для прохода массива в обратном порядке.
|
||||
//! Указывает на элемент, предшествующий первому элементу.
|
||||
//! Этот элемент существует лишь условно,
|
||||
//! попытка доступа к нему приведёт к выходу за разрешенную память.
|
||||
//! \~\return \ref stl_iterators
|
||||
//! \~\sa \a rbegin(), \a begin(), \a end()
|
||||
inline PIDeque<uchar>::reverse_iterator rend() {return d.rend();}
|
||||
|
||||
inline PIDeque<uchar>::const_reverse_iterator rbegin() const {return d.rbegin();}
|
||||
inline PIDeque<uchar>::const_reverse_iterator rend() const {return d.rend();}
|
||||
|
||||
//! \~english Number of elements in the container.
|
||||
//! \~russian Количество элементов массива.
|
||||
//! \~\sa \a size_s(), \a capacity(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
|
||||
inline size_t size() const {return d.size();}
|
||||
|
||||
//! \~english Number of elements in the container as signed value.
|
||||
//! \~russian Количество элементов массива в виде знакового числа.
|
||||
//! \~\sa \a size(), \a capacity(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
|
||||
inline ssize_t size_s() const {return d.size_s();}
|
||||
|
||||
//! \~english Same as \a size().
|
||||
//! \~russian Синоним \a size().
|
||||
//! \~\sa \a size(), \a size_s(), \a capacity(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
|
||||
inline size_t length() const {return d.length();}
|
||||
|
||||
//! \~english Number of elements that the container has currently allocated space for.
|
||||
//! \~russian Количество элементов, для которого сейчас выделена память массивом.
|
||||
//! \~\details
|
||||
//! \~english To find out the actual number of items, use the function \a size().
|
||||
//! \~russian Чтобы узнать фактическое количество элементов используйте функцию \a size().
|
||||
//! \~\sa \a reserve(), \a size(), \a size_s()
|
||||
inline size_t capacity() const {return d.capacity();}
|
||||
|
||||
//! \~english Checks if the container has no elements.
|
||||
//! \~russian Проверяет пуст ли массив.
|
||||
//! \~\return
|
||||
//! \~english **true** if the container is empty, **false** otherwise
|
||||
//! \~russian **true** если массив пуст, **false** иначе.
|
||||
//! \~\sa \a size(), \a size_s(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
|
||||
inline bool isEmpty() const {return d.isEmpty();}
|
||||
|
||||
//! \~english Checks if the container has elements.
|
||||
//! \~russian Проверяет не пуст ли массив.
|
||||
//! \~\return
|
||||
//! \~english **true** if the container is not empty, **false** otherwise
|
||||
//! \~russian **true** если массив не пуст, **false** иначе.
|
||||
//! \~\sa \a size(), \a size_s(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
|
||||
inline bool isNotEmpty() const {return d.isNotEmpty();}
|
||||
|
||||
//! \~english Tests whether at least one element in the array
|
||||
//! passes the test implemented by the provided function `test`.
|
||||
//! \~russian Проверяет, удовлетворяет ли какой-либо элемент массива условию,
|
||||
//! заданному в передаваемой функции `test`.
|
||||
//! \~\return
|
||||
//! \~english **true** if, in the array,
|
||||
//! it finds an element for which the provided function returns **true**;
|
||||
//! otherwise it returns **false**. Always returns **false** if is empty.
|
||||
//! \~russian **true** если хотя бы для одного элемента
|
||||
//! передаваемая функция возвращает **true**, в остальных случаях **false**.
|
||||
//! Метод возвращает **false** при любом условии для пустого массива.
|
||||
//! \~\details
|
||||
//! \~\sa \a every(), \a contains(), \a entries(), \a forEach()
|
||||
inline bool any(std::function<bool(uchar e)> test) const {
|
||||
return d.any(test);
|
||||
}
|
||||
|
||||
//! \~english Tests whether all elements in the array passes the test
|
||||
//! implemented by the provided function `test`.
|
||||
//! \~russian Проверяет, удовлетворяют ли все элементы массива условию,
|
||||
//! заданному в передаваемой функции `test`.
|
||||
//! \~\return
|
||||
//! \~english **true** if, in the array,
|
||||
//! it finds an element for which the provided function returns **true**;
|
||||
//! otherwise it returns **false**. Always returns **true** if is empty.
|
||||
//! \~russian **true** если для всех элементов передаваемая функция возвращает **true**,
|
||||
//! в остальных случаях **false**.
|
||||
//! Метод возвращает **true** при любом условии для пустого массива.
|
||||
//! \~\details
|
||||
//! \~\sa \a any(), \a contains(), \a entries(), \a forEach()
|
||||
inline bool every(std::function<bool(uchar e)> test) const {
|
||||
return d.every(test);
|
||||
}
|
||||
|
||||
//! \~english Full access to element by `index`.
|
||||
//! \~russian Полный доступ к элементу по индексу `index`.
|
||||
//! \~\details
|
||||
//! \~english Element index starts from `0`.
|
||||
//! Element index must be in range from `0` to `size()-1`.
|
||||
//! Otherwise will be undefined behavior.
|
||||
//! \~russian Индекс элемента считается от `0`.
|
||||
//! Индекс элемента должен лежать в пределах от `0` до `size()-1`.
|
||||
//! Иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
|
||||
//! \~\sa \a at()
|
||||
inline uchar & operator [](size_t index) {return d[index];}
|
||||
inline uchar operator [](size_t index) const {return d[index];}
|
||||
|
||||
//! \~english Read only access to element by `index`.
|
||||
//! \~russian Доступ исключительно на чтение к элементу по индексу `index`.
|
||||
//! \~\details
|
||||
//! \~english Element index starts from `0`.
|
||||
//! Element index must be in range from `0` to `size()-1`.
|
||||
//! Otherwise will be undefined behavior.
|
||||
//! \~russian Индекс элемента считается от `0`.
|
||||
//! Индекс элемента должен лежать в пределах от `0` до `size()-1`.
|
||||
//! Иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
|
||||
inline uchar at(size_t index) const {return d.at(index);}
|
||||
|
||||
//! \~english Last element.
|
||||
//! \~russian Последний элемент массива.
|
||||
//! \~\details
|
||||
//! \~english Returns a reference to the last item in the array.
|
||||
//! This function assumes that the array isn't empty.
|
||||
//! Otherwise will be undefined behavior.
|
||||
//! \~russian Возвращает ссылку на последний элемент в массиве.
|
||||
//! Эта функция предполагает, что массив не пустой.
|
||||
//! Иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
|
||||
inline uchar & back() {return d.back();}
|
||||
inline uchar back() const {return d.back();}
|
||||
|
||||
//! \~english Last element.
|
||||
//! \~russian Первый элемент массива.
|
||||
//! \~\details
|
||||
//! \~english Returns a reference to the last item in the array.
|
||||
//! This function assumes that the array isn't empty.
|
||||
//! Otherwise will be undefined behavior.
|
||||
//! \~russian Возвращает ссылку на пенрвый элемент в массиве.
|
||||
//! Эта функция предполагает, что массив не пустой.
|
||||
//! Иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
|
||||
inline uchar & front() {return d.front();}
|
||||
inline uchar front() const {return d.front();}
|
||||
|
||||
//! \~english Tests if element `e` exists in the array.
|
||||
//! \~russian Проверяет наличие элемента `e` в массиве.
|
||||
//! \~\details
|
||||
//! \~english Optional argument `start` - the position in this array at which to begin searching.
|
||||
//! If the index is greater than or equal to the array's size,
|
||||
//! **false** is returned, which means the array will not be searched.
|
||||
//! If the provided index value is a negative number,
|
||||
//! it is taken as the offset from the end of the array.
|
||||
//! Note: if the provided index is negative,
|
||||
//! the array is still searched from front to back.
|
||||
//! Default: 0 (entire array is searched).
|
||||
//! \~russian Опциональный аргумент `start` указывает на индекс в массиве, откуда будет начинаться поиск.
|
||||
//! Если индекс больше или равен длине массива,
|
||||
//! возвращается **false**, что означает, что массив даже не просматривается.
|
||||
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
|
||||
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
|
||||
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу.
|
||||
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
|
||||
//! \~\code
|
||||
//! PIByteArray v{1, 2, 3, 4};
|
||||
//! piCout << v.contains(3); // true
|
||||
//! piCout << v.contains(5); // false
|
||||
//! piCout << v.contains(3, 3); // false
|
||||
//! piCout << v.contains(3, -2); // true
|
||||
//! piCout << v.contains(3, -99); // true
|
||||
//! \endcode
|
||||
//! \~\return
|
||||
//! \~english **true** if the array contains an occurrence of element `e`,
|
||||
//! otherwise it returns **false**.
|
||||
//! \~russian **true** если элемент `e` присутствует в массиве,
|
||||
//! в остальных случаях **false**.
|
||||
//! \~\sa \a every(), \a any(), \a entries()
|
||||
inline bool contains(uchar e, ssize_t start = 0) const {
|
||||
return d.contains(e, start);
|
||||
}
|
||||
|
||||
//! \~english Count elements equal `e` in the array.
|
||||
//! \~russian Подсчитывает количество элементов, совпадающих с элементом `e` в массиве.
|
||||
//! \~\details
|
||||
//! \~english Optional argument `start` - the position in this array at which to begin searching.
|
||||
//! If the index is greater than or equal to the array's size,
|
||||
//! 0 is returned, which means the array will not be searched.
|
||||
//! If the provided index value is a negative number,
|
||||
//! it is taken as the offset from the end of the array.
|
||||
//! Note: if the provided index is negative,
|
||||
//! the array is still searched from front to back.
|
||||
//! Default: 0 (entire array is searched).
|
||||
//! \~russian Опциональный аргумент `start` указывает на индекс в массиве, откуда будет начинаться поиск.
|
||||
//! Если индекс больше или равен длине массива,
|
||||
//! возвращается 0, что означает, что массив даже не просматривается.
|
||||
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
|
||||
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
|
||||
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу.
|
||||
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
|
||||
//! \~\sa \a every(), \a any(), \a contains(), \a indexOf()
|
||||
inline int entries(uchar e, ssize_t start = 0) const {
|
||||
return d.entries(e, start);
|
||||
}
|
||||
|
||||
//! \~english Count elements in the array passes the test implemented by the provided function `test`.
|
||||
//! \~russian Подсчитывает количество элементов в массиве,
|
||||
//! проходящих по условию, заданному в передаваемой функции `test`.
|
||||
//! \~\details
|
||||
//! \~english Overloaded function.
|
||||
//! Optional argument `start` - the position in this array at which to begin searching.
|
||||
//! If the index is greater than or equal to the array's size,
|
||||
//! 0 is returned, which means the array will not be searched.
|
||||
//! If the provided index value is a negative number,
|
||||
//! it is taken as the offset from the end of the array.
|
||||
//! Note: if the provided index is negative,
|
||||
//! the array is still searched from front to back.
|
||||
//! Default: 0 (entire array is searched).
|
||||
//! \~russian Перегруженная функция.
|
||||
//! Опциональный аргумент `start` указывает на индекс в массиве, откуда будет начинаться поиск.
|
||||
//! Если индекс больше или равен длине массива,
|
||||
//! возвращается 0, что означает, что массив даже не просматривается.
|
||||
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
|
||||
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
|
||||
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу.
|
||||
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
|
||||
//! \~\sa \a every(), \a any(), \a contains(), \a indexWhere()
|
||||
inline int entries(std::function<bool(uchar e)> test, ssize_t start = 0) const {
|
||||
return d.entries(test, start);
|
||||
}
|
||||
|
||||
//! \~english Returns the first index at which a given element `e`
|
||||
//! can be found in the array, or `-1` if it is not present.
|
||||
//! \~russian Возвращает первый индекс, по которому данный элемент `e`
|
||||
//! может быть найден в массиве или `-1`, если такого индекса нет.
|
||||
//! \~\details
|
||||
//! \~english Optional argument `start` - the position in this array at which to begin searching.
|
||||
//! If the index is greater than or equal to the array's size,
|
||||
//! `-1` is returned, which means the array will not be searched.
|
||||
//! If the provided index value is a negative number,
|
||||
//! it is taken as the offset from the end of the array.
|
||||
//! Note: if the provided index is negative,
|
||||
//! the array is still searched from front to back.
|
||||
//! Default: 0 (entire array is searched).
|
||||
//! \~russian Опциональный аргумент `start` указывает на индекс в массиве, откуда будет начинаться поиск.
|
||||
//! Если индекс больше или равен длине массива,
|
||||
//! возвращается `-1`, что означает, что массив даже не просматривается.
|
||||
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
|
||||
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
|
||||
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу.
|
||||
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
|
||||
//! \~\code
|
||||
//! PIByteArray v{2, 5, 9};
|
||||
//! piCout << v.indexOf(2); // 0
|
||||
//! piCout << v.indexOf(7); // -1
|
||||
//! piCout << v.indexOf(9, 2); // 2
|
||||
//! piCout << v.indexOf(2, -1); // -1
|
||||
//! piCout << v.indexOf(2, -3); // 0
|
||||
//! \endcode
|
||||
//! \~\sa \a indexWhere(), \a lastIndexOf(), \a lastIndexWhere(), \a contains()
|
||||
inline ssize_t indexOf(const uchar & e, ssize_t start = 0) const {
|
||||
return d.indexOf(e, start);
|
||||
}
|
||||
|
||||
//! \~english Returns the first index passes the test implemented by the provided function `test`,
|
||||
//! or `-1` if it is not present.
|
||||
//! can be found in the array, or `-1` if it is not present.
|
||||
//! \~russian Возвращает первый индекс элемента проходящего по условию,
|
||||
//! заданному в передаваемой функции `test`, или `-1`, если таких элементов нет.
|
||||
//! \~\details
|
||||
//! \~english Optional argument `start` - the position in this array at which to begin searching.
|
||||
//! If the index is greater than or equal to the array's size,
|
||||
//! `-1` is returned, which means the array will not be searched.
|
||||
//! If the provided index value is a negative number,
|
||||
//! it is taken as the offset from the end of the array.
|
||||
//! Note: if the provided index is negative,
|
||||
//! the array is still searched from front to back.
|
||||
//! Default: 0 (entire array is searched).
|
||||
//! \~russian Опциональный аргумент `start` указывает на индекс в массиве, откуда будет начинаться поиск.
|
||||
//! Если индекс больше или равен длине массива,
|
||||
//! возвращается `-1`, что означает, что массив даже не просматривается.
|
||||
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
|
||||
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
|
||||
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу.
|
||||
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
|
||||
//! \~\code
|
||||
//! PIByteArray v{2, 5, 9};
|
||||
//! piCout << v.indexWhere([](const uchar & s){return s > 3;}); // 1
|
||||
//! piCout << v.indexWhere([](const uchar & s){return s > 3;}, 2); // 2
|
||||
//! piCout << v.indexWhere([](const uchar & s){return s > 10;}); // -1
|
||||
//! \endcode
|
||||
//! \~\sa \a indexOf(), \a lastIndexOf(), \a lastIndexWhere(), \a contains()
|
||||
inline ssize_t indexWhere(std::function<bool(const uchar & e)> test, ssize_t start = 0) const {
|
||||
return d.indexWhere(test, start);
|
||||
}
|
||||
|
||||
//! \~english Returns the last index at which a given element `e`
|
||||
//! can be found in the array, or `-1` if it is not present.
|
||||
//! \~russian Возвращает последний индекс, по которому данный элемент `e`
|
||||
//! может быть найден в массиве или `-1`, если такого индекса нет.
|
||||
//! \~\details
|
||||
//! \~english Optional argument `start` - the position in this array
|
||||
//! at which to start searching backwards.
|
||||
//! If the index is greater than or equal to the array's size,
|
||||
//! causes the whole array to be searched.
|
||||
//! If the provided index value is a negative number,
|
||||
//! it is taken as the offset from the end of the array.
|
||||
//! Therefore, if calculated index less than 0,
|
||||
//! the array is not searched, and the method returns `-1`.
|
||||
//! Note: if the provided index is negative,
|
||||
//! the array is still searched from back to front.
|
||||
//! Default: -1 (entire array is searched).
|
||||
//! \~russian Опциональный аргумент `start` указывает на индекс
|
||||
//! c которого начинать поиск в обратном направлении.
|
||||
//! Если индекс больше или равен длине массива, просматривается весь массив.
|
||||
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
|
||||
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от конца к началу.
|
||||
//! Если рассчитанный индекс оказывается меньше 0, массив даже не просматривается.
|
||||
//! Значение по умолчанию равно `-1`, что равно индексу последнего элемента
|
||||
//! и означает, что просматривается весь массив.
|
||||
//! \~\code
|
||||
//! PIByteArray v{2, 5, 9, 2};
|
||||
//! piCout << v.lastIndexOf(2); // 3
|
||||
//! piCout << v.lastIndexOf(7); // -1
|
||||
//! piCout << v.lastIndexOf(2, 2); // 0
|
||||
//! piCout << v.lastIndexOf(2, -3); // 0
|
||||
//! piCout << v.lastIndexOf(2, -300); // -1
|
||||
//! piCout << v.lastIndexOf(2, 300); // 3
|
||||
//! \endcode
|
||||
//! \~\sa \a indexOf(), \a indexWhere(), \a lastIndexWhere(), \a contains()
|
||||
inline ssize_t lastIndexOf(const uchar & e, ssize_t start = -1) const {
|
||||
return d.lastIndexOf(e, start);
|
||||
}
|
||||
|
||||
//! \~english Returns the last index passes the test implemented by the provided function `test`,
|
||||
//! or `-1` if it is not present.
|
||||
//! \~russian Возвращает последний индекс элемента проходящего по условию,
|
||||
//! заданному в передаваемой функции `test`, или `-1`, если таких элементов нет.
|
||||
//! \~\details
|
||||
//! \~english Optional argument `start` - the position in this array
|
||||
//! at which to start searching backwards.
|
||||
//! If the index is greater than or equal to the array's size,
|
||||
//! causes the whole array to be searched.
|
||||
//! If the provided index value is a negative number,
|
||||
//! it is taken as the offset from the end of the array.
|
||||
//! Therefore, if calculated index less than 0,
|
||||
//! the array is not searched, and the method returns `-1`.
|
||||
//! Note: if the provided index is negative,
|
||||
//! the array is still searched from back to front.
|
||||
//! Default: -1 (entire array is searched).
|
||||
//! \~russian Опциональный аргумент `start` указывает на индекс
|
||||
//! c которого начинать поиск в обратном направлении.
|
||||
//! Если индекс больше или равен длине массива, просматривается весь массив.
|
||||
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
|
||||
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от конца к началу.
|
||||
//! Если рассчитанный индекс оказывается меньше 0, массив даже не просматривается.
|
||||
//! Значение по умолчанию равно `-1`, что равно индексу последнего элемента
|
||||
//! и означает, что просматривается весь массив.
|
||||
//! \~\sa \a indexOf(), \a lastIndexOf(), \a indexWhere(), \a contains()
|
||||
inline ssize_t lastIndexWhere(std::function<bool(const uchar & e)> test, ssize_t start = -1) const {
|
||||
return d.lastIndexWhere(test, start);
|
||||
}
|
||||
|
||||
//! \~english Pointer to array
|
||||
//! \~russian Указатель на память массива
|
||||
//! \~\details
|
||||
//! \~english Optional argument `index` the position in this array,
|
||||
//! where is pointer. Default: start of array.
|
||||
//! \~russian Опциональный аргумент `index` указывает на индекс c которого брать указатель.
|
||||
//! По умолчанию указывает на начало массива.
|
||||
inline uchar * data(size_t index = 0) {return d.data(index);}
|
||||
|
||||
//! \~english Read only pointer to array
|
||||
//! \~russian Указатель на память массива только для чтения.
|
||||
//! \~\details
|
||||
//! \~english The pointer can be used to access and modify the items in the array.
|
||||
//! The pointer remains valid as long as the array isn't reallocated.
|
||||
//! Optional argument `index` the position in this array,
|
||||
//! where is pointer. Default: start of array.
|
||||
//! \~russian Указатель можно использовать для доступа и изменения элементов в массиве.
|
||||
//! Указатель остается действительным только до тех пор, пока массив не будет перераспределен.
|
||||
//! Опциональный аргумент `index` указывает на индекс c которого брать указатель.
|
||||
//! По умолчанию указывает на начало массива.
|
||||
inline const uchar * data(size_t index = 0) const {return d.data(index);}
|
||||
|
||||
//! \~english Clear array, remove all elements.
|
||||
//! \~russian Очищает массив, удаляет все элементы.
|
||||
//! \~\details
|
||||
//! \~\note
|
||||
//! \~english Reserved memory will not be released.
|
||||
//! \~russian Зарезервированная память не освободится.
|
||||
//! \~\sa \a resize()
|
||||
inline PIByteArray & clear() {
|
||||
resize(0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Assigns element 'e' to all items in the array.
|
||||
//! \~russian Заполняет весь массив копиями элемента 'e'.
|
||||
//! \~\details
|
||||
//! \~\sa \a resize()
|
||||
inline PIByteArray & fill(uchar e = 0) {
|
||||
d.fill(e);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Assigns result of function 'f(size_t i)' to all items in the array.
|
||||
//! \~russian Заполняет весь массив результатом вызова функции 'f(size_t i)'.
|
||||
//! \~\details
|
||||
//! \~\sa \a resize()
|
||||
inline PIByteArray & fill(std::function<uchar(size_t i)> f) {
|
||||
d.fill(f);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Same as \a fill().
|
||||
//! \~russian Тоже самое что и \a fill().
|
||||
//! \~\sa \a fill(), \a resize()
|
||||
inline PIByteArray & assign(uchar e = 0) {return fill(e);}
|
||||
|
||||
//! \~english First does `resize(new_size)` then `fill(e)`.
|
||||
//! \~russian Сначала делает `resize(new_size)`, затем `fill(e)`.
|
||||
//! \~\sa \a fill(), \a resize()
|
||||
inline PIByteArray & assign(size_t new_size, uchar e) {
|
||||
resize(new_size);
|
||||
return fill(e);
|
||||
}
|
||||
|
||||
//! \~english Sets size of the array, new elements are copied from `e`.
|
||||
//! \~russian Устанавливает размер массива, новые элементы копируются из `e`.
|
||||
//! \~\details
|
||||
//! \~english If `new_size` is greater than the current \a size(),
|
||||
//! elements are added to the end; the new elements are initialized from `e`.
|
||||
//! If `new_size` is less than the current \a size(), elements are removed from the end.
|
||||
//! \~russian Если `new_size` больше чем текущий размер массива \a size(),
|
||||
//! новые элементы добавляются в конец массива и создаются из `e`.
|
||||
//! Если `new_size` меньше чем текущий размер массива \a size(),
|
||||
//! лишние элементы удаляются с конца массива.
|
||||
//! \~\sa \a size(), \a clear()
|
||||
inline PIByteArray & resize(size_t new_size, uchar e = 0) {
|
||||
d.resize(new_size, e);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Sets size of the array, new elements created by function `f(size_t i)`.
|
||||
//! \~russian Устанавливает размер массива, новые элементы создаются функцией `f(size_t i)`.
|
||||
//! \~\details
|
||||
//! \~english If `new_size` is greater than the current \a size(),
|
||||
//! elements are added to the end; the new elements created by function `f(size_t i)`.
|
||||
//! If `new_size` is less than the current \a size(), elements are removed from the end.
|
||||
//! \~russian Если `new_size` больше чем текущий размер массива \a size(),
|
||||
//! новые элементы добавляются в конец массива и функцией `f(size_t i)`.
|
||||
//! Если `new_size` меньше чем текущий размер массива \a size(),
|
||||
//! лишние элементы удаляются с конца массива.
|
||||
//! \~\sa \a size(), \a clear()
|
||||
inline PIByteArray & resize(size_t new_size, std::function<uchar(size_t i)> f) {
|
||||
d.resize(new_size, f);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Return resized byte array
|
||||
//! \~russian Возвращает копию байтового массива с измененным размером
|
||||
PIByteArray resized(uint new_size) const {PIByteArray ret(new_size); memcpy(ret.data(), data(), new_size); return ret;}
|
||||
PIByteArray resized(uint new_size) const {
|
||||
PIByteArray ret(new_size);
|
||||
memcpy(ret.data(), data(), new_size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
//! \~english Attempts to allocate memory for at least `new_size` elements.
|
||||
//! \~russian Резервируется память под как минимум `new_size` элементов.
|
||||
//! \~\details
|
||||
//! \~english If you know in advance how large the array will be,
|
||||
//! you should call this function to prevent reallocations and memory fragmentation.
|
||||
//! If `new_size` is greater than the current \a capacity(),
|
||||
//! new storage is allocated, otherwise the function does nothing.
|
||||
//! This function does not change the \a size() of the array.
|
||||
//! \~russian Если вы заранее знаете, насколько велик будет массив,
|
||||
//! вы можете вызвать эту функцию, чтобы предотвратить перераспределение и фрагментацию памяти.
|
||||
//! Если размер `new_size` больше чем выделенная память \a capacity(),
|
||||
//! то произойдёт выделение новой памяти и перераспределение массива.
|
||||
//! Эта функция не изменяет количество элементов в массиве \a size().
|
||||
//! \~\sa \a size(), \a capacity(), \a resize()
|
||||
inline PIByteArray & reserve(size_t new_size) {
|
||||
d.reserve(new_size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Inserts value `e` at `index` position in the array.
|
||||
//! \~russian Вставляет значение `e` в позицию `index` в массиве.
|
||||
//! \~\details
|
||||
//! \~english The index must be greater than 0 and less than or equal to \a size().
|
||||
//! \~russian Индекс должен быть больше 0 и меньше или равен \a size().
|
||||
//! \~\sa \a append(), \a prepend(), \a remove()
|
||||
inline PIByteArray & insert(size_t index, uchar e = 0) {
|
||||
d.insert(index, e);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Inserts array `v` at `index` position in the array.
|
||||
//! \~russian Вставляет массив `v` в позицию `index` в массиве.
|
||||
//! \~\details
|
||||
//! \~english The index must be greater than or equal to 0 and less than or equal to \a size().
|
||||
//! \~russian Индекс должен быть больше или равен 0 и меньше или равен \a size().
|
||||
//! \~\sa \a append(), \a prepend(), \a remove()
|
||||
inline PIByteArray & insert(size_t index, const PIByteArray & v) {
|
||||
d.insert(index, v.d);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Inserts the given elements at `index` position in the array.
|
||||
//! \~russian Вставляет элементы в позицию `index` в массиве.
|
||||
//! \~\details
|
||||
//! \~english The index must be greater than or equal to 0 and less than or equal to \a size().
|
||||
//! Inserts the given elements from
|
||||
//! [C++11 initializer list](https://en.cppreference.com/w/cpp/utility/initializer_list).
|
||||
//! \~russian Индекс должен быть больше или равен 0 и меньше или равен \a size().
|
||||
//! Вставляет элементы из
|
||||
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
|
||||
//! \~\sa \a append(), \a prepend(), \a remove()
|
||||
inline PIByteArray & insert(size_t index, std::initializer_list<uchar> init_list) {
|
||||
d.insert(index, init_list);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Removes `count` elements from the middle of the array, starting at `index` position.
|
||||
//! \~russian Удаляет элементы из массива, начиная с позиции `index` в количестве `count`.
|
||||
//! \~\details
|
||||
//! \~\sa \a resize(), \a insert(), \a removeOne(), \a removeAll(), \a removeWhere()
|
||||
inline PIByteArray & remove(size_t index, size_t count = 1) {
|
||||
d.remove(index, count);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Return sub-array starts from "index" and has "count" or less bytes
|
||||
//! \~russian Возвращает подмассив с данными от индекса "index" и размером не более "count"
|
||||
PIByteArray getRange(size_t index, size_t count) const {
|
||||
return PIDeque<uchar>::getRange(index, count);
|
||||
return d.getRange(index, count);
|
||||
}
|
||||
|
||||
//! \~english Reverses this array.
|
||||
//! \~russian Обращает порядок следования элементов этого массива.
|
||||
//! \~\details
|
||||
//! \~english This method reverses an array [in place](https://en.wikipedia.org/wiki/In-place_algorithm).
|
||||
//! The first array element becomes the last, and the last array element becomes the first.
|
||||
//! The reverse method transposes the elements of the calling array object in place,
|
||||
//! mutating the array, and returning a reference to the array.
|
||||
//! \~russian Метод reverse() на месте переставляет элементы массива,
|
||||
//! на котором он был вызван, изменяет массив и возвращает ссылку на него.
|
||||
//! Первый элемент массива становится последним, а последний — первым.
|
||||
//! \~\sa \a reversed()
|
||||
inline PIByteArray & reverse() {
|
||||
d.reverse();
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Returns reversed array.
|
||||
//! \~russian Возвращает перевернутый массив.
|
||||
//! \~\details
|
||||
//! \~english Returns a copy of the array with elements in reverse order.
|
||||
//! The first array element becomes the last, and the last array element becomes the first.
|
||||
//! \~russian Возвращает копию массива с элементами в обратном порядке.
|
||||
//! Первый элемент массива становится последним, а последний — первым.
|
||||
//! \~\sa \a reverse()
|
||||
inline PIByteArray reversed() const {
|
||||
PIByteArray ret(*this);
|
||||
return ret.reverse();
|
||||
}
|
||||
|
||||
//! \~english Increases or decreases the size of the array by `add_size` elements.
|
||||
//! \~russian Увеличивает или уменьшает размер массива на `add_size` элементов.
|
||||
//! \~\details
|
||||
//! \~english If `add_size > 0` then elements are added to the end of the array.
|
||||
//! If `add_size < 0` then elements are removed from the end of the array.
|
||||
//! If `add_size < 0` and there are fewer elements in the array than specified, then the array becomes empty.
|
||||
//! \~russian Если `add_size > 0`, то в конец массива добавляются элементы.
|
||||
//! Если `add_size < 0`, то с конца массива удаляются элементы.
|
||||
//! Если `add_size < 0` и в массиве меньше элементов чем указано, то массив становится пустым.
|
||||
//! \~\sa \a resize()
|
||||
inline PIByteArray & enlarge(ssize_t add_size, uchar e = 0) {
|
||||
d.enlarge(add_size, e);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Remove no more than one element equal `e`.
|
||||
//! \~russian Удаляет первый элемент, который равен элементу `e`.
|
||||
//! \~\details
|
||||
//! \~\sa \a remove(), \a removeAll(), \a removeWhere()
|
||||
inline PIByteArray & removeOne(uchar e) {
|
||||
d.removeOne(e);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Remove all elements equal `e`.
|
||||
//! \~russian Удаляет все элементы, равные элементу `e`.
|
||||
//! \~\details
|
||||
//! \~\sa \a remove(), \a removeOne(), \a removeWhere()
|
||||
inline PIByteArray & removeAll(uchar e) {
|
||||
d.removeAll(e);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Remove all elements in the array
|
||||
//! passes the test implemented by the provided function `test`.
|
||||
//! \~russian Удаляет все элементы, удовлетворяющие условию,
|
||||
//! заданному в передаваемой функции `test`.
|
||||
//! \~\details
|
||||
//! \~\sa \a remove(), \a removeOne(), \a removeWhere()
|
||||
inline PIByteArray & removeWhere(std::function<bool(uchar e)> test) {
|
||||
d.removeWhere(test);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Appends the given element `e` to the end of the array.
|
||||
//! \~russian Добавляет элемент `e` в конец массива.
|
||||
//! \~\details
|
||||
//! \~english If size() is less than capacity(), which is most often
|
||||
//! then the addition will be very fast.
|
||||
//! In any case, the addition is fast and does not depend on the size of the array.
|
||||
//! If the new size() is greater than capacity()
|
||||
//! then all iterators and references
|
||||
//! (including the past-the-end iterator) are invalidated.
|
||||
//! Otherwise only the past-the-end iterator is invalidated.
|
||||
//! \~russian Если size() меньше capacity(), что часто бывает,
|
||||
//! то добавление будет очень быстрым.
|
||||
//! В любом случае добавление быстрое и не зависит от размера массива.
|
||||
//! Если новый size() больше, чем capacity(),
|
||||
//! то все итераторы и указатели становятся нерабочими.
|
||||
//! В противном случае все, кроме итераторов, указывающих на конец массива,
|
||||
//! остаются в рабочем состоянии.
|
||||
//! \~\sa \a push_front(), \a append(), \a prepend(), \a insert()
|
||||
inline PIByteArray & push_back(uchar e) {
|
||||
d.push_back(e);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Appends the given elements to the end of the array.
|
||||
//! \~russian Добавляет элементы в конец массива.
|
||||
//! \~\details
|
||||
//! \~english Overloaded function.
|
||||
//! Appends the given elements from
|
||||
//! [C++11 initializer list](https://en.cppreference.com/w/cpp/utility/initializer_list).
|
||||
//! \~russian Перегруженая функция.
|
||||
//! Добавляет элементы из
|
||||
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
|
||||
//! \~\sa \a push_back()
|
||||
inline PIByteArray & push_back(std::initializer_list<uchar> init_list) {
|
||||
d.push_back(init_list);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Appends the given array `v` to the end of the array.
|
||||
//! \~russian Добавляет массив `v` в конец массива.
|
||||
//! \~\details
|
||||
//! \~english Overloaded function.
|
||||
//! \~russian Перегруженая функция.
|
||||
//! \~\sa \a push_back()
|
||||
inline PIByteArray & push_back(const PIByteArray & v) {
|
||||
d.push_back(v.d);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
//! \~english Add to the end data "data" with size "size"
|
||||
//! \~russian Добавляет в конец массива данные по указателю "data" размером "size"
|
||||
PIByteArray & push_back(const void * data_, int size_) {uint ps = size(); enlarge(size_); memcpy(data(ps), data_, size_); return *this;}
|
||||
|
||||
//! \~english Appends the given element `e` to the begin of the array.
|
||||
//! \~russian Добавляет элемент `e` в начало массива.
|
||||
//! \~\details
|
||||
//! \~english If there is free space at the beginning of the array,
|
||||
//! which is most often, then the addition will be very fast.
|
||||
//! In any case, the addition is fast and does not depend on the size of the array.
|
||||
//! If there is no free space at the beginning of the array
|
||||
//! then all iterators and references
|
||||
//! (including the past-the-begin iterator) are invalidated.
|
||||
//! Otherwise only the past-the-begin iterator is invalidated.
|
||||
//! \~russian Если в начале массива имеется свободное место,
|
||||
//! что часто бывает, то добавление будет очень быстрым.
|
||||
//! В любом случае добавление быстрое и не зависит от размера массива.
|
||||
//! Если в начале массива нет свободного места,
|
||||
//! то все итераторы и указатели становятся нерабочими.
|
||||
//! В противном случае все, кроме итераторов указывающих, на начало массива,
|
||||
//! остаются в рабочем состоянии.
|
||||
//! \~\sa \a push_back(), \a append(), \a prepend(), \a insert()
|
||||
inline PIByteArray & push_front(uchar e) {
|
||||
d.push_front(e);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Appends the given array `v` to the begin of the array.
|
||||
//! \~russian Добавляет массив `v` в начало массива.
|
||||
//! \~\details
|
||||
//! \~english Overloaded function.
|
||||
//! \~russian Перегруженая функция.
|
||||
//! \~\sa \a push_front()
|
||||
inline PIByteArray & push_front(const PIByteArray & v) {
|
||||
d.push_front(v.d);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Appends the given elements to the begin of the array.
|
||||
//! \~russian Добавляет элементы в начало массива.
|
||||
//! \~\details
|
||||
//! \~english Overloaded function.
|
||||
//! Appends the given elements from
|
||||
//! [C++11 initializer list](https://en.cppreference.com/w/cpp/utility/initializer_list).
|
||||
//! \~russian Перегруженая функция.
|
||||
//! Добавляет элементы из
|
||||
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
|
||||
//! \~\sa \a append()
|
||||
inline PIByteArray & push_front(std::initializer_list<uchar> init_list) {
|
||||
d.push_front(init_list);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Appends the given element `e` to the begin of the array.
|
||||
//! \~russian Добавляет элемент `e` в начало массива.
|
||||
//! \~\details
|
||||
//! \~english If there is free space at the beginning of the array,
|
||||
//! which is most often, then the addition will be very fast.
|
||||
//! In any case, the addition is fast and does not depend on the size of the array.
|
||||
//! If there is no free space at the beginning of the array
|
||||
//! then all iterators and references
|
||||
//! (including the past-the-begin iterator) are invalidated.
|
||||
//! Otherwise only the past-the-begin iterator is invalidated.
|
||||
//! \~russian Если в начале массива имеется свободное место,
|
||||
//! что часто бывает, то добавление будет очень быстрым.
|
||||
//! В любом случае добавление быстрое и не зависит от размера массива.
|
||||
//! Если в начале массива нет свободного места,
|
||||
//! то все итераторы и указатели становятся нерабочими.
|
||||
//! В противном случае все, кроме итераторов указывающих, на начало массива,
|
||||
//! остаются в рабочем состоянии.
|
||||
//! \~\sa \a push_back(), \a append(), \a prepend(), \a insert()
|
||||
inline PIByteArray & prepend(uchar e) {
|
||||
d.prepend(e);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Appends the given array `v` to the begin of the array.
|
||||
//! \~russian Добавляет массив `v` в начало массива.
|
||||
//! \~\details
|
||||
//! \~english Overloaded function.
|
||||
//! \~russian Перегруженая функция.
|
||||
//! \~\sa \a prepend()
|
||||
inline PIByteArray & prepend(const PIByteArray & v) {
|
||||
d.prepend(v.d);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Appends the given elements to the begin of the array.
|
||||
//! \~russian Добавляет элементы в начало массива.
|
||||
//! \~\details
|
||||
//! \~english Overloaded function.
|
||||
//! Appends the given elements from
|
||||
//! [C++11 initializer list](https://en.cppreference.com/w/cpp/utility/initializer_list).
|
||||
//! \~russian Перегруженая функция.
|
||||
//! Добавляет элементы из
|
||||
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
|
||||
//! \~\sa \a append()
|
||||
inline PIByteArray & prepend(std::initializer_list<uchar> init_list) {
|
||||
d.prepend(init_list);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Remove one element from the end of the array.
|
||||
//! \~russian Удаляет один элемент с конца массива.
|
||||
//! \~\details
|
||||
//! \~english Deleting an element from the end is very fast
|
||||
//! and does not depend on the size of the array.
|
||||
//! \~russian Удаление элемента с конца выполняется очень быстро
|
||||
//! и не зависит от размера массива.
|
||||
//! \~\sa \a pop_front(), \a take_back(), \a take_front()
|
||||
inline PIByteArray & pop_back() {
|
||||
d.pop_back();
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Remove one element from the begining of the array.
|
||||
//! \~russian Удаляет один элемент с начала массива.
|
||||
//! \~\details
|
||||
//! \~english Removing an element from the beginning takes longer than from the end.
|
||||
//! This time is directly proportional to the size of the array.
|
||||
//! All iterators and references are invalidated.
|
||||
//! \~russian Удаление элемента с начала выполняется дольше, чем с конца.
|
||||
//! Это время прямопропорционально размеру массива.
|
||||
//! При удалении элемента все итераторы и указатели становятся нерабочими.
|
||||
//! \~\sa \a pop_back(), \a take_back(), \a take_front()
|
||||
inline PIByteArray & pop_front() {
|
||||
d.pop_front();
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Remove one element from the end of the array and return it.
|
||||
//! \~russian Удаляет один элемент с начала массива и возвращает его.
|
||||
//! \~\details
|
||||
//! \~\sa \a take_front(), \a pop_back(), \a pop_front()
|
||||
inline uchar take_back() {
|
||||
return d.take_back();
|
||||
}
|
||||
|
||||
//! \~english Remove one element from the begining of the array and return it.
|
||||
//! \~russian Удаляет один элемент с конца массива и возвращает его.
|
||||
//! \~\details
|
||||
//! \~\sa \a take_front(), \a pop_back(), \a pop_front()
|
||||
inline uchar take_front() {
|
||||
return d.take_front();
|
||||
}
|
||||
|
||||
//! \~english Returns a new array with all elements
|
||||
//! that pass the test implemented by the provided function `test`.
|
||||
//! \~russian Возвращает новый массив со всеми элементами,
|
||||
//! прошедшими проверку, задаваемую в передаваемой функции `test`.
|
||||
//! \~\details
|
||||
//! \~\code
|
||||
//! PIByteArray v{3, 2, 5, 2, 7};
|
||||
//! PIByteArray v2 = v.filter([](const uchar & i){return i > 2;});
|
||||
//! piCout << v2; // {3, 5, 7}
|
||||
//! \endcode
|
||||
//! \~\sa \a map(), \a any(), \a every()
|
||||
inline PIByteArray filter(std::function<bool(const uchar & e)> test) const {
|
||||
return PIByteArray(d.filter(test));
|
||||
}
|
||||
|
||||
//! \~english Execute function `void f(const uchar & e)` for every element in array.
|
||||
//! \~russian Выполняет функцию `void f(const uchar & e)` для каждого элемента массива.
|
||||
//! \~\details
|
||||
//! \~russian Не позволяет изменять элементы массива.
|
||||
//! Для редактирования элементов используйте функцию вида `void f(uchar & e)`.
|
||||
//! \~english Does not allow changing array elements.
|
||||
//! To edit elements, use the function like `void f(T & e)`
|
||||
//! \~\code
|
||||
//! PIByteArray v{1, 2, 3, 4, 5};
|
||||
//! int s = 0;
|
||||
//! v.forEach([&s](const uchar & e){s += e;});
|
||||
//! piCout << s; // 15
|
||||
//! \endcode
|
||||
//! \~\sa \a filter(), \a map(), \a reduce(), \a any(), \a every()
|
||||
inline void forEach(std::function<void(const uchar & e)> f) const {
|
||||
d.forEach(f);
|
||||
}
|
||||
|
||||
//! \~english Execute function `void f(uchar & e)` for every element in array.
|
||||
//! \~russian Выполняет функцию `void f(uchar & e)` для каждого элемента массива.
|
||||
//! \~\details
|
||||
//! \~english Overloaded function.
|
||||
//! Allows you to change the elements of the array.
|
||||
//! \~russian Перегруженая функция.
|
||||
//! Позволяет изменять элементы массива.
|
||||
//! \~\code
|
||||
//! PIByteArray v{1, 2, 3, 4, 5};
|
||||
//! v.forEach([](uchar & e){e++;});
|
||||
//! piCout << v; // {2, 3, 4, 5, 6}
|
||||
//! \endcode
|
||||
//! \~\sa \a filter(), \a map(), \a reduce(), \a any(), \a every()
|
||||
inline PIByteArray & forEach(std::function<void(uchar & e)> f) {
|
||||
d.forEach(f);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Сreates a new array populated with the results
|
||||
//! of calling a provided function `ST f(const uchar & e)` on every element in the calling array.
|
||||
//! \~russian Создаёт новый массив с результатом вызова указанной функции
|
||||
//! `ST f(const T & e)` для каждого элемента массива.
|
||||
//! \~\details
|
||||
//! \~english Calls a provided function`ST f(const uchar & e)`
|
||||
//! once for each element in an array, in order,
|
||||
//! and constructs a new array from the results.
|
||||
//! \~russian Метод `map` вызывает переданную функцию `ST f(const uchar & e)`
|
||||
//! один раз для каждого элемента в порядке их появления
|
||||
//! и конструирует новый массив из результатов её вызова.
|
||||
//! \~\code
|
||||
//! PIByteArray v{0x31, 0x0A, 0xFF};
|
||||
//! PIStringList sl = v.map<PIString>([](const uchar & i){return PIString::fromNumber(i, 16);});
|
||||
//! piCout << sl; {"31", "A", "FF"}
|
||||
//! \endcode
|
||||
//! \~\sa \a forEach(), \a reduce()
|
||||
template <typename ST>
|
||||
inline PIDeque<ST> map(std::function<ST(const uchar & e)> f) const {
|
||||
return d.map<ST>(f);
|
||||
}
|
||||
|
||||
//! \~english Applies the function `ST f(const uchar & e, const ST & acc)`
|
||||
//! to each element of the array (from left to right), returns one value.
|
||||
//! \~russian Применяет функцию `ST f(const uchar & e, const ST & acc)`
|
||||
//! к каждому элементу массива (слева-направо), возвращает одно значение.
|
||||
//! \~\details
|
||||
//! \~english The reduce() method performs the `f` function
|
||||
//! once for each element in the array.
|
||||
//! If the `initial` argument is passed when calling reduce(),
|
||||
//! then when the function `f` is called for the first time,
|
||||
//! the value of `acc` will be assigned to `initial`.
|
||||
//! If the array is empty, the value `initial` will be returned.
|
||||
//! \param f is a function like `ST f(const uchar & e, const ST & acc)`,
|
||||
//! executed for each element of the array. It takes two arguments:
|
||||
//! * **e** - current element of the array
|
||||
//! * **acc** - accumulator accumulating the value
|
||||
//! which this function returns after visiting the next element
|
||||
//!
|
||||
//! \param initial _optional_ Object used as the second argument
|
||||
//! when the `f` function is first called.
|
||||
//! \~russian Метод reduce() выполняет функцию `f`
|
||||
//! один раз для каждого элемента, присутствующего в массиве.
|
||||
//! Если при вызове reduce() передан аргумент `initial`,
|
||||
//! то при первом вызове функции `f` значение `acc`
|
||||
//! будет равным значению `initial`.
|
||||
//! Если массив пустой то будет возвращено значение `initial`.
|
||||
//! \param f Функция, вида `ST f(const uchar & e, const ST & acc)`,
|
||||
//! выполняющаяся для каждого элемента массива.
|
||||
//! Она принимает два аргумента:
|
||||
//! * **e** - текущий элемент массива
|
||||
//! * **acc** - аккумулятор, аккумулирующий значение
|
||||
//! которое возвращает эта функция после посещения очередного элемента
|
||||
//!
|
||||
//! \param initial _опциональный_ Объект,
|
||||
//! используемый в качестве второго аргумента при первом вызове функции `f`.
|
||||
//!
|
||||
//! \~\code
|
||||
//! PIByteArray v{1, 2, 3, 4, 5};
|
||||
//! PIString s = v.reduce<PIString>([](const uchar & e, const PIString & acc){return acc + PIString::fromNumber(e);});
|
||||
//! piCout << s; // "12345"
|
||||
//! \endcode
|
||||
//! \~\sa \a forEach(), \a map()
|
||||
template <typename ST>
|
||||
inline ST reduce(std::function<ST(const uchar & e, const ST & acc)> f, const ST & initial = ST()) const {
|
||||
return d.reduce<ST>(f, initial);
|
||||
}
|
||||
|
||||
//! \~english Convert data to Base 64 and return this byte array
|
||||
//! \~russian Преобразует данные в Base 64 и возвращает текущий массив
|
||||
@@ -142,6 +1088,21 @@ public:
|
||||
//! \~russian Добавляет в конец массива байт "t"
|
||||
PIByteArray & append(uchar t) {push_back(t); return *this;}
|
||||
|
||||
//! \~english Appends the given elements to the end of the array.
|
||||
//! \~russian Добавляет элементы в конец массива.
|
||||
//! \~\details
|
||||
//! \~english Overloaded function.
|
||||
//! Appends the given elements from
|
||||
//! [C++11 initializer list](https://en.cppreference.com/w/cpp/utility/initializer_list).
|
||||
//! \~russian Перегруженая функция.
|
||||
//! Добавляет элементы из
|
||||
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
|
||||
//! \~\sa \a push_back()
|
||||
inline PIByteArray & append(std::initializer_list<uchar> init_list) {
|
||||
d.append(init_list);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \~english Returns 8-bit checksum
|
||||
//! \~russian Возвращает 8-битную контрольную сумму
|
||||
uchar checksumPlain8(bool inverse = true) const;
|
||||
@@ -150,11 +1111,23 @@ public:
|
||||
//! \~russian Возвращает 32-битную контрольную сумму
|
||||
uint checksumPlain32(bool inverse = true) const;
|
||||
|
||||
//! \~english Returns 8-bit checksum CRC-8
|
||||
//! \~russian Возвращает 8-битную контрольную сумму CRC-8
|
||||
uchar checksumCRC8() const;
|
||||
|
||||
//! \~english Returns 16-bit checksum CRC-16
|
||||
//! \~russian Возвращает 16-битную контрольную сумму CRC-16
|
||||
ushort checksumCRC16() const;
|
||||
|
||||
//! \~english Returns 32-bit checksum CRC-32
|
||||
//! \~russian Возвращает 32-битную контрольную сумму CRC-32
|
||||
uint checksumCRC32() const;
|
||||
|
||||
//! \~english Returns hash of content
|
||||
//! \~russian Возвращает хэш содержимого
|
||||
uint hash() const;
|
||||
|
||||
void operator =(const PIDeque<uchar> & d) {resize(d.size()); memcpy(data(), d.data(), d.size());}
|
||||
void operator =(const PIDeque<uchar> & o) {resize(o.size()); memcpy(data(), o.data(), o.size());}
|
||||
|
||||
PIByteArray & operator =(const PIByteArray & o) {if (this == &o) return *this; clear(); append(o); return *this;}
|
||||
|
||||
@@ -170,13 +1143,22 @@ public:
|
||||
static PIByteArray fromBase64(const PIString & base64);
|
||||
|
||||
|
||||
class StreamRef {
|
||||
public:
|
||||
StreamRef(PIByteArray & s): ba(s) {}
|
||||
operator PIByteArray&() {return ba;}
|
||||
private:
|
||||
PIByteArray & ba;
|
||||
};
|
||||
bool binaryStreamAppendImp(const void * d_, size_t s) {
|
||||
append(d_, s);
|
||||
return true;
|
||||
}
|
||||
bool binaryStreamTakeImp(void * d_, size_t s) {
|
||||
size_t rs = size();
|
||||
if (rs > s) rs = s;
|
||||
memcpy(d_, data(), rs);
|
||||
remove(0, rs);
|
||||
return rs == s;
|
||||
}
|
||||
|
||||
ssize_t binaryStreamSizeImp() const {return size();}
|
||||
|
||||
private:
|
||||
PIDeque<uchar> d;
|
||||
|
||||
};
|
||||
|
||||
@@ -235,443 +1217,21 @@ inline std::ostream & operator <<(std::ostream & s, const PIByteArray & ba);
|
||||
PIP_EXPORT PICout operator <<(PICout s, const PIByteArray & ba);
|
||||
|
||||
|
||||
|
||||
|
||||
// store operators for basic types
|
||||
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \~english Store operator
|
||||
//! \~russian Оператор сохранения
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const bool v) {s.push_back(v); return s;}
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \~english Store operator
|
||||
//! \~russian Оператор сохранения
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const char v) {s.push_back(v); return s;}
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \~english Store operator
|
||||
//! \~russian Оператор сохранения
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const uchar v) {s.push_back(v); return s;}
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \~english Store operator for any trivial copyable type
|
||||
//! \~russian Оператор сохранения для тривиальных типов
|
||||
template<typename T, typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0>
|
||||
inline PIByteArray::StreamRef operator <<(PIByteArray & s, const T & v) {
|
||||
int os = s.size_s();
|
||||
s.enlarge(sizeof(v));
|
||||
memcpy(s.data(os), &v, sizeof(v));
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Store operator.
|
||||
//! \~russian Оператор сохранения.
|
||||
BINARY_STREAM_WRITE(PIByteArray) {
|
||||
s.binaryStreamAppend((int)v.size_s());
|
||||
s.binaryStreamAppend(v.data(), v.size());
|
||||
return s;
|
||||
}
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \~english Store operator, see \ref PIByteArray_sec1 for details
|
||||
//! \~russian Оператор сохранения, подробнее в \ref PIByteArray_sec1
|
||||
PIP_EXPORT PIByteArray & operator <<(PIByteArray & s, const PIByteArray & v);
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \~english Store operator
|
||||
//! \~russian Оператор сохранения
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIByteArray::RawData & v) {
|
||||
int os = s.size_s();
|
||||
if (v.s > 0) {
|
||||
s.enlarge(v.s);
|
||||
memcpy(s.data(os), v.d, v.s);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \~english Store operator for PIVector of any trivial copyable type
|
||||
//! \~russian Оператор сохранения для PIVector тривиальных типов
|
||||
template<typename T,
|
||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
||||
typename std::enable_if< std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIVector<T> & v) {
|
||||
s << int(v.size_s());
|
||||
int os = s.size_s();
|
||||
if (v.size_s() > 0) {
|
||||
s.enlarge(v.size_s()*sizeof(T));
|
||||
memcpy(s.data(os), v.data(), v.size_s()*sizeof(T));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
template<typename T,
|
||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
||||
typename std::enable_if<!std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIVector<T> & v) {
|
||||
s << int(v.size_s());
|
||||
for (uint i = 0; i < v.size(); ++i) s << v[i];
|
||||
return s;
|
||||
}
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \~english Store operator for PIDeque of any trivial copyable type
|
||||
//! \~russian Оператор сохранения для PIDeque тривиальных типов
|
||||
template<typename T,
|
||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
||||
typename std::enable_if< std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIDeque<T> & v) {
|
||||
s << int(v.size_s());
|
||||
int os = s.size_s();
|
||||
if (v.size_s() > 0) {
|
||||
s.enlarge(v.size_s()*sizeof(T));
|
||||
memcpy(s.data(os), v.data(), v.size_s()*sizeof(T));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
template<typename T,
|
||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
||||
typename std::enable_if<!std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIDeque<T> & v) {
|
||||
s << int(v.size_s());
|
||||
for (uint i = 0; i < v.size(); ++i) s << v[i];
|
||||
return s;
|
||||
}
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \~english Store operator for PIVector2D of any trivial copyable type
|
||||
//! \~russian Оператор сохранения для PIVector2D тривиальных типов
|
||||
template<typename T,
|
||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
||||
typename std::enable_if< std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIVector2D<T> & v) {
|
||||
s << int(v.rows()) << int(v.cols());
|
||||
int os = s.size_s();
|
||||
if (v.size_s() > 0) {
|
||||
s.enlarge(v.size_s()*sizeof(T));
|
||||
memcpy(s.data(os), v.data(), v.size_s()*sizeof(T));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
template<typename T,
|
||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
||||
typename std::enable_if<!std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIVector2D<T> & v) {
|
||||
s << int(v.rows()) << int(v.cols()) << v.toPlainVector();
|
||||
return s;
|
||||
}
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \~english Store operator
|
||||
//! \~russian Оператор сохранения
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIBitArray & v) {s << v.size_ << v.data_; return s;}
|
||||
|
||||
//! \relatesalso PIPair
|
||||
//! \~english Store operator
|
||||
//! \~russian Оператор сохранения
|
||||
template<typename Type0, typename Type1>
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIPair<Type0, Type1> & v) {s << v.first << v.second; return s;}
|
||||
|
||||
|
||||
|
||||
|
||||
// restore operators for basic types
|
||||
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \~english Restore operator
|
||||
//! \~russian Оператор извлечения
|
||||
inline PIByteArray & operator >>(PIByteArray & s, bool & v) {assert(s.size() >= 1u); v = s.take_front(); return s;}
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \~english Restore operator
|
||||
//! \~russian Оператор извлечения
|
||||
inline PIByteArray & operator >>(PIByteArray & s, char & v) {assert(s.size() >= 1u); v = s.take_front(); return s;}
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \~english Restore operator
|
||||
//! \~russian Оператор извлечения
|
||||
inline PIByteArray & operator >>(PIByteArray & s, uchar & v) {assert(s.size() >= 1u); v = s.take_front(); return s;}
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \~english Restore operator for any trivial copyable type
|
||||
//! \~russian Оператор извлечения для тривиальных типов
|
||||
template<typename T, typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0>
|
||||
inline PIByteArray::StreamRef operator >>(PIByteArray & s, T & v) {
|
||||
if (s.size() < sizeof(v)) {
|
||||
printf("error with %s\n", __PIP_TYPENAME__(T));
|
||||
assert(s.size() >= sizeof(v));
|
||||
}
|
||||
memcpy((void*)(&v), s.data(), sizeof(v));
|
||||
s.remove(0, sizeof(v));
|
||||
return s;
|
||||
}
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \~english Restore operator, see \ref PIByteArray_sec1 for details
|
||||
//! \~russian Оператор извлечения, подробнее в \ref PIByteArray_sec1
|
||||
PIP_EXPORT PIByteArray & operator >>(PIByteArray & s, PIByteArray & v);
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \~english Restore operator
|
||||
//! \~russian Оператор извлечения
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIByteArray::RawData v) {
|
||||
if (s.size_s() < v.s) {
|
||||
printf("error with RawData %d < %d\n", (int)s.size_s(), v.s);
|
||||
assert(s.size_s() >= v.s);
|
||||
}
|
||||
if (v.s > 0) {
|
||||
memcpy((void*)(v.d), s.data(), v.s);
|
||||
s.remove(0, v.s);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \~english Restore operator for PIVector of any trivial copyable type
|
||||
//! \~russian Оператор извлечения для PIVector тривиальных типов
|
||||
template<typename T,
|
||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
||||
typename std::enable_if< std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIVector<T> & v) {
|
||||
if (s.size_s() < 4) {
|
||||
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||
assert(s.size_s() >= 4);
|
||||
}
|
||||
int sz; s >> sz;
|
||||
v._resizeRaw(sz);
|
||||
if (sz > 0) {
|
||||
memcpy(v.data(), s.data(), sz*sizeof(T));
|
||||
s.remove(0, sz*sizeof(T));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
template<typename T,
|
||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
||||
typename std::enable_if<!std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIVector<T> & v) {
|
||||
if (s.size_s() < 4) {
|
||||
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||
assert(s.size_s() >= 4);
|
||||
}
|
||||
int sz; s >> sz;
|
||||
v.resize(sz);
|
||||
for (int i = 0; i < sz; ++i) s >> v[i];
|
||||
return s;
|
||||
}
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \~english Restore operator for PIDeque of any trivial copyable type
|
||||
//! \~russian Оператор извлечения для PIDeque тривиальных типов
|
||||
template<typename T,
|
||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
||||
typename std::enable_if< std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIDeque<T> & v) {
|
||||
if (s.size_s() < 4) {
|
||||
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||
assert(s.size_s() >= 4);
|
||||
}
|
||||
int sz; s >> sz;
|
||||
v._resizeRaw(sz);
|
||||
if (sz > 0) {
|
||||
memcpy(v.data(), s.data(), sz*sizeof(T));
|
||||
s.remove(0, sz*sizeof(T));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
template<typename T,
|
||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
||||
typename std::enable_if<!std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIDeque<T> & v) {
|
||||
if (s.size_s() < 4) {
|
||||
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||
assert(s.size_s() >= 4);
|
||||
}
|
||||
int sz; s >> sz;
|
||||
v.resize(sz);
|
||||
for (int i = 0; i < sz; ++i) s >> v[i];
|
||||
return s;
|
||||
}
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \~english Restore operator for PIVector2D of any trivial copyable type
|
||||
//! \~russian Оператор извлечения для PIVector2D тривиальных типов
|
||||
template<typename T,
|
||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
||||
typename std::enable_if< std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIVector2D<T> & v) {
|
||||
if (s.size_s() < 8) {
|
||||
printf("error with PIVecto2Dr<%s>\n", __PIP_TYPENAME__(T));
|
||||
assert(s.size_s() >= 8);
|
||||
}
|
||||
int r, c; s >> r >> c;
|
||||
v._resizeRaw(r, c);
|
||||
int sz = r*c;
|
||||
if (sz > 0) {
|
||||
memcpy(v.data(), s.data(), sz*sizeof(T));
|
||||
s.remove(0, sz*sizeof(T));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
template<typename T,
|
||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
||||
typename std::enable_if<!std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIVector2D<T> & v) {
|
||||
if (s.size_s() < 8) {
|
||||
printf("error with PIVecto2Dr<%s>\n", __PIP_TYPENAME__(T));
|
||||
assert(s.size_s() >= 8);
|
||||
}
|
||||
int r,c;
|
||||
PIVector<T> tmp;
|
||||
s >> r >> c >> tmp;
|
||||
v = PIVector2D<T>(r, c, tmp);
|
||||
return s;
|
||||
}
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \~english Restore operator
|
||||
//! \~russian Оператор извлечения
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIBitArray & v) {assert(s.size_s() >= 8); s >> v.size_ >> v.data_; return s;}
|
||||
|
||||
//! \relatesalso PIPair
|
||||
//! \~english Restore operator
|
||||
//! \~russian Оператор извлечения
|
||||
template<typename Type0, typename Type1>
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIPair<Type0, Type1> & v) {s >> v.first >> v.second; return s;}
|
||||
|
||||
|
||||
|
||||
|
||||
// store operators for complex types
|
||||
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \~english Store operator for PIVector of any compound type
|
||||
//! \~russian Оператор сохранения для PIVector сложных типов
|
||||
template<typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIVector<T> & v) {
|
||||
s << int(v.size_s());
|
||||
for (uint i = 0; i < v.size(); ++i) s << v[i];
|
||||
return s;
|
||||
}
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \~english Store operator for PIDeque of any compound type
|
||||
//! \~russian Оператор сохранения для PIDeque сложных типов
|
||||
template<typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIDeque<T> & v) {
|
||||
s << int(v.size_s());
|
||||
for (uint i = 0; i < v.size(); ++i) s << v[i];
|
||||
return s;
|
||||
}
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \~english Store operator for PIVector2D of any compound type
|
||||
//! \~russian Оператор сохранения для PIVector2D сложных типов
|
||||
template<typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIVector2D<T> & v) {
|
||||
s << int(v.rows()) << int(v.cols()) << v.toPlainVector();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// restore operators for complex types
|
||||
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \~english Restore operator for PIVector of any compound type
|
||||
//! \~russian Оператор извлечения для PIVector сложных типов
|
||||
template<typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIVector<T> & v) {
|
||||
if (s.size_s() < 4) {
|
||||
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||
assert(s.size_s() >= 4);
|
||||
}
|
||||
int sz; s >> sz;
|
||||
v.resize(sz);
|
||||
for (int i = 0; i < sz; ++i) s >> v[i];
|
||||
return s;
|
||||
}
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \~english Restore operator for PIDeque of any compound type
|
||||
//! \~russian Оператор извлечения для PIDeque сложных типов
|
||||
template<typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIDeque<T> & v) {
|
||||
if (s.size_s() < 4) {
|
||||
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||
assert(s.size_s() >= 4);
|
||||
}
|
||||
int sz; s >> sz;
|
||||
v.resize(sz);
|
||||
for (int i = 0; i < sz; ++i) s >> v[i];
|
||||
return s;
|
||||
}
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \~english Restore operator for PIVector2D of any compound type
|
||||
//! \~russian Оператор извлечения для PIVector2D сложных типов
|
||||
template<typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIVector2D<T> & v) {
|
||||
if (s.size_s() < 8) {
|
||||
printf("error with PIVecto2Dr<%s>\n", __PIP_TYPENAME__(T));
|
||||
assert(s.size_s() >= 8);
|
||||
}
|
||||
int r,c;
|
||||
PIVector<T> tmp;
|
||||
s >> r >> c >> tmp;
|
||||
v = PIVector2D<T>(r, c, tmp);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// other types
|
||||
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \~english Store operator
|
||||
//! \~russian Оператор сохранения
|
||||
template <typename Key, typename T>
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIMap<Key, T> & v) {
|
||||
s << int(v.pim_index.size_s());
|
||||
for (uint i = 0; i < v.size(); ++i)
|
||||
s << int(v.pim_index[i].index) << v.pim_index[i].key;
|
||||
s << v.pim_content;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \~english Restore operator
|
||||
//! \~russian Оператор извлечения
|
||||
template <typename Key, typename T>
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIMap<Key, T> & v) {
|
||||
if (s.size_s() < 4) {
|
||||
printf("error with PIMap<%s, %s>\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
|
||||
assert(s.size_s() >= 4);
|
||||
}
|
||||
int sz; s >> sz; v.pim_index.resize(sz);
|
||||
int ind = 0;
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
s >> ind >> v.pim_index[i].key;
|
||||
v.pim_index[i].index = ind;
|
||||
}
|
||||
s >> v.pim_content;
|
||||
if (v.pim_content.size_s() != v.pim_index.size_s()) {
|
||||
piCout << "Warning: loaded invalid PIMap, clear";
|
||||
v.clear();
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const T & ) {
|
||||
static_assert(std::is_trivially_copyable<T>::value, "[PIByteArray] Error: using undeclared operator << for complex type!");
|
||||
return s;
|
||||
}
|
||||
|
||||
template<typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
||||
inline PIByteArray & operator >>(PIByteArray & s, T & ) {
|
||||
static_assert(std::is_trivially_copyable<T>::value, "[PIByteArray] Error: using undeclared operator >> for complex type!");
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Restore operator.
|
||||
//! \~russian Оператор извлечения.
|
||||
BINARY_STREAM_READ(PIByteArray) {
|
||||
v.resize(s.binaryStreamTakeInt());
|
||||
s.binaryStreamTake(v.data(), v.size());
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
@@ -359,7 +359,7 @@ PIChar PIChar::toLower() const {
|
||||
|
||||
PICout operator <<(PICout s, const PIChar & v) {
|
||||
s.space();
|
||||
s.setControl(0, true);
|
||||
s.saveAndSetControls(0);
|
||||
if (v.isAscii()) s << char(v.ch);
|
||||
else {
|
||||
#ifdef PIP_ICU
|
||||
@@ -380,6 +380,6 @@ PICout operator <<(PICout s, const PIChar & v) {
|
||||
s << PIString(v);
|
||||
#endif
|
||||
}
|
||||
s.restoreControl();
|
||||
s.restoreControls();
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ int PIChunkStream::read() {
|
||||
last_id = readVInt(*data_);
|
||||
last_data.resize(readVInt(*data_));
|
||||
//piCout << last_id << last_data.size();
|
||||
(*data_) >> PIByteArray::RawData(last_data.data(), last_data.size_s());
|
||||
(*data_) >> PIMemoryBlock(last_data.data(), last_data.size_s());
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
@@ -125,15 +125,14 @@ int PIChunkStream::read() {
|
||||
}
|
||||
|
||||
|
||||
int PIChunkStream::peekVInt(Version version_, PIByteArray * data_, int pos, PIByteArray & hdr, uint & ret) {
|
||||
int PIChunkStream::peekVInt(Version version_, uchar * data_, int sz, uint & ret) {
|
||||
switch (version_) {
|
||||
case Version_1:
|
||||
memcpy(&ret, data_->data(pos), 4);
|
||||
memcpy(&ret, data_, 4);
|
||||
return 4;
|
||||
case Version_2: {
|
||||
PIByteArray hdr(data_, piMini(4, sz));
|
||||
hdr.resize(4);
|
||||
hdr.fill(uchar(0));
|
||||
memcpy(hdr.data(), data_->data(pos), piMini(4, data_->size_s() - pos));
|
||||
uchar hsz = 0;
|
||||
ret = readVInt(hdr, &hsz);
|
||||
return hsz;
|
||||
@@ -153,13 +152,16 @@ void PIChunkStream::replaceChunk(int id, const PIByteArray & v) {
|
||||
pos.length = v.size_s();
|
||||
if (size_mod != 0) {
|
||||
auto it = data_map.makeIterator();
|
||||
while (it.next())
|
||||
if (it.valueRef().start > pos.start)
|
||||
it.valueRef().start += size_mod;
|
||||
if (size_mod > 0)
|
||||
while (it.next()) {
|
||||
if (it.value().start > pos.start) {
|
||||
it.value().start += size_mod;
|
||||
}
|
||||
}
|
||||
if (size_mod > 0) {
|
||||
data_->insert(pos.start, PIByteArray(size_mod));
|
||||
else
|
||||
} else {
|
||||
data_->remove(pos.start, -size_mod);
|
||||
}
|
||||
}
|
||||
memcpy(data_->data(pos.start - pos.size_bytes), nsba.data(), nsba.size());
|
||||
pos.start += nsba.size_s() - pos.size_bytes;
|
||||
@@ -172,10 +174,9 @@ void PIChunkStream::readAll() {
|
||||
if (!data_) return;
|
||||
int pos = 0, sz = data_->size_s(), hsz = 0;
|
||||
uint csz = 0, cid = 0;
|
||||
PIByteArray hdr;
|
||||
while (pos < sz) {
|
||||
pos += peekVInt((Version)version_, data_, pos, hdr, cid);
|
||||
hsz = peekVInt((Version)version_, data_, pos, hdr, csz);
|
||||
pos += peekVInt((Version)version_, data_->data(pos), data_->size_s() - pos, cid);
|
||||
hsz = peekVInt((Version)version_, data_->data(pos), data_->size_s() - pos, csz);
|
||||
pos += hsz;
|
||||
data_map[cid] = CacheEntry(pos, csz, hsz);
|
||||
pos += csz;
|
||||
@@ -193,8 +194,7 @@ bool PIChunkStream::extract(PIByteArray & data, bool read_all) {
|
||||
if (tmp_data.size_s() < 4) return false;
|
||||
data_ = &tmp_data;
|
||||
_init();
|
||||
if (read_all)
|
||||
readAll();
|
||||
if (read_all) readAll();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -208,19 +208,27 @@ void PIChunkStream::_init() {
|
||||
if ((v & 0x80) == 0x80) {
|
||||
v &= 0x7f;
|
||||
switch (v) {
|
||||
case 2: version_ = (uchar)Version_2; data_->pop_front(); first_byte_taken = true; break;
|
||||
default: version_ = Version_1; break;
|
||||
case 2:
|
||||
version_ = (uchar)Version_2;
|
||||
data_->pop_front();
|
||||
first_byte_taken = true;
|
||||
break;
|
||||
default:
|
||||
version_ = Version_1;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
version_ = Version_1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint PIChunkStream::readVInt(PIByteArray & s, uchar * bytes_cnt) {
|
||||
if (s.isEmpty()) return 0;
|
||||
uchar bytes[4]; s >> bytes[0];
|
||||
uchar abc = 0;
|
||||
uchar bytes[4];
|
||||
uchar abc;
|
||||
s >> bytes[0];
|
||||
for (abc = 0; abc < 3; ++abc) {
|
||||
uchar mask = (0x80 >> abc);
|
||||
if ((bytes[0] & mask) == mask) {
|
||||
|
||||
@@ -124,7 +124,7 @@ public:
|
||||
//! \~english Returns value of last readed chunk
|
||||
//! \~russian Возвращает значение последнего прочитанного чанка
|
||||
template <typename T>
|
||||
T getData() const {T ret; PIByteArray s(last_data); s >> ret; return ret;}
|
||||
T getData() const {T ret{}; PIByteArray s(last_data); s >> ret; return ret;}
|
||||
|
||||
//! \~english Place value of last readed chunk into \"v\"
|
||||
//! \~russian Записывает значение последнего прочитанного чанка в \"v\"
|
||||
@@ -165,7 +165,7 @@ private:
|
||||
|
||||
static uint readVInt(PIByteArray & s, uchar * bytes = 0);
|
||||
static void writeVInt(PIByteArray & s, uint val);
|
||||
static int peekVInt(Version version_, PIByteArray * data_, int pos, PIByteArray & hdr, uint & ret);
|
||||
static int peekVInt(Version version_, uchar * data_, int sz, uint & ret);
|
||||
void replaceChunk(int id, const PIByteArray & v);
|
||||
|
||||
int last_id;
|
||||
|
||||
@@ -42,6 +42,13 @@
|
||||
//!
|
||||
|
||||
|
||||
bool PIConstChars::contains(char c) const {
|
||||
for (int i = 0; i < (int)len; ++i)
|
||||
if (str[i] == c) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool PIConstChars::startsWith(const PIConstChars & str) const {
|
||||
if (size() < str.size()) return false;
|
||||
return str == left(str.size());
|
||||
|
||||
@@ -86,6 +86,10 @@ public:
|
||||
//! \~russian Возвращает \c true если строка непустая, т.е. длина > 0.
|
||||
inline bool isNotEmpty() const {return len > 0;}
|
||||
|
||||
//! \~english Returns \c true if string contains character "c".
|
||||
//! \~russian Возвращает \c true если строка содержит символ "c".
|
||||
bool contains(char c) const;
|
||||
|
||||
//! \~english Returns characters length of string.
|
||||
//! \~russian Возвращает длину строки в символах.
|
||||
inline size_t length() const {return len;}
|
||||
|
||||
@@ -108,7 +108,7 @@ class NotifierObject: public PIObject {
|
||||
PIOBJECT(NotifierObject)
|
||||
public:
|
||||
NotifierObject() {}
|
||||
EVENT2(finished, int, id, PIString*, buffer)
|
||||
EVENT2(finished, int, id, PIString*, buffer);
|
||||
};
|
||||
|
||||
|
||||
@@ -267,8 +267,8 @@ PICout PICout::operator <<(const PICoutAction v) {
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case PICoutManipulators::SaveContol: saveControl(); break;
|
||||
case PICoutManipulators::RestoreControl: restoreControl(); break;
|
||||
case PICoutManipulators::SaveContol: saveControls(); break;
|
||||
case PICoutManipulators::RestoreControl: restoreControls(); break;
|
||||
default: break;
|
||||
};
|
||||
return *this;
|
||||
@@ -317,66 +317,67 @@ PICout PICout::operator <<(const PIFlags<PICoutManipulators::PICoutFormat> & v)
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
#define PICOUTTOTARGET(v) { \
|
||||
if (buffer_) {\
|
||||
(*buffer_) << (v);\
|
||||
} else {\
|
||||
if (PICout::isOutputDeviceActive(PICout::StdOut)) std::cout << (v);\
|
||||
if (PICout::isOutputDeviceActive(PICout::Buffer)) PICout::__string__() << (v);\
|
||||
}\
|
||||
}
|
||||
|
||||
#define PINUMERICCOUT(v) { \
|
||||
#define PIINTCOUT(v) { \
|
||||
if (!act_) return *this; \
|
||||
space(); \
|
||||
if (cnb_ == 10) PICOUTTOTARGET(v) \
|
||||
else write(PIString::fromNumber(v, cnb_)); \
|
||||
if (cnb_ == 10) {\
|
||||
if (buffer_) {\
|
||||
(*buffer_) += PIString::fromNumber(v);\
|
||||
} else {\
|
||||
if (PICout::isOutputDeviceActive(PICout::StdOut)) std::cout << (v);\
|
||||
if (PICout::isOutputDeviceActive(PICout::Buffer)) PICout::__string__() += PIString::fromNumber(v);\
|
||||
}\
|
||||
} else write(PIString::fromNumber(v, cnb_)); \
|
||||
return *this; \
|
||||
}
|
||||
|
||||
#define PIFLOATCOUT(v) { \
|
||||
if (buffer_) {\
|
||||
(*buffer_) += PIString::fromNumber(v, 'g');\
|
||||
} else {\
|
||||
if (PICout::isOutputDeviceActive(PICout::StdOut)) std::cout << (v);\
|
||||
if (PICout::isOutputDeviceActive(PICout::Buffer)) PICout::__string__() += PIString::fromNumber(v, 'g');\
|
||||
}\
|
||||
}
|
||||
|
||||
PICout PICout::operator <<(const char * v) {if (!act_ || !v) return *this; if (v[0] == '\0') return *this; space(); quote(); PICOUTTOTARGET(v) quote(); return *this;}
|
||||
|
||||
PICout PICout::operator <<(const bool v) {if (!act_) return *this; space(); if (v) PICOUTTOTARGET("true") else PICOUTTOTARGET("false") return *this;}
|
||||
PICout PICout::operator <<(const char * v) {if (!act_ || !v) return *this; if (v[0] == '\0') return *this; space(); quote(); write(v); quote(); return *this;}
|
||||
|
||||
PICout PICout::operator <<(const char v) {if (!act_) return *this; space(); PICOUTTOTARGET(v) return *this;}
|
||||
PICout PICout::operator <<(const bool v) {if (!act_) return *this; space(); if (v) write("true"); else write("false"); return *this;}
|
||||
|
||||
PICout PICout::operator <<(const uchar v) {PINUMERICCOUT(ushort(v))}
|
||||
PICout PICout::operator <<(const char v) {if (!act_) return *this; space(); write(v); return *this;}
|
||||
|
||||
PICout PICout::operator <<(const short int v) {PINUMERICCOUT(v)}
|
||||
PICout PICout::operator <<(const uchar v) {PIINTCOUT(ushort(v))}
|
||||
|
||||
PICout PICout::operator <<(const ushort v) {PINUMERICCOUT(v)}
|
||||
PICout PICout::operator <<(const short int v) {PIINTCOUT(v)}
|
||||
|
||||
PICout PICout::operator <<(const int v) {PINUMERICCOUT(v)}
|
||||
PICout PICout::operator <<(const ushort v) {PIINTCOUT(v)}
|
||||
|
||||
PICout PICout::operator <<(const uint v) {PINUMERICCOUT(v)}
|
||||
PICout PICout::operator <<(const int v) {PIINTCOUT(v)}
|
||||
|
||||
PICout PICout::operator <<(const long v) {PINUMERICCOUT(v)}
|
||||
PICout PICout::operator <<(const uint v) {PIINTCOUT(v)}
|
||||
|
||||
PICout PICout::operator <<(const ulong v) {PINUMERICCOUT(v)}
|
||||
PICout PICout::operator <<(const long v) {PIINTCOUT(v)}
|
||||
|
||||
PICout PICout::operator <<(const llong v) {PINUMERICCOUT(v)}
|
||||
PICout PICout::operator <<(const ulong v) {PIINTCOUT(v)}
|
||||
|
||||
PICout PICout::operator <<(const ullong v) {PINUMERICCOUT(v)}
|
||||
PICout PICout::operator <<(const llong v) {PIINTCOUT(v)}
|
||||
|
||||
PICout PICout::operator <<(const float v) {if (!act_) return *this; space(); PICOUTTOTARGET(v) return *this;}
|
||||
PICout PICout::operator <<(const ullong v) {PIINTCOUT(v)}
|
||||
|
||||
PICout PICout::operator <<(const double v) {if (!act_) return *this; space(); PICOUTTOTARGET(v) return *this;}
|
||||
PICout PICout::operator <<(const float v) {if (!act_) return *this; space(); PIFLOATCOUT(v) return *this;}
|
||||
|
||||
PICout PICout::operator <<(const void * v) {if (!act_) return *this; space(); PICOUTTOTARGET("0x") write(PIString::fromNumber(ullong(v), 16)); return *this;}
|
||||
PICout PICout::operator <<(const double v) {if (!act_) return *this; space(); PIFLOATCOUT(v) return *this;}
|
||||
|
||||
PICout PICout::operator <<(const void * v) {if (!act_) return *this; space(); write("0x" + PIString::fromNumber(ullong(v), 16)); return *this;}
|
||||
|
||||
PICout PICout::operator <<(const PIObject * v) {
|
||||
if (!act_) return *this;
|
||||
space();
|
||||
if (v == 0) PICOUTTOTARGET("PIObject*(0x0)")
|
||||
if (v == 0) write("PIObject*(0x0)");
|
||||
else {
|
||||
PICOUTTOTARGET(v->className())
|
||||
PICOUTTOTARGET("*(0x")
|
||||
write(PIString::fromNumber(ullong(v), 16));
|
||||
PICOUTTOTARGET(", \"")
|
||||
write(v->name());
|
||||
PICOUTTOTARGET("\")")
|
||||
write(v->className());
|
||||
write("*(0x" + PIString::fromNumber(ullong(v), 16) + ", \"" + v->name() + "\")");
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@@ -386,52 +387,52 @@ PICout PICout::operator <<(const PICoutSpecialChar v) {
|
||||
switch (v) {
|
||||
case Null:
|
||||
if (buffer_) {
|
||||
(*buffer_) << PIChar();
|
||||
(*buffer_) += PIChar();
|
||||
} else {
|
||||
if (isOutputDeviceActive(StdOut)) std::cout << char(0);
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() << PIChar();
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += PIChar();
|
||||
}
|
||||
break;
|
||||
case NewLine:
|
||||
if (buffer_) {
|
||||
(*buffer_) << "\n";
|
||||
(*buffer_) += "\n";
|
||||
} else {
|
||||
if (isOutputDeviceActive(StdOut)) std::cout << '\n';
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() << "\n";
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += "\n";
|
||||
}
|
||||
fo_ = true;
|
||||
break;
|
||||
case Tab:
|
||||
if (buffer_) {
|
||||
(*buffer_) << "\t";
|
||||
(*buffer_) += "\t";
|
||||
} else {
|
||||
if (isOutputDeviceActive(StdOut)) std::cout << '\t';
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() << "\t";
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += "\t";
|
||||
}
|
||||
break;
|
||||
case Esc:
|
||||
#ifdef CC_VC
|
||||
if (buffer_) {
|
||||
(*buffer_) << PIChar(27);
|
||||
(*buffer_) += PIChar(27);
|
||||
} else {
|
||||
if (isOutputDeviceActive(StdOut)) std::cout << char(27);
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() << PIChar(27);
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += PIChar(27);
|
||||
}
|
||||
#else
|
||||
if (buffer_) {
|
||||
(*buffer_) << "\e";
|
||||
(*buffer_) += "\e";
|
||||
} else {
|
||||
if (isOutputDeviceActive(StdOut)) std::cout << '\e';
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() << "\e";
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += "\e";
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case Quote:
|
||||
if (buffer_) {
|
||||
(*buffer_) << "\"";
|
||||
(*buffer_) += "\"";
|
||||
} else {
|
||||
if (isOutputDeviceActive(StdOut)) std::cout << '"';
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() << "\"";
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += "\"";
|
||||
}
|
||||
break;
|
||||
};
|
||||
@@ -439,14 +440,14 @@ PICout PICout::operator <<(const PICoutSpecialChar v) {
|
||||
}
|
||||
|
||||
|
||||
PICout & PICout::saveControl() {
|
||||
PICout & PICout::saveControls() {
|
||||
if (!act_) return *this;
|
||||
PRIVATE->cos_.push(co_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PICout & PICout::restoreControl() {
|
||||
PICout & PICout::restoreControls() {
|
||||
if (!act_) return *this;
|
||||
if (!PRIVATE->cos_.isEmpty()) {
|
||||
co_ = PRIVATE->cos_.top();
|
||||
@@ -456,8 +457,6 @@ PICout & PICout::restoreControl() {
|
||||
}
|
||||
|
||||
|
||||
#undef PICOUTTOTARGET
|
||||
#undef PINUMERICCOUT
|
||||
|
||||
//! \details
|
||||
//! \~english
|
||||
@@ -469,10 +468,10 @@ PICout & PICout::space() {
|
||||
if (!act_) return *this;
|
||||
if (!fo_ && co_[AddSpaces]) {
|
||||
if (buffer_) {
|
||||
(*buffer_) << " ";
|
||||
(*buffer_) += " ";
|
||||
} else {
|
||||
if (isOutputDeviceActive(StdOut)) std::cout << ' ';
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() << " ";
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += " ";
|
||||
}
|
||||
}
|
||||
fo_ = false;
|
||||
@@ -489,10 +488,10 @@ PICout & PICout::quote() {
|
||||
if (!act_) return *this;
|
||||
if (co_[AddQuotes]) {
|
||||
if (buffer_) {
|
||||
(*buffer_) << "\"";
|
||||
(*buffer_) += "\"";
|
||||
} else {
|
||||
if (isOutputDeviceActive(StdOut)) std::cout << '"';
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() << "\"";
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += "\"";
|
||||
}
|
||||
}
|
||||
fo_ = false;
|
||||
@@ -509,10 +508,10 @@ PICout & PICout::newLine() {
|
||||
if (!act_) return *this;
|
||||
if (co_[AddNewLine]) {
|
||||
if (buffer_) {
|
||||
(*buffer_) << "\n";
|
||||
(*buffer_) += "\n";
|
||||
} else {
|
||||
if (isOutputDeviceActive(StdOut)) std::cout << std::endl;
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() << "\n";
|
||||
if (isOutputDeviceActive(Buffer)) PICout::__string__() += "\n";
|
||||
}
|
||||
}
|
||||
fo_ = false;
|
||||
@@ -520,6 +519,18 @@ PICout & PICout::newLine() {
|
||||
}
|
||||
|
||||
|
||||
PICout & PICout::write(char c) {
|
||||
if (!act_) return *this;
|
||||
if (buffer_) {
|
||||
buffer_->append(c);
|
||||
} else {
|
||||
if (PICout::isOutputDeviceActive(PICout::StdOut)) std::cout << c;
|
||||
if (PICout::isOutputDeviceActive(PICout::Buffer)) PICout::__string__().append(c);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
PICout & PICout::write(const char * str) {
|
||||
if (!act_ || !str) return *this;
|
||||
return write(str, strlen(str));
|
||||
@@ -543,8 +554,7 @@ PICout & PICout::write(const PIString & s) {
|
||||
if (buffer_) {
|
||||
buffer_->append(s);
|
||||
} else {
|
||||
if (PICout::isOutputDeviceActive(PICout::StdOut))
|
||||
stdoutPIString(s);
|
||||
if (PICout::isOutputDeviceActive(PICout::StdOut)) stdoutPIString(s);
|
||||
if (PICout::isOutputDeviceActive(PICout::Buffer)) PICout::__string__().append(s);
|
||||
}
|
||||
return *this;
|
||||
@@ -640,24 +650,17 @@ void PICout::applyFormat(PICoutFormat f) {
|
||||
}
|
||||
|
||||
|
||||
bool PICout::setBufferActive(bool on, bool clear) {
|
||||
PIString PICout::getBuffer() {
|
||||
PIMutexLocker ml(PICout::__mutex__());
|
||||
bool ret = isBufferActive();
|
||||
if (clear) PICout::__string__().clear();
|
||||
setOutputDevice(Buffer, on);
|
||||
PIString ret = PICout::__string__();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool PICout::isBufferActive() {
|
||||
return isOutputDeviceActive(Buffer);
|
||||
}
|
||||
|
||||
|
||||
PIString PICout::buffer(bool clear) {
|
||||
PIString PICout::getBufferAndClear() {
|
||||
PIMutexLocker ml(PICout::__mutex__());
|
||||
PIString ret = PICout::__string__();
|
||||
if (clear) PICout::__string__().clear();
|
||||
PICout::__string__().clear();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -261,19 +261,23 @@ public:
|
||||
//! \~russian Установить флаг "c" в "on" состояние
|
||||
PICout & setControl(PICoutManipulators::PICoutControl c, bool on = true) {co_.setFlag(c, on); return *this;}
|
||||
|
||||
//! \~english Set control flags "c" and if "save" exec \a saveControl()
|
||||
//! \~russian Установить флаг "c" и если "save" то выполнить \a saveControl()
|
||||
PICout & setControl(PICoutManipulators::PICoutControls c, bool save = false) {if (save) saveControl(); co_ = c; return *this;}
|
||||
//! \~english Set control flags "c"
|
||||
//! \~russian Установить флаги "c"
|
||||
PICout & setControls(PICoutManipulators::PICoutControls c) {co_ = c; return *this;}
|
||||
|
||||
//! \~english Exec \a saveControls() and set control flags to "c"
|
||||
//! \~russian Иыполнить \a saveControls() и Установить флаги "c"
|
||||
PICout & saveAndSetControls(PICoutManipulators::PICoutControls c) {saveControls(); co_ = c; return *this;}
|
||||
|
||||
//! \~english Save control flags to internal stack
|
||||
//! \~russian Сохраняет состояние флагов во внутренний стек
|
||||
//! \~\sa \a restoreControl()
|
||||
PICout & saveControl();
|
||||
PICout & saveControls();
|
||||
|
||||
//! \~english Restore control flags from internal stack
|
||||
//! \~russian Восстанавливает состояние флагов из внутреннего стека
|
||||
//! \~\sa \a saveControl()
|
||||
PICout & restoreControl();
|
||||
PICout & restoreControls();
|
||||
|
||||
//! \~english Conditional put space character to output
|
||||
//! \~russian Условно добавляет пробел
|
||||
@@ -287,6 +291,10 @@ public:
|
||||
//! \~russian Условно добавляет новую строку
|
||||
PICout & newLine();
|
||||
|
||||
//! \~english Write char
|
||||
//! \~russian Пишет символ
|
||||
PICout & write(char c);
|
||||
|
||||
//! \~english Write raw data
|
||||
//! \~russian Пишет сырые символы
|
||||
PICout & write(const char * str);
|
||||
@@ -303,17 +311,13 @@ public:
|
||||
//! \~russian Вывод \a PIString в stdout
|
||||
static void stdoutPIString(const PIString & s);
|
||||
|
||||
//! \~english Set output device to \a PICout::Buffer and if "clear" clear it
|
||||
//! \~russian Устанавливает устройство вывода на \a PICout::Buffer и если "clear" то очищает его
|
||||
static bool setBufferActive(bool on, bool clear = false);
|
||||
//! \~english Returns internal PIString buffer
|
||||
//! \~russian Возвращает внутренний PIString буфер
|
||||
static PIString getBuffer();
|
||||
|
||||
//! \~english Equivalent to \a isOutputDeviceActive(OutputDevice)
|
||||
//! \~russian Аналог \a isOutputDeviceActive(OutputDevice)
|
||||
static bool isBufferActive();
|
||||
|
||||
//! \~english Returns internal PIString buffer and if "clear" clear it
|
||||
//! \~russian Возвращает внутренний PIString буфер и если "clear" то очищает его
|
||||
static PIString buffer(bool clear = false);
|
||||
//! \~english Returns internal PIString buffer and clear it
|
||||
//! \~russian Возвращает внутренний PIString буфер и очищает его
|
||||
static PIString getBufferAndClear();
|
||||
|
||||
//! \~english Clear internal PIString buffer
|
||||
//! \~russian Очищает внутренний PIString буфер
|
||||
@@ -324,10 +328,22 @@ public:
|
||||
//! \~russian Устройство вывода "d" устанавливается в "on". Возвращает было ли устройство активно
|
||||
static bool setOutputDevice(OutputDevice d, bool on = true);
|
||||
|
||||
//! \~english Turn on output device "d". Returns if it was enabled
|
||||
//! \~russian Включает устройство вывода "d". Возвращает было ли устройство активно
|
||||
static bool enableOutputDevice(OutputDevice d) {return setOutputDevice(d, true);}
|
||||
|
||||
//! \~english Turn off output device "d". Returns if it was enabled
|
||||
//! \~russian Выключает устройство вывода "d". Возвращает было ли устройство активно
|
||||
static bool disableOutputDevice(OutputDevice d) {return setOutputDevice(d, false);}
|
||||
|
||||
//! \~english Set output to devices to "d"
|
||||
//! \~russian Устанавливает устройства вывода "d"
|
||||
static void setOutputDevices(OutputDevices d);
|
||||
|
||||
//! \~english Returns current output devices
|
||||
//! \~russian Возвращает текущие устройства вывода
|
||||
static OutputDevices currentOutputDevices() {return devs;}
|
||||
|
||||
//! \~english Returns if output device "d" is active
|
||||
//! \~russian Возвращает активно ли устройство вывода "d"
|
||||
static bool isOutputDeviceActive(OutputDevice d);
|
||||
|
||||
@@ -312,30 +312,30 @@ PIString datetime2string(const PIDateTime & date, const PIString & format) {
|
||||
|
||||
PICout operator <<(PICout s, const PITime & v) {
|
||||
s.space();
|
||||
s.setControl(0, true);
|
||||
s.saveAndSetControls(0);
|
||||
s << "PITime(" << v.hours << ":";
|
||||
s << PIString::fromNumber(v.minutes).expandLeftTo(2, '0') << ":";
|
||||
s << PIString::fromNumber(v.seconds).expandLeftTo(2, '0') << ":";
|
||||
s << PIString::fromNumber(v.milliseconds).expandLeftTo(3, '0') << ")";
|
||||
s.restoreControl();
|
||||
s.restoreControls();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
PICout operator <<(PICout s, const PIDate & v) {
|
||||
s.space();
|
||||
s.setControl(0, true);
|
||||
s.saveAndSetControls(0);
|
||||
s << "PIDate(" << v.day << "-";
|
||||
s << PIString::fromNumber(v.month).expandLeftTo(2, '0') << "-";
|
||||
s << v.year << ")";
|
||||
s.restoreControl();
|
||||
s.restoreControls();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
PICout operator <<(PICout s, const PIDateTime & v) {
|
||||
s.space();
|
||||
s.setControl(0, true);
|
||||
s.saveAndSetControls(0);
|
||||
s << "PIDateTime(";
|
||||
s << v.day << "-";
|
||||
s << PIString::fromNumber(v.month).expandLeftTo(2, '0') << "-";
|
||||
@@ -344,7 +344,7 @@ PICout operator <<(PICout s, const PIDateTime & v) {
|
||||
s << PIString::fromNumber(v.minutes).expandLeftTo(2, '0') << ":";
|
||||
s << PIString::fromNumber(v.seconds).expandLeftTo(2, '0') << ":";
|
||||
s << PIString::fromNumber(v.milliseconds).expandLeftTo(3, '0') << ")";
|
||||
s.restoreControl();
|
||||
s.restoreControls();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
@@ -311,16 +311,6 @@ inline bool operator <=(const PIDateTime & t0, const PIDateTime & t1) {return !(
|
||||
//! \~russian Оператор сравнения
|
||||
inline bool operator >=(const PIDateTime & t0, const PIDateTime & t1) {return !(t0 < t1);}
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \~english Store operator
|
||||
//! \~russian Оператор сохранения
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIDateTime & v) {s << v.year << v.month << v.day << v.hours << v.minutes << v.seconds << v.milliseconds; return s;}
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \~english Restore operator
|
||||
//! \~russian Оператор извлечения
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIDateTime & v) {s >> v.year >> v.month >> v.day >> v.hours >> v.minutes >> v.seconds >> v.milliseconds; return s;}
|
||||
|
||||
//! \relatesalso PICout
|
||||
//! \~english \brief Output operator to PICout
|
||||
//! \~russian \brief Оператор вывода в PICout
|
||||
|
||||
@@ -38,6 +38,7 @@ class PIMutexLocker;
|
||||
class PIObject;
|
||||
class PIString;
|
||||
class PIByteArray;
|
||||
template <typename P> class PIBinaryStream;
|
||||
#ifndef MICRO_PIP
|
||||
class PIInit;
|
||||
#endif
|
||||
|
||||
73
libs/main/core/pimemoryblock.h
Normal file
73
libs/main/core/pimemoryblock.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/*! \file pimemoryblock.h
|
||||
* \ingroup Core
|
||||
* \~\brief
|
||||
* \~english Base types and functions
|
||||
* \~russian Базовые типы и методы
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Base types and functions
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIMEMORYBLOCK_H
|
||||
#define PIMEMORYBLOCK_H
|
||||
|
||||
|
||||
//! \ingroup Core
|
||||
//! \include pimemoryblock.h
|
||||
//! \brief
|
||||
//! \~english Help struct to store/restore custom blocks of data to/from PIBinaryStream
|
||||
//! \~russian Вспомогательная структура для сохранения/извлечения произвольного блока данных в/из PIBinaryStream
|
||||
struct PIMemoryBlock {
|
||||
public:
|
||||
|
||||
//! \~english Constructs data block
|
||||
//! \~russian Создает блок данных
|
||||
PIMemoryBlock(void * data_ = 0, int size_ = 0) {d = data_; s = size_;}
|
||||
|
||||
//! \~english Constructs data block
|
||||
//! \~russian Создает блок данных
|
||||
PIMemoryBlock(const void * data_, const int size_) {d = const_cast<void * >(data_); s = size_;}
|
||||
|
||||
PIMemoryBlock(const PIMemoryBlock & o) {d = o.d; s = o.s;}
|
||||
|
||||
PIMemoryBlock & operator =(const PIMemoryBlock & o) {d = o.d; s = o.s; return *this;}
|
||||
|
||||
//! \~english Pointer to data
|
||||
//! \~russian Указатель на данные
|
||||
void * data() {return d;}
|
||||
|
||||
//! \~english Pointer to data
|
||||
//! \~russian Указатель на данные
|
||||
const void * data() const {return d;}
|
||||
|
||||
//! \~english Size of data in bytes
|
||||
//! \~russian Размер данных в байтах
|
||||
int size() const {return s;}
|
||||
|
||||
private:
|
||||
void * d;
|
||||
int s;
|
||||
|
||||
};
|
||||
|
||||
//! \~english Returns PIMemoryBlock from pointer to variable "ptr" with type "T"
|
||||
//! \~russian Возвращает PIMemoryBlock из указателя "ptr" типа "T"
|
||||
template<typename T>
|
||||
PIMemoryBlock createMemoryBlock(const T * ptr) {return PIMemoryBlock(ptr, sizeof(T));}
|
||||
|
||||
#endif // PIMEMORYBLOCK_H
|
||||
@@ -23,6 +23,7 @@
|
||||
#ifndef MICRO_PIP
|
||||
# include "pisysteminfo.h"
|
||||
# include "pifile.h"
|
||||
# include "piiostream.h"
|
||||
#endif
|
||||
|
||||
|
||||
@@ -750,12 +751,14 @@ bool dumpApplicationToFile(const PIString & path, bool with_objects) {
|
||||
f.setName("__S__DumpFile");
|
||||
f.clear();
|
||||
if (!f.open(PIIODevice::WriteOnly)) return false;
|
||||
bool ba = PICout::isBufferActive();
|
||||
PICout::setBufferActive(true, true);
|
||||
auto out_devs = PICout::currentOutputDevices();
|
||||
PICout::setOutputDevices(PICout::Buffer);
|
||||
PICout::clearBuffer();
|
||||
dumpApplication(with_objects);
|
||||
f << PICout::buffer();
|
||||
PIIOTextStream ts(&f);
|
||||
ts << PICout::getBuffer();
|
||||
f.close();
|
||||
PICout::setBufferActive(ba, true);
|
||||
PICout::setOutputDevices(out_devs);
|
||||
PIFile::rename(path + "_tmp", path);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -34,8 +34,6 @@
|
||||
#include "piqueue.h"
|
||||
#include "piobject_macros.h"
|
||||
|
||||
typedef void (*Handler)(void * );
|
||||
|
||||
//! \ingroup Core
|
||||
//! \~\brief
|
||||
//! \~english This is base class for any classes which use events -> handlers mechanism.
|
||||
@@ -49,7 +47,7 @@ class PIP_EXPORT PIObject {
|
||||
typedef PIObject __PIObject__;
|
||||
typedef void __Parent__;
|
||||
public:
|
||||
NO_COPY_CLASS(PIObject)
|
||||
NO_COPY_CLASS(PIObject);
|
||||
|
||||
//! \~english Contructs %PIObject with name "name"
|
||||
//! \~russian Создает %PIObject с именем "name"
|
||||
@@ -518,7 +516,7 @@ protected:
|
||||
//! \~russian Виртуальная функция, вызывается после изменения любого свойства.
|
||||
virtual void propertyChanged(const char * name) {}
|
||||
|
||||
EVENT1(deleted, PIObject *, o)
|
||||
EVENT1(deleted, PIObject *, o);
|
||||
|
||||
//! \events
|
||||
//! \{
|
||||
|
||||
@@ -390,32 +390,32 @@
|
||||
|
||||
#define PIOBJECT(name) \
|
||||
protected: \
|
||||
typedef name __PIObject__; \
|
||||
typedef name __PIObject__; \
|
||||
public: \
|
||||
static const char * __classNameCC() {return #name;} \
|
||||
static uint __classNameIDS() {static uint ret = PIStringAscii(#name).hash(); return ret;} \
|
||||
virtual const char * className() const {return #name;} \
|
||||
virtual uint classNameID() const {static uint ret = PIStringAscii(#name).hash(); return ret;} \
|
||||
static const char * __classNameCC() {return #name;} \
|
||||
static uint __classNameIDS() {static uint ret = PIStringAscii(#name).hash(); return ret;} \
|
||||
const char * className() const override {return #name;} \
|
||||
uint classNameID() const override {static uint ret = PIStringAscii(#name).hash(); return ret;} \
|
||||
private: \
|
||||
virtual int ptrOffset() const {name * o = (name*)100; return int(llong((PIObject*)o) - llong(o));} \
|
||||
class __BaseInitializer__ { \
|
||||
public: \
|
||||
__BaseInitializer__() { \
|
||||
uint pid = PIObject::__classNameIDS(); \
|
||||
if (pid == 0) return; \
|
||||
uint id = __classNameIDS(); \
|
||||
PIMutexLocker ml(__meta_mutex()); \
|
||||
if (__meta_data().contains(id)) return; \
|
||||
__meta_data()[pid]; \
|
||||
__meta_data()[id]; \
|
||||
__MetaData & ehp(__meta_data()[pid]); \
|
||||
__MetaData & eh(__meta_data()[id]); \
|
||||
eh.eh_set << ehp.eh_set; \
|
||||
eh.eh_func << ehp.eh_func; \
|
||||
eh.addScope(__classNameCC(), id); \
|
||||
} \
|
||||
}; \
|
||||
__BaseInitializer__ __base_init__;
|
||||
int ptrOffset() const override {name * o = (name*)100; return int(llong((PIObject*)o) - llong(o));} \
|
||||
class __BaseInitializer__ { \
|
||||
public: \
|
||||
__BaseInitializer__() { \
|
||||
uint pid = PIObject::__classNameIDS(); \
|
||||
if (pid == 0) return; \
|
||||
uint id = __classNameIDS(); \
|
||||
PIMutexLocker ml(__meta_mutex()); \
|
||||
if (__meta_data().contains(id)) return; \
|
||||
__meta_data()[pid]; \
|
||||
__meta_data()[id]; \
|
||||
__MetaData & ehp(__meta_data()[pid]); \
|
||||
__MetaData & eh(__meta_data()[id]); \
|
||||
eh.eh_set << ehp.eh_set; \
|
||||
eh.eh_func << ehp.eh_func; \
|
||||
eh.addScope(__classNameCC(), id); \
|
||||
} \
|
||||
}; \
|
||||
__BaseInitializer__ __base_init__;
|
||||
|
||||
#define PIOBJECT_PARENT(name) \
|
||||
class __ParentInitializer__ { \
|
||||
@@ -437,8 +437,8 @@
|
||||
}; \
|
||||
__ParentInitializer__ __parent_init__; \
|
||||
public: \
|
||||
virtual const char * parentClassName() const {return #name;} \
|
||||
typedef name __Parent__; \
|
||||
const char * parentClassName() const override {return #name;} \
|
||||
typedef name __Parent__; \
|
||||
private:
|
||||
|
||||
#define PIOBJECT_SUBCLASS(name, parent) PIOBJECT(name) PIOBJECT_PARENT(parent)
|
||||
|
||||
@@ -271,10 +271,26 @@ protected:
|
||||
};
|
||||
|
||||
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIPropertyStorage::Property & v) {s << v.name << v.value << v.comment << v.flags; return s;}
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIPropertyStorage::Property & v) {s >> v.name >> v.value >> v.comment >> v.flags; return s;}
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Store operator.
|
||||
//! \~russian Оператор сохранения.
|
||||
BINARY_STREAM_WRITE(PIPropertyStorage::Property) {s << v.name << v.value << v.comment << v.flags; return s;}
|
||||
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Restore operator.
|
||||
//! \~russian Оператор извлечения.
|
||||
BINARY_STREAM_READ (PIPropertyStorage::Property) {s >> v.name >> v.value >> v.comment >> v.flags; return s;}
|
||||
|
||||
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Store operator.
|
||||
//! \~russian Оператор сохранения.
|
||||
BINARY_STREAM_WRITE(PIPropertyStorage) {s << v.properties(); return s;}
|
||||
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Restore operator.
|
||||
//! \~russian Оператор извлечения.
|
||||
BINARY_STREAM_READ (PIPropertyStorage) {s >> v.properties(); return s;}
|
||||
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIPropertyStorage & v) {s << v.properties(); return s;}
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIPropertyStorage & v) {s >> v.properties(); return s;}
|
||||
|
||||
#endif // PIPROPERTYSTORAGE_H
|
||||
|
||||
@@ -215,6 +215,13 @@ void PIString::appendFromChars(const char * c, int s, const char * codepage) {
|
||||
}
|
||||
|
||||
|
||||
PIString PIString::fromConsole(const PIByteArray & ba) {
|
||||
PIString ret;
|
||||
if (ba.isNotEmpty()) ret.appendFromChars((const char*)ba.data(), ba.size(), __sysoemname__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIString PIString::fromConsole(const char * s) {
|
||||
PIString ret;
|
||||
if (!s) return ret;
|
||||
@@ -224,6 +231,13 @@ PIString PIString::fromConsole(const char * s) {
|
||||
}
|
||||
|
||||
|
||||
PIString PIString::fromSystem(const PIByteArray & ba) {
|
||||
PIString ret;
|
||||
if (ba.isNotEmpty()) ret.appendFromChars((const char*)ba.data(), ba.size(), __syslocname__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PIString PIString::fromSystem(const char * s) {
|
||||
PIString ret;
|
||||
if (!s) return ret;
|
||||
@@ -361,6 +375,13 @@ uint PIString::hash() const {
|
||||
}
|
||||
|
||||
|
||||
PIByteArray PIString::toSystem() const {
|
||||
if (isEmpty()) return PIByteArray();
|
||||
buildData(__syslocname__);
|
||||
return PIByteArray(data_, strlen(data_));
|
||||
}
|
||||
|
||||
|
||||
PIByteArray PIString::toUTF8() const {
|
||||
if (isEmpty()) return PIByteArray();
|
||||
buildData(__utf8name__);
|
||||
@@ -462,59 +483,65 @@ bool PIString::operator >(const PIString & str) const {
|
||||
//! \~\details
|
||||
//! \~english
|
||||
//! If "len" < 0 then returns substring from symbol "start" to end.
|
||||
//! "start" should be >= 0.
|
||||
//! \~russian
|
||||
//! Если "len" < 0 тогда возвращается подстрока от символа "start" и до конца.
|
||||
//! "start" должен быть >= 0.
|
||||
//! \~\code
|
||||
//! PIString s("0123456789");
|
||||
//! piCout << s.mid(-2, -1); // s = "0123456789"
|
||||
//! piCout << s.mid(-2, 4); // s = "01"
|
||||
//! piCout << s.mid(3, -1); // s = "3456789"
|
||||
//! piCout << s.mid(0, -1); // s = "0123456789"
|
||||
//! piCout << s.mid(0, 2); // s = "01"
|
||||
//! piCout << s.mid(3); // s = "3456789"
|
||||
//! piCout << s.mid(3, 4); // s = "3456"
|
||||
//! piCout << s.mid(7, 1); // s = "7"
|
||||
//! piCout << s.mid(7, 4); // s = "789"
|
||||
//! piCout << s.mid(-1); // s = ""
|
||||
//! \endcode
|
||||
//! \~\sa \a left(), \a right()
|
||||
PIString PIString::mid(const int start, const int len) const {
|
||||
//PIString str;
|
||||
int s = start, l = len;
|
||||
if (l == 0 || s >= length()) return PIString();
|
||||
if (s < 0) {
|
||||
l += s;
|
||||
s = 0;
|
||||
PIString PIString::mid(int start, int len) const {
|
||||
if (len == 0 || start >= length()) return PIString();
|
||||
if (start < 0) {
|
||||
return PIString();
|
||||
}
|
||||
if (l < 0) {
|
||||
return PIString(d.data(s), size_s() - s);
|
||||
if (len < 0) {
|
||||
return PIString(d.data(start), size_s() - start);
|
||||
} else {
|
||||
if (l > length() - s) l = length() - s;
|
||||
return PIString(d.data(s), l);
|
||||
if (len > length() - start) len = length() - start;
|
||||
return PIString(d.data(start), len);
|
||||
}
|
||||
return PIString();
|
||||
}
|
||||
|
||||
|
||||
//! \~\details
|
||||
//! \~english
|
||||
//! If "len" < 0 then remove substring from symbol "start" to end.
|
||||
//! "start" should be >= 0.
|
||||
//! \~russian
|
||||
//! Если "len" < 0 тогда удаляется подстрока от символа "start" и до конца.
|
||||
//! "start" должен быть >= 0.
|
||||
//! \~\code
|
||||
//! PIString s("0123456789");
|
||||
//! s.cutMid(1, 3);
|
||||
//! piCout << s; // s = "0456789"
|
||||
//! s.cutMid(-1, 3);
|
||||
//! s.cutMid(0, 2);
|
||||
//! piCout << s; // s = "56789"
|
||||
//! s.cutMid(3, -1);
|
||||
//! piCout << s; // s = "567"
|
||||
//! s.cutMid(-1, -1);
|
||||
//! piCout << s; // s = "567"
|
||||
//! \endcode
|
||||
//! \~\sa \a cutLeft(), \a cutRight()
|
||||
PIString & PIString::cutMid(const int start, const int len) {
|
||||
int s = start, l = len;
|
||||
if (l == 0) return *this;
|
||||
if (s < 0) {
|
||||
l += s;
|
||||
s = 0;
|
||||
PIString & PIString::cutMid(int start, int len) {
|
||||
if (len == 0) return *this;
|
||||
if (start < 0) {
|
||||
return *this;
|
||||
}
|
||||
if (l < 0) {
|
||||
d.remove(s, size() - s);
|
||||
if (len < 0) {
|
||||
d.remove(start, size() - start);
|
||||
} else {
|
||||
if (l > length() - s) l = length() - s;
|
||||
d.remove(s, l);
|
||||
if (len > length() - start) len = length() - start;
|
||||
d.remove(start, len);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -40,8 +40,7 @@ class PIStringList;
|
||||
//! \~russian Класс строки.
|
||||
class PIP_EXPORT PIString
|
||||
{
|
||||
friend PIByteArray & operator >>(PIByteArray & s, PIString & v);
|
||||
friend PIByteArray & operator <<(PIByteArray & s, const PIString & v);
|
||||
BINARY_STREAM_FRIEND(PIString);
|
||||
public:
|
||||
typedef PIDeque<PIChar>::iterator iterator;
|
||||
typedef PIDeque<PIChar>::const_iterator const_iterator;
|
||||
@@ -78,6 +77,26 @@ public:
|
||||
PIString & operator +=(const PIString & str);
|
||||
PIString & operator +=(const PIConstChars & str);
|
||||
|
||||
PIString(uchar ) = delete;
|
||||
PIString( short) = delete;
|
||||
PIString(ushort) = delete;
|
||||
PIString( int ) = delete;
|
||||
PIString(uint ) = delete;
|
||||
PIString( long ) = delete;
|
||||
PIString(ulong ) = delete;
|
||||
PIString( llong) = delete;
|
||||
PIString(ullong) = delete;
|
||||
|
||||
PIString & operator +=(uchar ) = delete;
|
||||
PIString & operator +=( short) = delete;
|
||||
PIString & operator +=(ushort) = delete;
|
||||
PIString & operator +=( int ) = delete;
|
||||
PIString & operator +=(uint ) = delete;
|
||||
PIString & operator +=( long ) = delete;
|
||||
PIString & operator +=(ulong ) = delete;
|
||||
PIString & operator +=( llong) = delete;
|
||||
PIString & operator +=(ullong) = delete;
|
||||
|
||||
//! \~english Contructs a copy of string.
|
||||
//! \~russian Создает копию строки.
|
||||
PIString(const PIString & o) {d = o.d;}
|
||||
@@ -242,94 +261,6 @@ public:
|
||||
//! \~russian Оператор сравнения.
|
||||
bool operator >=(const char * str) const {return *this >= PIString(str);}
|
||||
|
||||
//! \~english Append string "str" at the end of string.
|
||||
//! \~russian Добавляет в конец строку "str".
|
||||
//! \~\details
|
||||
//! \~\code
|
||||
//! PIString s("this"), s1(" is"), s2(" string");
|
||||
//! s << s1 << s2; // s = "this is string"
|
||||
//! \endcode
|
||||
PIString & operator <<(const PIString & str) {*this += str; return *this;}
|
||||
|
||||
//! \~english Append character "c" at the end of string.
|
||||
//! \~russian Добавляет в конец символ "c".
|
||||
//! \~\details
|
||||
//! \~\code
|
||||
//! PIString s("stri");
|
||||
//! s << PIChar('n') << PIChar('g'); // s = "string"
|
||||
//! \endcode
|
||||
PIString & operator <<(const PIChar c) {d.append(c); return *this;}
|
||||
|
||||
//! \~english Append character `c` at the end of string.
|
||||
//! \~russian Добавляет в конец символ `c`.
|
||||
//! \~\details
|
||||
//! \~\code
|
||||
//! PIString s("stri");
|
||||
//! s << 'n' << 'g'; // s = "string"
|
||||
//! \endcode
|
||||
PIString & operator <<(const char c) {d.append(PIChar(c)); return *this;}
|
||||
|
||||
//! \~english Append С-string "str" at the end of string.
|
||||
//! \~russian Добавляет в конец C-строку "str".
|
||||
//! \~\details
|
||||
//! \~\code
|
||||
//! PIString s("this");
|
||||
//! s << " is" << " string"; // s = "this is string"
|
||||
//! \endcode
|
||||
PIString & operator <<(const char * str) {*this += str; return *this;}
|
||||
|
||||
//! \~english Append \c wchar_t C-string "str" at the end of string.
|
||||
//! \~russian Добавляет в конец \c wchar_t C-строку "str".
|
||||
//! \~\details
|
||||
//! \~\code
|
||||
//! PIString s;
|
||||
//! s << L"№ -" << " number"; // s = "№ - number"
|
||||
//! \endcode
|
||||
PIString & operator <<(const wchar_t * str) {*this += str; return *this;}
|
||||
|
||||
PIString & operator <<(const PIConstChars & str) {*this += str; return *this;}
|
||||
|
||||
//! \~english Append string representation of "num" at the end of string.
|
||||
//! \~russian Добавляет в конец строковое представление "num".
|
||||
//! \~\details
|
||||
//! \~\code
|
||||
//! PIString s("ten - ");
|
||||
//! s << 10; // s = "ten - 10"
|
||||
//! \endcode
|
||||
PIString & operator <<(const int & num) {*this += PIString::fromNumber(num); return *this;}
|
||||
PIString & operator <<(const uint & num) {*this += PIString::fromNumber(num); return *this;}
|
||||
|
||||
//! \~english Append string representation of "num" at the end of string.
|
||||
//! \~russian Добавляет в конец строковое представление "num".
|
||||
//! \~\details
|
||||
//! \~\code
|
||||
//! PIString s("ten - ");
|
||||
//! s << 10; // s = "ten - 10"
|
||||
//! \endcode
|
||||
PIString & operator <<(const long & num) {*this += PIString::fromNumber(num); return *this;}
|
||||
PIString & operator <<(const ulong & num) {*this += PIString::fromNumber(num); return *this;}
|
||||
|
||||
PIString & operator <<(const llong & num) {*this += PIString::fromNumber(num); return *this;}
|
||||
PIString & operator <<(const ullong & num) {*this += PIString::fromNumber(num); return *this;}
|
||||
|
||||
//! \~english Append string representation of "num" at the end of string.
|
||||
//! \~russian Добавляет в конец строковое представление "num".
|
||||
//! \~\details
|
||||
//! \~\code
|
||||
//! PIString s("1/10 - ");
|
||||
//! s << 0.1; // s = "1/10 - 0.1"
|
||||
//! \endcode
|
||||
PIString & operator <<(const float & num) {*this += PIString::fromNumber(num); return *this;}
|
||||
|
||||
//! \~english Append string representation of "num" at the end of string.
|
||||
//! \~russian Добавляет в конец строковое представление "num".
|
||||
//! \~\details
|
||||
//! \~\code
|
||||
//! PIString s("1/10 - ");
|
||||
//! s << 0.1; // s = "1/10 - 0.1"
|
||||
//! \endcode
|
||||
PIString & operator <<(const double & num) {*this += PIString::fromNumber(num); return *this;}
|
||||
|
||||
//! \~english Iterator to the first element.
|
||||
//! \~russian Итератор на первый элемент.
|
||||
//! \~\details
|
||||
@@ -502,11 +433,11 @@ public:
|
||||
|
||||
//! \~english Returns part of string from character at index "start" and maximum length "len".
|
||||
//! \~russian Возвращает подстроку от символа "start" и максимальной длиной "len".
|
||||
PIString mid(const int start, const int len = -1) const;
|
||||
PIString mid(int start, int len = -1) const;
|
||||
|
||||
//! \~english Synonym of \a mid().
|
||||
//! \~russian Аналог \a mid().
|
||||
PIString subString(const int start, const int len = -1) const {return mid(start, len);}
|
||||
PIString subString(int start, int len = -1) const {return mid(start, len);}
|
||||
|
||||
//! \~english Returns part of string from start and maximum length "len".
|
||||
//! \~russian Возвращает подстроку от начала и максимальной длиной "len".
|
||||
@@ -519,7 +450,7 @@ public:
|
||||
//! piCout << s.left(15); // s = "0123456789"
|
||||
//! \endcode
|
||||
//! \~\sa \a mid(), \a right()
|
||||
PIString left(const int len) const {return len <= 0 ? PIString() : mid(0, len);}
|
||||
PIString left(int len) const {return len <= 0 ? PIString() : mid(0, len);}
|
||||
|
||||
//! \~english Returns part of string at end and maximum length "len".
|
||||
//! \~russian Возвращает подстроку максимальной длиной "len" и до конца.
|
||||
@@ -532,11 +463,11 @@ public:
|
||||
//! piCout << s.right(15); // s = "0123456789"
|
||||
//! \endcode
|
||||
//! \~\sa \a mid(), \a left()
|
||||
PIString right(const int len) const {return len <= 0 ? PIString() : mid(size() - len, len);}
|
||||
PIString right(int len) const {return len <= 0 ? PIString() : mid(size() - len, len);}
|
||||
|
||||
//! \~english Remove part of string from character as index "start" and maximum length "len" and return this string.
|
||||
//! \~russian Удаляет часть строки от символа "start" и максимальной длины "len", возвращает эту строку.
|
||||
PIString & cutMid(const int start, const int len);
|
||||
PIString & cutMid(int start, int len);
|
||||
|
||||
//! \~english Remove part of string from start and maximum length "len" and return this string.
|
||||
//! \~russian Удаляет часть строки от начала и максимальной длины "len", возвращает эту строку.
|
||||
@@ -551,7 +482,7 @@ public:
|
||||
//! piCout << s; // s = ""
|
||||
//! \endcode
|
||||
//! \~\sa \a cutMid(), \a cutRight()
|
||||
PIString & cutLeft(const int len) {return len <= 0 ? *this : cutMid(0, len);}
|
||||
PIString & cutLeft(int len) {return len <= 0 ? *this : cutMid(0, len);}
|
||||
|
||||
//! \~english Remove part of string at end and maximum length "len" and return this string.
|
||||
//! \~russian Удаляет часть строки максимальной длины "len" от конца, возвращает эту строку.
|
||||
@@ -566,7 +497,7 @@ public:
|
||||
//! piCout << s; // s = ""
|
||||
//! \endcode
|
||||
//! \~\sa \a cutMid(), \a cutLeft()
|
||||
PIString & cutRight(const int len) {return len <= 0 ? *this : cutMid(size() - len, len);}
|
||||
PIString & cutRight(int len) {return len <= 0 ? *this : cutMid(size() - len, len);}
|
||||
|
||||
//! \~english Remove spaces at the start and at the end of string and return this string.
|
||||
//! \~russian Удаляет пробельные символы с начала и конца строки и возвращает эту строку.
|
||||
@@ -909,6 +840,10 @@ public:
|
||||
//! \~russian Тоже самое, что \a toUTF8().
|
||||
PIByteArray toByteArray() const {return toUTF8();}
|
||||
|
||||
//! \~english Returns \a PIByteArray contains \a data() of this string without terminating null-char.
|
||||
//! \~russian Возвращает \a PIByteArray содержащий \a data() строки без завершающего нулевого байта.
|
||||
PIByteArray toSystem() const;
|
||||
|
||||
//! \~english Returns \a PIByteArray contains \a dataUTF8() of this string without terminating null-char.
|
||||
//! \~russian Возвращает \a PIByteArray содержащий \a dataUTF8() строки без завершающего нулевого байта.
|
||||
PIByteArray toUTF8() const;
|
||||
@@ -1507,10 +1442,18 @@ public:
|
||||
//! \~english Returns "true" or "false"
|
||||
//! \~russian Возвращает "true" или "false"
|
||||
static PIString fromBool(const bool value) {return PIString(value ? PIStringAscii("true") : PIStringAscii("false"));}
|
||||
|
||||
//! \~english Returns string constructed from terminal codepage.
|
||||
//! \~russian Возвращает строку созданную из кодировки консоли.
|
||||
static PIString fromConsole(const PIByteArray & s);
|
||||
|
||||
//! \~english Returns string constructed from terminal codepage.
|
||||
//! \~russian Возвращает строку созданную из кодировки консоли.
|
||||
static PIString fromConsole(const char * s);
|
||||
|
||||
//! \~english Returns string constructed from system codepage.
|
||||
//! \~russian Возвращает строку созданную из кодировки системы.
|
||||
static PIString fromSystem(const PIByteArray & s);
|
||||
|
||||
//! \~english Returns string constructed from system codepage.
|
||||
//! \~russian Возвращает строку созданную из кодировки системы.
|
||||
@@ -1580,15 +1523,15 @@ private:
|
||||
//! \~russian Оператор вывода в \a PICout.
|
||||
PIP_EXPORT PICout operator <<(PICout s, const PIString & v);
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Store operator.
|
||||
//! \~russian Оператор сохранения.
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIString & v) {s << v.d; return s;}
|
||||
BINARY_STREAM_WRITE(PIString) {s << v.d; return s;}
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Restore operator.
|
||||
//! \~russian Оператор извлечения.
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIString & v) {v.d.clear(); s >> v.d; return s;}
|
||||
BINARY_STREAM_READ(PIString) {s >> v.d; return s;}
|
||||
|
||||
|
||||
//! \~english Returns concatenated string.
|
||||
|
||||
@@ -126,19 +126,26 @@ public:
|
||||
};
|
||||
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \~english Store operator
|
||||
//! \~russian Оператор сохранения
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIStringList & v) {s << int(v.size_s()); for (int i = 0; i < v.size_s(); ++i) s << v[i]; return s;}
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Store operator.
|
||||
//! \~russian Оператор сохранения.
|
||||
BINARY_STREAM_WRITE(PIStringList) {
|
||||
s << static_cast<const PIDeque<PIString> &>(v);
|
||||
return s;
|
||||
}
|
||||
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Restore operator.
|
||||
//! \~russian Оператор извлечения.
|
||||
BINARY_STREAM_READ(PIStringList) {
|
||||
s >> static_cast<PIDeque<PIString> &>(v);
|
||||
return s;
|
||||
}
|
||||
|
||||
//! \relatesalso PIByteArray
|
||||
//! \~english Restore operator
|
||||
//! \~russian Оператор извлечения
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIStringList & v) {int sz; s >> sz; v.resize(sz); for (int i = 0; i < sz; ++i) s >> v[i]; return s;}
|
||||
|
||||
//! \relatesalso PICout
|
||||
//! \~english Output operator to \a PICout
|
||||
//! \~russian Оператор вывода в \a PICout
|
||||
inline PICout operator <<(PICout s, const PIStringList & v) {s.space(); s.setControl(0, true); s << "{"; for (uint i = 0; i < v.size(); ++i) {s << "\"" << v[i] << "\""; if (i < v.size() - 1) s << ", ";} s << "}"; s.restoreControl(); return s;}
|
||||
inline PICout operator <<(PICout s, const PIStringList & v) {s.space(); s.saveAndSetControls(0); s << "{"; for (uint i = 0; i < v.size(); ++i) {s << "\"" << v[i] << "\""; if (i < v.size() - 1) s << ", ";} s << "}"; s.restoreControls(); return s;}
|
||||
|
||||
#endif // PISTRINGLIST_H
|
||||
|
||||
@@ -186,7 +186,7 @@ private:
|
||||
//! \relatesalso PICout
|
||||
//! \~english \brief Output operator to PICout
|
||||
//! \~russian \brief Оператор вывода в PICout
|
||||
inline PICout operator <<(PICout s, const PISystemTime & v) {s.space(); s.setControl(0, true); s << "(" << v.seconds << " s, " << v.nanoseconds << " ns)"; s.restoreControl(); return s;}
|
||||
inline PICout operator <<(PICout s, const PISystemTime & v) {s.space(); s.saveAndSetControls(0); s << "(" << v.seconds << " s, " << v.nanoseconds << " ns)"; s.restoreControls(); return s;}
|
||||
|
||||
|
||||
|
||||
|
||||
341
libs/main/core/pitextstream.h
Normal file
341
libs/main/core/pitextstream.h
Normal file
@@ -0,0 +1,341 @@
|
||||
/*! \file pitextstream.h
|
||||
* \ingroup Core
|
||||
* \~\brief
|
||||
* \~english Text serialization functionality over PIBinaryStream
|
||||
* \~russian Функциональность текстовой сериализации поверх PIBinaryStream
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Text serialization functionality over PIBinaryStream
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PITEXTSTREAM_H
|
||||
#define PITEXTSTREAM_H
|
||||
|
||||
#include "pistring.h"
|
||||
|
||||
|
||||
//! \ingroup Core
|
||||
//! \~\brief
|
||||
//! \~english Text serialization functionality over PIBinaryStream.
|
||||
//! \~russian Функциональность текстовой сериализации поверх PIBinaryStream.
|
||||
template<typename P>
|
||||
class PITextStream {
|
||||
public:
|
||||
|
||||
//! \~english Floating-point numbers write format
|
||||
//! \~russian Формат записи чисел с плавающей точкой
|
||||
enum FloatFormat {
|
||||
DecimalFormat /** \~english Decimal format, "*.*" \~russian Десятичный формат, "*.*" */ = 'f',
|
||||
ExponentFormat /** \~english Exponential format, "*e+-<E>" \~russian Экспонентный формат, "*e+-<E>" */ = 'e'
|
||||
};
|
||||
|
||||
//! \~english String encoding
|
||||
//! \~russian Кодировка строк
|
||||
enum Encoding {
|
||||
System /** \~english System encoding \~russian Системная кодировка */,
|
||||
UTF8 /** \~english UTF-8 encoding \~russian Кодировка UTF-8 */,
|
||||
};
|
||||
|
||||
//! \~english Construct text stream binded to "stream_"
|
||||
//! \~russian Возвращает привязанный к "stream_" текстовый поток
|
||||
PITextStream(PIBinaryStream<P> * stream_) {setStream(stream_);}
|
||||
|
||||
//! \~english Returns binded PIBinaryStream
|
||||
//! \~russian Возвращает привязанный PIBinaryStream
|
||||
PIBinaryStream<P> * stream() const {return s;}
|
||||
void setStream(PIBinaryStream<P> * stream_) {
|
||||
s = stream_;
|
||||
is_end = false;
|
||||
}
|
||||
|
||||
//! \~english Returns if end of stream reached
|
||||
//! \~russian Возвращает достигнут ли конец потока
|
||||
bool isEnd() const {return is_end;}
|
||||
|
||||
//! \~english Returns read/write encoding
|
||||
//! \~russian Возвращает кодировку чтения/записи
|
||||
Encoding encoding() const {return enc;}
|
||||
|
||||
//! \~english Set read/write encoding, default UTF8
|
||||
//! \~russian Устанавливает кодировку чтения/записи, по умолчанию UTF8
|
||||
void setEncoding(Encoding e) {enc = e;}
|
||||
|
||||
//! \~english Returns float numbers write format
|
||||
//! \~russian Возвращает формат записи чисел с плавающей точкой
|
||||
FloatFormat floatFormat() const {return format_;}
|
||||
|
||||
//! \~english Set float numbers write format, default DecimalFormat
|
||||
//! \~russian Устанавливает формат записи чисел с плавающей точкой, по умолчанию DecimalFormat
|
||||
void setFloatFormat(FloatFormat format) {format_ = format;}
|
||||
|
||||
//! \~english Returns float numbers write precision
|
||||
//! \~russian Возвращает точность записи чисел с плавающей точкой
|
||||
int floatPrecision() const {return prec_;}
|
||||
|
||||
//! \~english Set float numbers write precision to "prec_" digits, default 5
|
||||
//! \~russian Устанавливает точность записи чисел с плавающей точкой, по умолчанию 5
|
||||
void setFloatPrecision(int prec) {prec_ = prec;}
|
||||
|
||||
//! \~english Append space
|
||||
//! \~russian Добавляет пробел
|
||||
PITextStream<P> & space() {s->binaryStreamAppend(' '); return *this;}
|
||||
|
||||
//! \~english Append new line
|
||||
//! \~russian Добавляет новую строку
|
||||
PITextStream<P> & newLine() {s->binaryStreamAppend('\n'); return *this;}
|
||||
|
||||
//! \~english Append "v" string
|
||||
//! \~russian Добавляет строку "v"
|
||||
void append(const PIString & v) {
|
||||
if (v.isEmpty()) return;
|
||||
PIByteArray d;
|
||||
switch (enc) {
|
||||
case System: d = v.toSystem(); break;
|
||||
case UTF8 : d = v.toUTF8(); break;
|
||||
}
|
||||
s->binaryStreamAppend(d.data(), d.size());
|
||||
}
|
||||
|
||||
//! \~english Append "v" as ASCII
|
||||
//! \~russian Добавляет "v" как ASCII
|
||||
void append(const PIConstChars & v) {if (!v.isEmpty()) s->binaryStreamAppend(v.data(), v.size());}
|
||||
|
||||
//! \~english Append "v" char as character
|
||||
//! \~russian Добавляет "v" как символ
|
||||
void append(char v) {s->binaryStreamAppend(v);}
|
||||
|
||||
//! \~english Append "v" as ASCII
|
||||
//! \~russian Добавляет "v" как ASCII
|
||||
void append(const char * v) {append(PIConstChars(v));}
|
||||
|
||||
//! \~english Append boolean, "true" of "false"
|
||||
//! \~russian Добавляет логическое, "true" of "false"
|
||||
void append(bool v) {append(v ? "true" : "false");}
|
||||
|
||||
//! \~english Append integer
|
||||
//! \~russian Добавляет целое
|
||||
void append(int v) {append(PIString::fromNumber(v));}
|
||||
|
||||
//! \~english Append integer
|
||||
//! \~russian Добавляет целое
|
||||
void append(llong v) {append(PIString::fromNumber(v));}
|
||||
|
||||
//! \~english Append floating-point number, using \a floatFormat() and \a floatPrecision()
|
||||
//! \~russian Добавляет число с плавающей точкой, используя \a floatFormat() и \a floatPrecision()
|
||||
void append(float v) {append(PIString::fromNumber(v, (char)format_, prec_));}
|
||||
|
||||
//! \~english Append floating-point number, using \a floatFormat() and \a floatPrecision()
|
||||
//! \~russian Добавляет число с плавающей точкой, используя \a floatFormat() и \a floatPrecision()
|
||||
void append(double v) {append(PIString::fromNumber(v, (char)format_, prec_));}
|
||||
|
||||
|
||||
//! \~english Read character
|
||||
//! \~russian Читает символ
|
||||
char readChar(bool * rok) {
|
||||
char ret;
|
||||
bool ok = s->binaryStreamTake(&ret, sizeof(ret));
|
||||
if (!ok) is_end = true;
|
||||
if (rok) *rok = ok;
|
||||
return ret;
|
||||
}
|
||||
|
||||
//! \~english Read line
|
||||
//! \~russian Читает строку
|
||||
PIString readLine() {
|
||||
PIByteArray ret;
|
||||
bool ok = true;
|
||||
for (;;) {
|
||||
char b = readChar(&ok);
|
||||
if (!ok || b == '\n') break;
|
||||
if (b != '\r')
|
||||
ret.append((uchar)b);
|
||||
}
|
||||
return fromBytes(ret);
|
||||
}
|
||||
|
||||
//! \~english Read word, skip leading whitespaces, until next whitespace
|
||||
//! \~russian Читает слово, пропуская начальные пробельные символы, до следующего пробельного символа
|
||||
PIString readWord() {
|
||||
static PIConstChars spaces(" \t\n\r");
|
||||
return readUntil(spaces);
|
||||
}
|
||||
|
||||
//! \~english Read C-word, skip leading and until non C-identifier
|
||||
//! \~russian Читает C-слово, пропуская начальные и до следующих символов, не являющихся C-идентификаторами
|
||||
PIString readCWord() {
|
||||
static PIConstChars chars(" \t\n\r:;%$&#@!?~/*-+=.,\\\"'`[](){}<>");
|
||||
return readUntil(chars);
|
||||
}
|
||||
|
||||
private:
|
||||
PIString fromBytes(const PIByteArray & ba) {
|
||||
switch (enc) {
|
||||
case System: return PIString::fromSystem(ba);
|
||||
case UTF8 : return PIString::fromUTF8(ba);
|
||||
}
|
||||
return PIString();
|
||||
}
|
||||
PIString readUntil(const PIConstChars & chars) {
|
||||
//static PIConstChars spaces(" \t\n\r");
|
||||
bool ok = true;
|
||||
char c = skipWhile(chars, &ok);
|
||||
if (!ok) return PIString();
|
||||
PIByteArray ret;
|
||||
ret.append((uchar)c);
|
||||
for (;;) {
|
||||
c = readChar(&ok);
|
||||
if (!ok || chars.contains(c)) break;
|
||||
ret.append((uchar)c);
|
||||
}
|
||||
return fromBytes(ret);
|
||||
}
|
||||
// returns first non-"chars" char
|
||||
char skipWhile(const PIConstChars & chars, bool * rok) {
|
||||
bool ok = true;
|
||||
char c = 0;
|
||||
for (;;) {
|
||||
c = readChar(&ok);
|
||||
if (!ok || !chars.contains(c)) break;
|
||||
}
|
||||
if (rok) *rok = ok;
|
||||
return c;
|
||||
}
|
||||
|
||||
PIBinaryStream<P> * s;
|
||||
Encoding enc = UTF8;
|
||||
FloatFormat format_ = DecimalFormat;
|
||||
bool is_end = false;
|
||||
int prec_ = 5;
|
||||
|
||||
};
|
||||
|
||||
|
||||
//! \~english Returns PITextStream for binary stream "stream"
|
||||
//! \~russian Возвращает PITextStream для бинарного потока "stream"
|
||||
template<typename P>
|
||||
inline PITextStream<P> createPITextStream(PIBinaryStream<P> * stream) {return PITextStream<P>(stream);}
|
||||
|
||||
|
||||
//! \~english Append boolean
|
||||
//! \~russian Добавляет логическое
|
||||
template<typename P> inline PITextStream<P> & operator <<(PITextStream<P> & s, bool v) {s.append(v); return s;}
|
||||
|
||||
//! \~english Append character
|
||||
//! \~russian Добавляет символ
|
||||
template<typename P> inline PITextStream<P> & operator <<(PITextStream<P> & s, char v) {s.append(v); return s;}
|
||||
|
||||
//! \~english Append integer
|
||||
//! \~russian Добавляет целое
|
||||
template<typename P> inline PITextStream<P> & operator <<(PITextStream<P> & s, uchar v) {s.append((int)v); return s;}
|
||||
|
||||
//! \~english Append integer
|
||||
//! \~russian Добавляет целое
|
||||
template<typename P> inline PITextStream<P> & operator <<(PITextStream<P> & s, short v) {s.append((int)v); return s;}
|
||||
|
||||
//! \~english Append integer
|
||||
//! \~russian Добавляет целое
|
||||
template<typename P> inline PITextStream<P> & operator <<(PITextStream<P> & s, ushort v) {s.append((int)v); return s;}
|
||||
|
||||
//! \~english Append integer
|
||||
//! \~russian Добавляет целое
|
||||
template<typename P> inline PITextStream<P> & operator <<(PITextStream<P> & s, int v) {s.append((int)v); return s;}
|
||||
|
||||
//! \~english Append integer
|
||||
//! \~russian Добавляет целое
|
||||
template<typename P> inline PITextStream<P> & operator <<(PITextStream<P> & s, uint v) {s.append((int)v); return s;}
|
||||
|
||||
//! \~english Append integer
|
||||
//! \~russian Добавляет целое
|
||||
template<typename P> inline PITextStream<P> & operator <<(PITextStream<P> & s, llong v) {s.append((llong)v); return s;}
|
||||
|
||||
//! \~english Append integer
|
||||
//! \~russian Добавляет целое
|
||||
template<typename P> inline PITextStream<P> & operator <<(PITextStream<P> & s, ullong v) {s.append((llong)v); return s;}
|
||||
|
||||
//! \~english Append floating-point number
|
||||
//! \~russian Добавляет число с плавающей точкой
|
||||
template<typename P> inline PITextStream<P> & operator <<(PITextStream<P> & s, float v) {s.append(v); return s;}
|
||||
|
||||
//! \~english Append floating-point number
|
||||
//! \~russian Добавляет число с плавающей точкой
|
||||
template<typename P> inline PITextStream<P> & operator <<(PITextStream<P> & s, double v) {s.append(v); return s;}
|
||||
|
||||
|
||||
//! \~english Append string
|
||||
//! \~russian Добавляет строку
|
||||
template<typename P> inline PITextStream<P> & operator <<(PITextStream<P> & s, const char * v) {s.append(v); return s;}
|
||||
|
||||
//! \~english Append string
|
||||
//! \~russian Добавляет строку
|
||||
template<typename P> inline PITextStream<P> & operator <<(PITextStream<P> & s, const PIConstChars & v) {s.append(v); return s;}
|
||||
|
||||
//! \~english Append string
|
||||
//! \~russian Добавляет строку
|
||||
template<typename P> inline PITextStream<P> & operator <<(PITextStream<P> & s, const PIString & v) {s.append(v); return s;}
|
||||
|
||||
|
||||
//! \~english Read word as bool
|
||||
//! \~russian Читает слово как логическое
|
||||
template<typename P> inline PITextStream<P> & operator >>(PITextStream<P> & s, bool & v) {v = s.readWord().toBool(); return s;}
|
||||
|
||||
//! \~english Read character
|
||||
//! \~russian Читает символ
|
||||
template<typename P> inline PITextStream<P> & operator >>(PITextStream<P> & s, char & v) {v = s.readChar(); return s;}
|
||||
|
||||
//! \~english Read word as integer
|
||||
//! \~russian Читает слово как целое
|
||||
template<typename P> inline PITextStream<P> & operator >>(PITextStream<P> & s, uchar & v) {v = s.readWord().toUInt(); return s;}
|
||||
|
||||
//! \~english Read word as integer
|
||||
//! \~russian Читает слово как целое
|
||||
template<typename P> inline PITextStream<P> & operator >>(PITextStream<P> & s, short & v) {v = s.readWord().toInt(); return s;}
|
||||
|
||||
//! \~english Read word as integer
|
||||
//! \~russian Читает слово как целое
|
||||
template<typename P> inline PITextStream<P> & operator >>(PITextStream<P> & s, ushort & v) {v = s.readWord().toUInt(); return s;}
|
||||
|
||||
//! \~english Read word as integer
|
||||
//! \~russian Читает слово как целое
|
||||
template<typename P> inline PITextStream<P> & operator >>(PITextStream<P> & s, int & v) {v = s.readWord().toInt(); return s;}
|
||||
|
||||
//! \~english Read word as integer
|
||||
//! \~russian Читает слово как целое
|
||||
template<typename P> inline PITextStream<P> & operator >>(PITextStream<P> & s, uint & v) {v = s.readWord().toUInt(); return s;}
|
||||
|
||||
//! \~english Read word as integer
|
||||
//! \~russian Читает слово как целое
|
||||
template<typename P> inline PITextStream<P> & operator >>(PITextStream<P> & s, llong & v) {v = s.readWord().toLLong(); return s;}
|
||||
|
||||
//! \~english Read word as integer
|
||||
//! \~russian Читает слово как целое
|
||||
template<typename P> inline PITextStream<P> & operator >>(PITextStream<P> & s, ullong & v) {v = s.readWord().toULLong(); return s;}
|
||||
|
||||
//! \~english Read word as floating-point number
|
||||
//! \~russian Читает слово как число с плавающей точкой
|
||||
template<typename P> inline PITextStream<P> & operator >>(PITextStream<P> & s, float & v) {v = s.readWord().toFloat(); return s;}
|
||||
|
||||
//! \~english Read word as floating-point number
|
||||
//! \~russian Читает слово как число с плавающей точкой
|
||||
template<typename P> inline PITextStream<P> & operator >>(PITextStream<P> & s, double & v) {v = s.readWord().toDouble(); return s;}
|
||||
|
||||
|
||||
//! \~english Read word
|
||||
//! \~russian Читает слово
|
||||
template<typename P> inline PITextStream<P> & operator >>(PITextStream<P> & s, PIString & v) {v = s.readWord(); return s;}
|
||||
|
||||
#endif
|
||||
@@ -206,8 +206,7 @@ classname_to __PIVariantFunctions__<classname_from>::castVariant<classname_to>(c
|
||||
//! \~english Variant type.
|
||||
class PIP_EXPORT PIVariant {
|
||||
friend PICout operator <<(PICout s, const PIVariant & v);
|
||||
friend PIByteArray & operator <<(PIByteArray & s, const PIVariant & v);
|
||||
friend PIByteArray & operator >>(PIByteArray & s, PIVariant & v);
|
||||
BINARY_STREAM_FRIEND(PIVariant);
|
||||
public:
|
||||
|
||||
//! Type of %PIVariant content
|
||||
@@ -773,8 +772,12 @@ REGISTER_VARIANT(PILined)
|
||||
REGISTER_VARIANT(PIMathVectord)
|
||||
REGISTER_VARIANT(PIMathMatrixd)
|
||||
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIVariant & v) {
|
||||
s << v._content << int(v._type);
|
||||
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Store operator.
|
||||
//! \~russian Оператор сохранения.
|
||||
BINARY_STREAM_WRITE(PIVariant) {
|
||||
s << v._content << v._type;
|
||||
if (v._type == PIVariant::pivCustom) {
|
||||
#ifdef CUSTOM_PIVARIANT
|
||||
if (v._info) {
|
||||
@@ -788,10 +791,12 @@ inline PIByteArray & operator <<(PIByteArray & s, const PIVariant & v) {
|
||||
}
|
||||
return s;
|
||||
}
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIVariant & v) {
|
||||
int t(0);
|
||||
s >> v._content >> t;
|
||||
v._type = (PIVariant::Type)t;
|
||||
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Restore operator.
|
||||
//! \~russian Оператор извлечения.
|
||||
BINARY_STREAM_READ(PIVariant) {
|
||||
s >> v._content >> v._type;
|
||||
if (v._type == PIVariant::pivCustom) {
|
||||
PIString tn;
|
||||
s >> tn;
|
||||
@@ -804,12 +809,12 @@ inline PIByteArray & operator >>(PIByteArray & s, PIVariant & v) {
|
||||
}
|
||||
|
||||
inline PICout operator <<(PICout s, const PIVariant & v) {
|
||||
s.space(); s.setControl(0, true);
|
||||
s.space(); s.saveAndSetControls(0);
|
||||
s << "PIVariant(" << v.typeName();
|
||||
if (v.isValid())
|
||||
s << ", " << v.toString();
|
||||
s << ")";
|
||||
s.restoreControl(); return s;
|
||||
s.restoreControls(); return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -110,25 +110,25 @@ PIPropertyStorage PIVariantTypes::IODevice::get() const {
|
||||
|
||||
PIString PIVariantTypes::IODevice::toPICout() const {
|
||||
PIString s;
|
||||
s << "IODevice(" << prefix << ", mode=";
|
||||
s += "IODevice(" + prefix + ", mode=";
|
||||
int rwc = 0;
|
||||
if (mode & 1) {s << "r"; ++rwc;}
|
||||
if (mode & 2) {s << "w"; ++rwc;}
|
||||
if (rwc == 1) s << "o";
|
||||
s << ", flags=";
|
||||
if (mode & 1) {s += "r"; ++rwc;}
|
||||
if (mode & 2) {s += "w"; ++rwc;}
|
||||
if (rwc == 1) s += "o";
|
||||
s += ", flags=";
|
||||
#ifndef MICRO_PIP // TODO: PIIODevice for MICRO PIP
|
||||
if (options != 0) {
|
||||
if (((PIIODevice::DeviceOptions)options)[PIIODevice::BlockingRead])
|
||||
s << " br";
|
||||
s += " br";
|
||||
if (((PIIODevice::DeviceOptions)options)[PIIODevice::BlockingWrite])
|
||||
s << " bw";
|
||||
s += " bw";
|
||||
}
|
||||
#endif // MICRO_PIP
|
||||
PIPropertyStorage ps = get();
|
||||
piForeachC (PIPropertyStorage::Property & p, ps) {
|
||||
s << ", " << p.name << "=\"" << p.value.toString() << "\"";
|
||||
s += ", " + p.name + "=\"" + p.value.toString() + "\"";
|
||||
}
|
||||
s << ")";
|
||||
s += ")";
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
@@ -164,28 +164,83 @@ struct PIP_EXPORT IODevice {
|
||||
|
||||
}
|
||||
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIVariantTypes::Enumerator & v) {s << v.value << v.name; return s;}
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIVariantTypes::Enumerator & v) {s >> v.value >> v.name; return s;}
|
||||
inline PICout operator <<(PICout s, const PIVariantTypes::Enumerator & v) {s << v.name << "(" << v.value << ")"; return s;}
|
||||
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIVariantTypes::Enum & v) {s << v.enum_name << v.selected << v.enum_list; return s;}
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIVariantTypes::Enum & v) {s >> v.enum_name >> v.selected >> v.enum_list; return s;}
|
||||
inline PICout operator <<(PICout s, const PIVariantTypes::Enum & v) {s << "Enum(" << v.selectedValue() << "=" << v.selectedName() << ")"; return s;}
|
||||
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIVariantTypes::File & v) {s << v.file << v.filter << uchar((v.is_abs ? 1 : 0) + (v.is_save ? 2 : 0)); return s;}
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIVariantTypes::File & v) {uchar f(0); s >> v.file >> v.filter >> f; v.is_abs = ((f & 1) == 1); v.is_save = ((f & 2) == 2); return s;}
|
||||
inline PICout operator <<(PICout s, const PIVariantTypes::File & v) {s << "File(\"" << v.file << "\")"; return s;}
|
||||
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIVariantTypes::Dir & v) {s << v.dir << v.is_abs; return s;}
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIVariantTypes::Dir & v) {s >> v.dir >> v.is_abs; return s;}
|
||||
inline PICout operator <<(PICout s, const PIVariantTypes::Dir & v) {s << "Dir(\"" << v.dir << "\")"; return s;}
|
||||
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIVariantTypes::Color & v) {s << v.rgba; return s;}
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIVariantTypes::Color & v) {s >> v.rgba; return s;}
|
||||
inline PICout operator <<(PICout s, const PIVariantTypes::Color & v) {s.saveControl(); s << PICoutManipulators::Hex << "Color(#" << v.rgba << ")"; s.restoreControl(); return s;}
|
||||
inline PICout operator <<(PICout s, const PIVariantTypes::Color & v) {s.saveControls(); s << PICoutManipulators::Hex << "Color(#" << v.rgba << ")"; s.restoreControls(); return s;}
|
||||
|
||||
inline PIByteArray & operator <<(PIByteArray & s, const PIVariantTypes::IODevice & v) {s << v.prefix << v.mode << v.options << v.props; return s;}
|
||||
inline PIByteArray & operator >>(PIByteArray & s, PIVariantTypes::IODevice & v) {s >> v.prefix >> v.mode >> v.options >> v.props; return s;}
|
||||
inline PICout operator <<(PICout s, const PIVariantTypes::IODevice & v) {s << v.toPICout(); return s;}
|
||||
|
||||
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Store operator.
|
||||
//! \~russian Оператор сохранения.
|
||||
BINARY_STREAM_WRITE(PIVariantTypes::Enumerator) {s << v.value << v.name; return s;}
|
||||
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Restore operator.
|
||||
//! \~russian Оператор извлечения.
|
||||
BINARY_STREAM_READ (PIVariantTypes::Enumerator) {s >> v.value >> v.name; return s;}
|
||||
|
||||
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Store operator.
|
||||
//! \~russian Оператор сохранения.
|
||||
BINARY_STREAM_WRITE(PIVariantTypes::Enum) {s << v.enum_name << v.selected << v.enum_list; return s;}
|
||||
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Restore operator.
|
||||
//! \~russian Оператор извлечения.
|
||||
BINARY_STREAM_READ (PIVariantTypes::Enum) {s >> v.enum_name >> v.selected >> v.enum_list; return s;}
|
||||
|
||||
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Store operator.
|
||||
//! \~russian Оператор сохранения.
|
||||
BINARY_STREAM_WRITE(PIVariantTypes::File) {s << v.file << v.filter << uchar((v.is_abs ? 1 : 0) + (v.is_save ? 2 : 0)); return s;}
|
||||
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Restore operator.
|
||||
//! \~russian Оператор извлечения.
|
||||
BINARY_STREAM_READ (PIVariantTypes::File) {uchar f(0); s >> v.file >> v.filter >> f; v.is_abs = ((f & 1) == 1); v.is_save = ((f & 2) == 2); return s;}
|
||||
|
||||
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Store operator.
|
||||
//! \~russian Оператор сохранения.
|
||||
BINARY_STREAM_WRITE(PIVariantTypes::Dir) {s << v.dir << v.is_abs; return s;}
|
||||
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Restore operator.
|
||||
//! \~russian Оператор извлечения.
|
||||
BINARY_STREAM_READ (PIVariantTypes::Dir) {s >> v.dir >> v.is_abs; return s;}
|
||||
|
||||
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Store operator.
|
||||
//! \~russian Оператор сохранения.
|
||||
BINARY_STREAM_WRITE(PIVariantTypes::Color) {s << v.rgba; return s;}
|
||||
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Restore operator.
|
||||
//! \~russian Оператор извлечения.
|
||||
BINARY_STREAM_READ (PIVariantTypes::Color) {s >> v.rgba; return s;}
|
||||
|
||||
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Store operator.
|
||||
//! \~russian Оператор сохранения.
|
||||
BINARY_STREAM_WRITE(PIVariantTypes::IODevice) {s << v.prefix << v.mode << v.options << v.props; return s;}
|
||||
|
||||
//! \relatesalso PIBinaryStream
|
||||
//! \~english Restore operator.
|
||||
//! \~russian Оператор извлечения.
|
||||
BINARY_STREAM_READ (PIVariantTypes::IODevice) {s >> v.prefix >> v.mode >> v.options >> v.props; return s;}
|
||||
|
||||
|
||||
#endif // PIVARIANTYPES_H
|
||||
|
||||
@@ -76,19 +76,19 @@ public:
|
||||
|
||||
|
||||
//! Disconneted event
|
||||
EVENT1(disconnected, PIString, reason)
|
||||
EVENT1(disconnected, PIString, reason);
|
||||
|
||||
//! Conneted event
|
||||
EVENT1(connected, PIString, info)
|
||||
EVENT1(connected, PIString, info);
|
||||
|
||||
//! Client event for authorize new server
|
||||
EVENT2(authorize, PIByteArray, info, bool *, ok)
|
||||
EVENT2(authorize, PIByteArray, info, bool *, ok);
|
||||
|
||||
//! Client event for input server password
|
||||
EVENT1(passwordRequest, PIString *, pass)
|
||||
EVENT1(passwordRequest, PIString *, pass);
|
||||
|
||||
//! Server event on check client password
|
||||
EVENT1(passwordCheck, bool, result)
|
||||
EVENT1(passwordCheck, bool, result);
|
||||
|
||||
private:
|
||||
enum Role {Client, Server};
|
||||
|
||||
@@ -96,15 +96,3 @@ PIVector<PIIntrospectionContainers::TypeInfo> PIIntrospectionContainers::getInfo
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
PIByteArray & operator <<(PIByteArray & s, const PIIntrospectionContainers::TypeInfo & v) {
|
||||
s << PIByteArray::RawData(&v, sizeof(PIIntrospectionContainers::_Type)) << v.name;
|
||||
return s;
|
||||
}
|
||||
PIByteArray & operator >>(PIByteArray & s, PIIntrospectionContainers::TypeInfo & v) {
|
||||
s >> PIByteArray::RawData(&v, sizeof(PIIntrospectionContainers::_Type)) >> v.name;
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -65,7 +65,14 @@ public:
|
||||
mutable PISpinlock mutex;
|
||||
};
|
||||
|
||||
PIP_EXPORT PIByteArray & operator <<(PIByteArray & s, const PIIntrospectionContainers::TypeInfo & v);
|
||||
PIP_EXPORT PIByteArray & operator >>(PIByteArray & s, PIIntrospectionContainers::TypeInfo & v);
|
||||
|
||||
BINARY_STREAM_WRITE(PIIntrospectionContainers::TypeInfo) {
|
||||
s << PIMemoryBlock(&v, sizeof(PIIntrospectionContainers::_Type)) << v.name;
|
||||
return s;
|
||||
}
|
||||
BINARY_STREAM_READ(PIIntrospectionContainers::TypeInfo) {
|
||||
s >> PIMemoryBlock(&v, sizeof(PIIntrospectionContainers::_Type)) >> v.name;
|
||||
return s;
|
||||
}
|
||||
|
||||
#endif // PIINTROSPECTION_CONTAINERS_P_H
|
||||
|
||||
@@ -56,7 +56,7 @@ void PIIntrospectionServer::start(const PIString & server_name) {
|
||||
sysmon = PISystemMonitor::Pool::instance()->getByPID(PIProcess::currentPID());
|
||||
if (sysmon) {
|
||||
piCoutObj << "using existing sysmon";
|
||||
CONNECTU(sysmon, deleted, this, sysmonDeleted);
|
||||
CONNECT1(void, PIObject *, sysmon, deleted, this, sysmonDeleted);
|
||||
} else {
|
||||
piCoutObj << "create own sysmon";
|
||||
sysmon = new PISystemMonitor();
|
||||
|
||||
@@ -46,7 +46,7 @@ class PISystemMonitor;
|
||||
# define PIINTROSPECTION_START(name) PIINTROSPECTION_SERVER->start(#name);
|
||||
|
||||
class PIP_EXPORT PIIntrospectionServer: public PIPeer {
|
||||
PIOBJECT_SUBCLASS(PIIntrospectionServer, PIPeer)
|
||||
PIOBJECT_SUBCLASS(PIIntrospectionServer, PIPeer);
|
||||
public:
|
||||
static PIIntrospectionServer * instance();
|
||||
|
||||
@@ -55,7 +55,7 @@ public:
|
||||
private:
|
||||
PIIntrospectionServer();
|
||||
~PIIntrospectionServer();
|
||||
NO_COPY_CLASS(PIIntrospectionServer)
|
||||
NO_COPY_CLASS(PIIntrospectionServer);
|
||||
|
||||
PIString genName();
|
||||
virtual void dataReceived(const PIString & from, const PIByteArray & data);
|
||||
|
||||
@@ -77,82 +77,6 @@ PIVector<PIIntrospection::ObjectInfo> PIIntrospection::getObjects() {
|
||||
}
|
||||
|
||||
|
||||
PIByteArray & operator <<(PIByteArray & b, const PIIntrospection::RequiredInfo & v) {
|
||||
PIChunkStream cs;
|
||||
cs.add(1, v.types);
|
||||
b << cs.data();
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
PIByteArray & operator >>(PIByteArray & b, PIIntrospection::RequiredInfo & v) {
|
||||
PIByteArray csba; b >> csba;
|
||||
PIChunkStream cs(csba);
|
||||
while (!cs.atEnd()) {
|
||||
switch (cs.read()) {
|
||||
case 1: cs.get(v.types); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
PIByteArray & operator <<(PIByteArray & b, const PIIntrospection::ProcessInfo & v) {
|
||||
PIChunkStream cs;
|
||||
cs.add(1, v.architecture).add(2, v.execCommand).add(3, v.execDateTime).add(4, v.hostname).add(5, v.OS_name)
|
||||
.add(6, v.OS_version).add(7, v.processorsCount).add(8, v.user).add(9, v.build_options);
|
||||
b << cs.data();
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
PIByteArray & operator >>(PIByteArray & b, PIIntrospection::ProcessInfo & v) {
|
||||
PIByteArray csba; b >> csba;
|
||||
PIChunkStream cs(csba);
|
||||
while (!cs.atEnd()) {
|
||||
switch (cs.read()) {
|
||||
case 1: cs.get(v.architecture); break;
|
||||
case 2: cs.get(v.execCommand); break;
|
||||
case 3: cs.get(v.execDateTime); break;
|
||||
case 4: cs.get(v.hostname); break;
|
||||
case 5: cs.get(v.OS_name); break;
|
||||
case 6: cs.get(v.OS_version); break;
|
||||
case 7: cs.get(v.processorsCount); break;
|
||||
case 8: cs.get(v.user); break;
|
||||
case 9: cs.get(v.build_options); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
PIByteArray & operator <<(PIByteArray & b, const PIIntrospection::ObjectInfo & v) {
|
||||
PIChunkStream cs;
|
||||
cs.add(1, v.classname).add(2, v.name).add(3, v.parents).add(4, v.properties).add(5, v.queued_events);
|
||||
b << cs.data();
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
PIByteArray & operator >>(PIByteArray & b, PIIntrospection::ObjectInfo & v) {
|
||||
PIByteArray csba; b >> csba;
|
||||
PIChunkStream cs(csba);
|
||||
while (!cs.atEnd()) {
|
||||
switch (cs.read()) {
|
||||
case 1: cs.get(v.classname); break;
|
||||
case 2: cs.get(v.name); break;
|
||||
case 3: cs.get(v.parents); break;
|
||||
case 4: cs.get(v.properties); break;
|
||||
case 5: cs.get(v.queued_events); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
PIByteArray PIIntrospection::packInfo() {
|
||||
@@ -216,8 +140,8 @@ PIByteArray PIIntrospection::packThreads() {
|
||||
PIMap<PIThread*, PIIntrospectionThreads::ThreadInfo> & tm(p->threads);
|
||||
auto it = tm.makeIterator();
|
||||
while (it.next()) {
|
||||
it.valueRef().classname = PIStringAscii(it.key()->className());
|
||||
it.valueRef().name = it.key()->name();
|
||||
it.value().classname = PIStringAscii(it.key()->className());
|
||||
it.value().name = it.key()->name();
|
||||
}
|
||||
ret << tm.values();
|
||||
p->mutex.unlock();
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "piintrospection_containers_p.h"
|
||||
#include "piintrospection_threads.h"
|
||||
#include "piintrospection_threads_p.h"
|
||||
#include "pichunkstream.h"
|
||||
#include "pisystemmonitor.h"
|
||||
|
||||
|
||||
@@ -91,13 +92,72 @@ public:
|
||||
|
||||
};
|
||||
|
||||
PIP_EXPORT PIByteArray & operator <<(PIByteArray & b, const PIIntrospection::RequiredInfo & v);
|
||||
PIP_EXPORT PIByteArray & operator >>(PIByteArray & b, PIIntrospection::RequiredInfo & v);
|
||||
|
||||
PIP_EXPORT PIByteArray & operator <<(PIByteArray & b, const PIIntrospection::ProcessInfo & v);
|
||||
PIP_EXPORT PIByteArray & operator >>(PIByteArray & b, PIIntrospection::ProcessInfo & v);
|
||||
BINARY_STREAM_WRITE(PIIntrospection::RequiredInfo) {
|
||||
PIChunkStream cs;
|
||||
cs.add(1, v.types);
|
||||
s << cs.data();
|
||||
return s;
|
||||
}
|
||||
BINARY_STREAM_READ(PIIntrospection::RequiredInfo) {
|
||||
PIByteArray csba; s >> csba;
|
||||
PIChunkStream cs(csba);
|
||||
while (!cs.atEnd()) {
|
||||
switch (cs.read()) {
|
||||
case 1: cs.get(v.types); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
PIP_EXPORT PIByteArray & operator <<(PIByteArray & b, const PIIntrospection::ObjectInfo & v);
|
||||
PIP_EXPORT PIByteArray & operator >>(PIByteArray & b, PIIntrospection::ObjectInfo & v);
|
||||
BINARY_STREAM_WRITE(PIIntrospection::ProcessInfo) {
|
||||
PIChunkStream cs;
|
||||
cs.add(1, v.architecture).add(2, v.execCommand).add(3, v.execDateTime).add(4, v.hostname).add(5, v.OS_name)
|
||||
.add(6, v.OS_version).add(7, v.processorsCount).add(8, v.user).add(9, v.build_options);
|
||||
s << cs.data();
|
||||
return s;
|
||||
}
|
||||
BINARY_STREAM_READ(PIIntrospection::ProcessInfo) {
|
||||
PIByteArray csba; s >> csba;
|
||||
PIChunkStream cs(csba);
|
||||
while (!cs.atEnd()) {
|
||||
switch (cs.read()) {
|
||||
case 1: cs.get(v.architecture); break;
|
||||
case 2: cs.get(v.execCommand); break;
|
||||
case 3: cs.get(v.execDateTime); break;
|
||||
case 4: cs.get(v.hostname); break;
|
||||
case 5: cs.get(v.OS_name); break;
|
||||
case 6: cs.get(v.OS_version); break;
|
||||
case 7: cs.get(v.processorsCount); break;
|
||||
case 8: cs.get(v.user); break;
|
||||
case 9: cs.get(v.build_options); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
BINARY_STREAM_WRITE(PIIntrospection::ObjectInfo) {
|
||||
PIChunkStream cs;
|
||||
cs.add(1, v.classname).add(2, v.name).add(3, v.parents).add(4, v.properties).add(5, v.queued_events);
|
||||
s << cs.data();
|
||||
return s;
|
||||
}
|
||||
BINARY_STREAM_READ(PIIntrospection::ObjectInfo) {
|
||||
PIByteArray csba; s >> csba;
|
||||
PIChunkStream cs(csba);
|
||||
while (!cs.atEnd()) {
|
||||
switch (cs.read()) {
|
||||
case 1: cs.get(v.classname); break;
|
||||
case 2: cs.get(v.name); break;
|
||||
case 3: cs.get(v.parents); break;
|
||||
case 4: cs.get(v.properties); break;
|
||||
case 5: cs.get(v.queued_events); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
#endif // PIINTROSPECTION_SERVER_P_H
|
||||
|
||||
@@ -81,19 +81,3 @@ void PIIntrospectionThreads::threadRunDone(PIThread * t, ullong us) {
|
||||
ThreadInfo & ti(threads[t]);
|
||||
ti.run_us = (ti.run_us * 0.8) + (us * 0.2); /// WARNING
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
PIByteArray & operator <<(PIByteArray & b, const PIIntrospectionThreads::ThreadInfo & v) {
|
||||
b << v.classname << v.name << v.id << int(v.state) << v.priority << v.delay << v.run_us << v.run_count;
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
PIByteArray & operator >>(PIByteArray & b, PIIntrospectionThreads::ThreadInfo & v) {
|
||||
int st(0);
|
||||
b >> v.classname >> v.name >> v.id >> st >> v.priority >> v.delay >> v.run_us >> v.run_count;
|
||||
v.state = (PIIntrospectionThreads::ThreadState)st;
|
||||
return b;
|
||||
}
|
||||
|
||||
@@ -57,7 +57,14 @@ public:
|
||||
|
||||
};
|
||||
|
||||
PIP_EXPORT PIByteArray & operator <<(PIByteArray & b, const PIIntrospectionThreads::ThreadInfo & v);
|
||||
PIP_EXPORT PIByteArray & operator >>(PIByteArray & b, PIIntrospectionThreads::ThreadInfo & v);
|
||||
|
||||
BINARY_STREAM_WRITE(PIIntrospectionThreads::ThreadInfo) {
|
||||
s << v.classname << v.name << v.id << v.state << v.priority << v.delay << v.run_us << v.run_count;
|
||||
return s;
|
||||
}
|
||||
BINARY_STREAM_READ(PIIntrospectionThreads::ThreadInfo) {
|
||||
s >> v.classname >> v.name >> v.id >> v.state >> v.priority >> v.delay >> v.run_us >> v.run_count;
|
||||
return s;
|
||||
}
|
||||
|
||||
#endif // PIINTROSPECTION_THREADS_P_H
|
||||
|
||||
@@ -61,6 +61,7 @@ PIBinaryLog::PIBinaryLog() {
|
||||
is_started = is_indexed = is_pause = false;
|
||||
current_index = -1;
|
||||
log_size = 0;
|
||||
f_new_path = nullptr;
|
||||
setPlaySpeed(1.);
|
||||
setDefaultID(1);
|
||||
setPlaySpeed(1.0);
|
||||
@@ -100,7 +101,8 @@ bool PIBinaryLog::openDevice() {
|
||||
return false;
|
||||
}
|
||||
if (path().isEmpty() && mode_ == WriteOnly) {
|
||||
setPath(getLogfilePath());
|
||||
if (f_new_path) setPath(f_new_path());
|
||||
else setPath(getLogfilePath(logDir(), filePrefix()));
|
||||
}
|
||||
if (path().isEmpty() && mode_ == ReadOnly) {
|
||||
PIDir ld(logDir());
|
||||
@@ -168,7 +170,7 @@ bool PIBinaryLog::closeDevice() {
|
||||
}
|
||||
|
||||
|
||||
bool PIBinaryLog::threadedRead(uchar *readed, int size) {
|
||||
bool PIBinaryLog::threadedRead(const uchar *readed, ssize_t size) {
|
||||
// piCout << "binlog threaded read";
|
||||
if (!canRead() || isEnd()) return PIIODevice::threadedRead(readed, size);
|
||||
is_thread_ok = false;
|
||||
@@ -243,18 +245,18 @@ bool PIBinaryLog::threadedRead(uchar *readed, int size) {
|
||||
}
|
||||
|
||||
|
||||
PIString PIBinaryLog::getLogfilePath() const {
|
||||
PIDir dir(logDir());
|
||||
PIString PIBinaryLog::getLogfilePath(const PIString & log_dir, const PIString & prefix) {
|
||||
PIDir dir(log_dir);
|
||||
dir.setDir(dir.absolutePath());
|
||||
if (!dir.isExists()) {
|
||||
piCoutObj << "Creating directory" << dir.path();
|
||||
piCout << "[PIBinaryLog]" << "Creating directory" << dir.path();
|
||||
dir.make(true);
|
||||
}
|
||||
PIString npath = logDir() + "/" + filePrefix() + PIDateTime::current().toString("yyyy_MM_dd__hh_mm_ss");
|
||||
PIString npath = log_dir + PIDir::separator + prefix + PIDateTime::current().toString("yyyy_MM_dd__hh_mm_ss");
|
||||
PIString cnpath = npath + ".binlog";
|
||||
int i = 1;
|
||||
while (PIFile::isExists(cnpath)) {
|
||||
cnpath = npath + "_" + PIString::fromNumber(i) + ".binlog";
|
||||
cnpath = npath + '_' + PIString::fromNumber(i) + ".binlog";
|
||||
i++;
|
||||
}
|
||||
return cnpath;
|
||||
@@ -262,12 +264,14 @@ PIString PIBinaryLog::getLogfilePath() const {
|
||||
|
||||
PIString PIBinaryLog::createNewFile() {
|
||||
if (!file.close()) return PIString();
|
||||
PIString cnpath = getLogfilePath();
|
||||
PIString cnpath;
|
||||
if (f_new_path) cnpath = f_new_path();
|
||||
else cnpath = getLogfilePath(logDir(), filePrefix());
|
||||
if (open(cnpath, PIIODevice::WriteOnly)) {
|
||||
newFile(file.path());
|
||||
return file.path();
|
||||
}
|
||||
piCoutObj << "Can't create new file, maybe LogDir is invalid.";
|
||||
piCoutObj << "Can't create new file, maybe LogDir" << ("\"" + logDir() + "\"") << "is invalid.";
|
||||
return PIString();
|
||||
}
|
||||
|
||||
@@ -276,7 +280,7 @@ void PIBinaryLog::createNewFile(const PIString &path) {
|
||||
if (open(path, PIIODevice::WriteOnly)) {
|
||||
newFile(file.path());
|
||||
}
|
||||
else piCoutObj << "Can't create new file, maybe path is invalid.";
|
||||
else piCoutObj << "Can't create new file, maybe path" << ("\"" + path + "\"") << "is invalid.";
|
||||
}
|
||||
|
||||
|
||||
@@ -295,13 +299,20 @@ void PIBinaryLog::setPause(bool pause) {
|
||||
int PIBinaryLog::writeBinLog(int id, const void *data, int size) {
|
||||
if (size <= 0 || !canWrite()) return -1;
|
||||
if (id == 0) {
|
||||
piCoutObj << "Error: can`t write with id = 0!";
|
||||
piCoutObj << "Error: can`t write with id = 0! Id must be > 0";
|
||||
return -1;
|
||||
}
|
||||
if (is_pause) return 0;
|
||||
logmutex.lock();
|
||||
PIByteArray logdata;
|
||||
logdata << id << size << (PISystemTime::current() - startlogtime) << PIMemoryBlock(data, size);
|
||||
int res = file.write(logdata.data(), logdata.size());
|
||||
file.flush();
|
||||
write_count++;
|
||||
log_size = file.size();
|
||||
switch (split_mode) {
|
||||
case SplitSize:
|
||||
if (file.size() > split_size) createNewFile();
|
||||
if (log_size > split_size) createNewFile();
|
||||
break;
|
||||
case SplitTime:
|
||||
if ((PISystemTime::current() - startlogtime) > split_time) createNewFile();
|
||||
@@ -311,16 +322,6 @@ int PIBinaryLog::writeBinLog(int id, const void *data, int size) {
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
if (is_pause) {
|
||||
logmutex.unlock();
|
||||
return 0;
|
||||
}
|
||||
PIByteArray logdata;
|
||||
logdata << id << size << (PISystemTime::current() - startlogtime) << PIByteArray::RawData(data, size);
|
||||
int res = file.write(logdata.data(), logdata.size());
|
||||
file.flush();
|
||||
write_count++;
|
||||
log_size = file.size();
|
||||
logmutex.unlock();
|
||||
if (res > 0) return size;
|
||||
else return res;
|
||||
@@ -330,7 +331,7 @@ int PIBinaryLog::writeBinLog(int id, const void *data, int size) {
|
||||
int PIBinaryLog::writeBinLog_raw(int id, const PISystemTime &time, const void *data, int size) {
|
||||
if (size <= 0 || !canWrite()) return -1;
|
||||
PIByteArray logdata;
|
||||
logdata << id << size << time << PIByteArray::RawData(data, size);
|
||||
logdata << id << size << time << PIMemoryBlock(data, size);
|
||||
logmutex.lock();
|
||||
int res = file.write(logdata.data(), logdata.size());
|
||||
file.flush();
|
||||
@@ -400,7 +401,7 @@ PIByteArray PIBinaryLog::getHeader() {
|
||||
}
|
||||
|
||||
|
||||
int PIBinaryLog::readDevice(void *read_to, int max_size) {
|
||||
ssize_t PIBinaryLog::readDevice(void *read_to, ssize_t max_size) {
|
||||
PIMutexLocker _ml(logmutex);
|
||||
if (lastrecord.id == -1 || isEnd()) return 0;
|
||||
if(!is_thread_ok && lastrecord.id > 0) return lastrecord.data.size();
|
||||
@@ -408,8 +409,9 @@ int PIBinaryLog::readDevice(void *read_to, int max_size) {
|
||||
if (max_size <= 0 || read_to == 0) return -1;
|
||||
BinLogRecord br;
|
||||
br.id = 0;
|
||||
if (filterID.isEmpty()) br = readRecord();
|
||||
else {
|
||||
if (filterID.isEmpty()) {
|
||||
br = readRecord();
|
||||
} else {
|
||||
while (!filterID.contains(br.id) && !isEnd()) br = readRecord();
|
||||
}
|
||||
if (br.id == -1) {
|
||||
@@ -421,13 +423,18 @@ int PIBinaryLog::readDevice(void *read_to, int max_size) {
|
||||
piCoutObj << "Read record error";
|
||||
return -1;
|
||||
}
|
||||
int sz = piMini(max_size, br.data.size());
|
||||
ssize_t sz = piMini(max_size, br.data.size());
|
||||
if (sz < br.data.size_s()) piCoutObj << "too small read buffer:" << max_size << ", data size:" << br.data.size();
|
||||
memcpy(read_to, br.data.data(), sz);
|
||||
return sz;
|
||||
}
|
||||
|
||||
|
||||
ssize_t PIBinaryLog::writeDevice(const void * data, ssize_t size) {
|
||||
return writeBinLog(default_id, data, size);
|
||||
}
|
||||
|
||||
|
||||
void PIBinaryLog::restart() {
|
||||
bool th = isRunning();
|
||||
if (th) stopThreadedRead();
|
||||
@@ -543,15 +550,33 @@ void PIBinaryLog::parseLog(PIFile * f, PIBinaryLog::BinLogInfo * info, PIVector<
|
||||
}
|
||||
uchar read_sig[PIBINARYLOG_SIGNATURE_SIZE];
|
||||
for (uint i=0; i<PIBINARYLOG_SIGNATURE_SIZE; i++) read_sig[i] = 0;
|
||||
bool ok = true;
|
||||
if (f->read(read_sig, PIBINARYLOG_SIGNATURE_SIZE) < 0) {if (info) info->records_count = -1; ok = false;}
|
||||
for (uint i=0; i<PIBINARYLOG_SIGNATURE_SIZE; i++)
|
||||
if (read_sig[i] != binlog_sig[i]) {if (info) info->records_count = -2; ok = false;}
|
||||
if (f->read(read_sig, PIBINARYLOG_SIGNATURE_SIZE) < 0) {
|
||||
if (info) info->records_count = -1;
|
||||
return;
|
||||
}
|
||||
for (uint i=0; i<PIBINARYLOG_SIGNATURE_SIZE; i++) {
|
||||
if (read_sig[i] != binlog_sig[i]) {
|
||||
if (info) info->records_count = -2;
|
||||
return;
|
||||
}
|
||||
}
|
||||
uchar read_version = 0;
|
||||
if (f->read(&read_version, 1) < 0) {if (info) info->records_count = -3; ok = false;}
|
||||
if (read_version == 0) {if (info) info->records_count = -4; ok = false;}
|
||||
if (read_version < PIBINARYLOG_VERSION_OLD) {if (info) info->records_count = -5; ok = false;}
|
||||
if (read_version > PIBINARYLOG_VERSION) {if (info) info->records_count = -6; ok = false;}
|
||||
if (f->read(&read_version, 1) < 0) {
|
||||
if (info) info->records_count = -3;
|
||||
return;
|
||||
}
|
||||
if (read_version == 0) {
|
||||
if (info) info->records_count = -4;
|
||||
return;
|
||||
}
|
||||
if (read_version < PIBINARYLOG_VERSION_OLD) {
|
||||
if (info) info->records_count = -5;
|
||||
return;
|
||||
}
|
||||
if (read_version > PIBINARYLOG_VERSION) {
|
||||
if (info) info->records_count = -6;
|
||||
return;
|
||||
}
|
||||
if (read_version == PIBINARYLOG_VERSION) {
|
||||
uint32_t sz = 0;
|
||||
f->read(&sz, 4);
|
||||
@@ -559,9 +584,10 @@ void PIBinaryLog::parseLog(PIFile * f, PIBinaryLog::BinLogInfo * info, PIVector<
|
||||
info->user_header = f->read(sz);
|
||||
}
|
||||
}
|
||||
if (!ok) return;
|
||||
PIByteArray ba;
|
||||
BinLogRecord br;
|
||||
br.id = 0;
|
||||
br.size = 0;
|
||||
bool first = true;
|
||||
size_t hdr_size = sizeof(BinLogRecord) - sizeof(PIByteArray);
|
||||
ba.resize(hdr_size);
|
||||
@@ -570,15 +596,16 @@ void PIBinaryLog::parseLog(PIFile * f, PIBinaryLog::BinLogInfo * info, PIVector<
|
||||
{
|
||||
if (f->read(ba.data(), ba.size()) > 0) {
|
||||
ba >> br.id >> br.size >> br.timestamp;
|
||||
} else
|
||||
break;
|
||||
if (info->log_size - f->pos() >= br.size)
|
||||
f->seek(f->pos() + br.size);
|
||||
else
|
||||
break;
|
||||
} else break;
|
||||
if (info) {
|
||||
if (info->log_size - f->pos() >= br.size) {
|
||||
f->seek(f->pos() + br.size);
|
||||
}
|
||||
}
|
||||
else break;
|
||||
}
|
||||
if (br.id > 0) {
|
||||
if (info) {
|
||||
if (index) {
|
||||
BinLogIndex bl_ind;
|
||||
bl_ind.id = br.id;
|
||||
bl_ind.data_size = br.size;
|
||||
@@ -631,14 +658,22 @@ PIBinaryLog::BinLogInfo PIBinaryLog::getLogInfo(const PIString & path) {
|
||||
|
||||
bool PIBinaryLog::cutBinLog(const PIBinaryLog::BinLogInfo & src, const PIString & dst, int from, int to) {
|
||||
PIBinaryLog slog;
|
||||
if (!slog.open(src.path, PIIODevice::ReadOnly)) return false;
|
||||
if (!slog.open(src.path, PIIODevice::ReadOnly)) {
|
||||
piCout << "[PIBinaryLog]" << "Error, can't open" << src.path;
|
||||
return false;
|
||||
}
|
||||
PIVector<int> ids = src.records.keys();
|
||||
slog.seekTo(from);
|
||||
PIBinaryLog dlog;
|
||||
dlog.createNewFile(dst);
|
||||
if (!dlog.isOpened()) {
|
||||
piCout << "[PIBinaryLog]" << "Error, can't create" << dst;
|
||||
return false;
|
||||
}
|
||||
bool first = true;
|
||||
BinLogRecord br;
|
||||
PISystemTime st;
|
||||
PITimeMeasurer tm;
|
||||
while (!slog.isEnd() && ((slog.pos() <= to) || to < 0)) {
|
||||
br = slog.readRecord();
|
||||
if (first) {
|
||||
@@ -646,9 +681,74 @@ bool PIBinaryLog::cutBinLog(const PIBinaryLog::BinLogInfo & src, const PIString
|
||||
first = false;
|
||||
}
|
||||
if (ids.contains(br.id)) {
|
||||
dlog.writeBinLog_raw(br.id, br.timestamp - st, br.data);
|
||||
if (dlog.writeBinLog_raw(br.id, br.timestamp - st, br.data) <= 0) {
|
||||
piCout << "[PIBinaryLog]" << "Error, can't write to file" << dst;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (tm.elapsed_s() > 1) {
|
||||
tm.reset();
|
||||
piCout << "[PIBinaryLog]" << "process" << PITime::fromSystemTime(br.timestamp).toString();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PIBinaryLog::joinBinLogsSerial(const PIStringList & src, const PIString & dst, std::function<bool (const PIString &, PISystemTime)> progress) {
|
||||
PIBinaryLog slog;
|
||||
PIBinaryLog dlog;
|
||||
PISystemTime dtime;
|
||||
PISystemTime lt;
|
||||
PITimeMeasurer tm;
|
||||
bool first = true;
|
||||
for (const PIString & fn : src) {
|
||||
if (!slog.open(fn, PIIODevice::ReadOnly)) {
|
||||
piCout << "[PIBinaryLog]" << "Error, can't open" << fn;
|
||||
return false;
|
||||
}
|
||||
if (first) {
|
||||
first = false;
|
||||
dlog.setHeader(slog.getHeader());
|
||||
dlog.createNewFile(dst);
|
||||
if (!dlog.isOpened()) {
|
||||
piCout << "[PIBinaryLog]" << "Error, can't create" << dst;
|
||||
return false;
|
||||
}
|
||||
piCout << "[PIBinaryLog]" << "Start join binlogs to" << dst;
|
||||
} else {
|
||||
dtime = lt;
|
||||
}
|
||||
tm.reset();
|
||||
BinLogRecord br;
|
||||
PISystemTime st;
|
||||
while (!slog.isEnd()) {
|
||||
br = slog.readRecord();
|
||||
if (br.data.isEmpty() || br.id < 1) continue;
|
||||
st = br.timestamp;
|
||||
lt = dtime + br.timestamp;
|
||||
if (dlog.writeBinLog_raw(br.id, lt, br.data) <= 0) {
|
||||
piCout << "[PIBinaryLog]" << "Error, can't write to file" << dst;
|
||||
return false;
|
||||
}
|
||||
if (tm.elapsed_s() > 0.1) {
|
||||
tm.reset();
|
||||
if (progress) {
|
||||
if (!progress(fn, lt)) {
|
||||
slog.close();
|
||||
dlog.close();
|
||||
PIFile::remove(dlog.path());
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
piCout << "[PIBinaryLog]" << "process" << PITime::fromSystemTime(lt).toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
slog.close();
|
||||
//piCout << "[PIBinaryLog]" << "complete" << fn;
|
||||
}
|
||||
piCout << "[PIBinaryLog]" << "Finish join binlogs, total time" << PITime::fromSystemTime(lt).toString();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -728,19 +828,19 @@ bool PIBinaryLog::seek(llong filepos) {
|
||||
|
||||
PIString PIBinaryLog::constructFullPathDevice() const {
|
||||
PIString ret;
|
||||
ret << logDir() << ":" << filePrefix() << ":" << defaultID() << ":";
|
||||
ret += logDir() + ":" + filePrefix() + ":" + PIString::fromNumber(defaultID()) + ":";
|
||||
switch (play_mode) {
|
||||
case PlayRealTime:
|
||||
ret << "RT";
|
||||
ret += "RT";
|
||||
break;
|
||||
case PlayVariableSpeed:
|
||||
ret << PIString::fromNumber(playSpeed()) << "X";
|
||||
ret += PIString::fromNumber(playSpeed()) + "X";
|
||||
break;
|
||||
case PlayStaticDelay:
|
||||
ret << PIString::fromNumber(playDelay().toMilliseconds()) << "M";
|
||||
ret += PIString::fromNumber(playDelay().toMilliseconds()) + "M";
|
||||
break;
|
||||
default:
|
||||
ret << "RT";
|
||||
ret += "RT";
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
|
||||
@@ -28,10 +28,13 @@
|
||||
|
||||
#include "pifile.h"
|
||||
|
||||
|
||||
//! \ingroup IO
|
||||
//! \~\brief
|
||||
//! \~english Binary log
|
||||
//! \~russian Бинарный лог
|
||||
class PIP_EXPORT PIBinaryLog: public PIIODevice
|
||||
{
|
||||
PIIODEVICE(PIBinaryLog, "binlog")
|
||||
PIIODEVICE(PIBinaryLog, "binlog");
|
||||
public:
|
||||
explicit PIBinaryLog();
|
||||
virtual ~PIBinaryLog();
|
||||
@@ -165,6 +168,11 @@ public:
|
||||
//! Set pause while playing via \a threadedRead or writing via write
|
||||
void setPause(bool pause);
|
||||
|
||||
//! Set function wich returns new binlog file path when using split mode.
|
||||
//! Overrides internal file path generator (logdir() + prefix() + current_time()).
|
||||
//! To restore internal file path generator set this function to "nullptr".
|
||||
void setFuncGetNewFilePath(std::function<PIString()> f) {f_new_path = f;}
|
||||
|
||||
//! Write one record to BinLog file, with ID = id, id must be greather than 0
|
||||
int writeBinLog(int id, PIByteArray data) {return writeBinLog(id, data.data(), data.size_s());}
|
||||
|
||||
@@ -278,28 +286,33 @@ public:
|
||||
//! \}
|
||||
|
||||
EVENT_HANDLER(PIString, createNewFile);
|
||||
EVENT(fileEnd)
|
||||
EVENT(fileError)
|
||||
EVENT1(newFile, const PIString &, filename)
|
||||
EVENT1(posChanged, int, pos)
|
||||
EVENT(fileEnd);
|
||||
EVENT(fileError);
|
||||
EVENT1(newFile, const PIString &, filename);
|
||||
EVENT1(posChanged, int, pos);
|
||||
|
||||
//! Get binlog info and statistic
|
||||
static BinLogInfo getLogInfo(const PIString & path);
|
||||
|
||||
//! Create new binlog from part of "src" with allowed IDs and "from" to "to" file position
|
||||
static bool cutBinLog(const BinLogInfo & src, const PIString & dst, int from, int to);
|
||||
|
||||
//! Create new binlog from serial splitted binlogs "src"
|
||||
static bool joinBinLogsSerial(const PIStringList & src, const PIString & dst, std::function<bool (const PIString &, PISystemTime)> progress = nullptr);
|
||||
|
||||
protected:
|
||||
PIString constructFullPathDevice() const;
|
||||
void configureFromFullPathDevice(const PIString & full_path);
|
||||
PIPropertyStorage constructVariantDevice() const;
|
||||
void configureFromVariantDevice(const PIPropertyStorage & d);
|
||||
int readDevice(void *read_to, int max_size);
|
||||
int writeDevice(const void * data, int size) {return writeBinLog(default_id, data, size);}
|
||||
bool openDevice();
|
||||
bool closeDevice();
|
||||
void propertyChanged(const char * s);
|
||||
bool threadedRead(uchar *readed, int size);
|
||||
void threadedReadTerminated() {pausemutex.unlock();}
|
||||
DeviceInfoFlags deviceInfoFlags() const {return PIIODevice::Reliable;}
|
||||
PIString constructFullPathDevice() const override;
|
||||
void configureFromFullPathDevice(const PIString & full_path) override;
|
||||
PIPropertyStorage constructVariantDevice() const override;
|
||||
void configureFromVariantDevice(const PIPropertyStorage & d) override;
|
||||
ssize_t readDevice(void *read_to, ssize_t max_size) override;
|
||||
ssize_t writeDevice(const void * data, ssize_t size) override;
|
||||
bool openDevice() override;
|
||||
bool closeDevice() override;
|
||||
void propertyChanged(const char * s) override;
|
||||
bool threadedRead(const uchar *readed, ssize_t size) override;
|
||||
void threadedReadTerminated() override {pausemutex.unlock();}
|
||||
DeviceInfoFlags deviceInfoFlags() const override {return PIIODevice::Reliable;}
|
||||
|
||||
private:
|
||||
struct PIP_EXPORT BinLogRecord {
|
||||
@@ -314,7 +327,7 @@ private:
|
||||
BinLogRecord readRecord();
|
||||
static void parseLog(PIFile *f, BinLogInfo *info, PIVector<BinLogIndex> * index);
|
||||
void moveIndex(int i);
|
||||
PIString getLogfilePath() const;
|
||||
static PIString getLogfilePath(const PIString & log_dir, const PIString & prefix);
|
||||
|
||||
PIVector<BinLogIndex> index;
|
||||
PIMap<llong, int> index_pos;
|
||||
@@ -331,42 +344,43 @@ private:
|
||||
int write_count, split_count, default_id, current_index;
|
||||
bool is_started, is_thread_ok, is_indexed, rapid_start, is_pause;
|
||||
PIByteArray user_header;
|
||||
std::function<PIString()> f_new_path;
|
||||
};
|
||||
|
||||
//! \relatesalso PICout \brief Output operator PIBinaryLog::BinLogInfo to PICout
|
||||
inline PICout operator <<(PICout s, const PIBinaryLog::BinLogInfo & bi) {
|
||||
s.space();
|
||||
s.setControl(0, true);
|
||||
s.saveAndSetControls(0);
|
||||
s << "[PIBinaryLog] " << bi.path << "\n";
|
||||
if (bi.log_size < 0) {
|
||||
s << "invalid file path";
|
||||
s.restoreControl();
|
||||
s.restoreControls();
|
||||
return s;
|
||||
}
|
||||
if (bi.log_size == 0) {
|
||||
s << "Invalid empty file";
|
||||
s.restoreControl();
|
||||
s.restoreControls();
|
||||
return s;
|
||||
} if (bi.records_count < 0 && bi.records_count > -4) {
|
||||
s << "Invalid file or corrupted signature";
|
||||
s.restoreControl();
|
||||
s.restoreControls();
|
||||
return s;
|
||||
}
|
||||
if (bi.records_count < -3) {
|
||||
s << "Invalid binlog version";
|
||||
s.restoreControl();
|
||||
s.restoreControls();
|
||||
return s;
|
||||
}
|
||||
s << "read records " << bi.records_count << " in " << bi.records.size() << " types, log size " << bi.log_size;
|
||||
s << "\nlog start " << bi.start_time << " , log end " << bi.end_time;
|
||||
PIVector<int> keys = bi.records.keys();
|
||||
piForeachC(int i, keys) {
|
||||
const PIBinaryLog::BinLogRecordInfo &bri(bi.records[i]);
|
||||
for (int i : keys) {
|
||||
PIBinaryLog::BinLogRecordInfo bri = bi.records.at(i);
|
||||
s << "\n record id " << bri.id << " , count " << bri.count;
|
||||
s << "\n record start " << bri.start_time << " , end " << bri.end_time;
|
||||
s << "\n record size " << bri.minimum_size << " - " << bri.maximum_size;
|
||||
}
|
||||
s.restoreControl();
|
||||
s.restoreControls();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
@@ -98,13 +98,13 @@ bool PICAN::closeDevice() {
|
||||
}
|
||||
|
||||
|
||||
int PICAN::readDevice(void * read_to, int max_size) {
|
||||
ssize_t PICAN::readDevice(void * read_to, ssize_t max_size) {
|
||||
#ifdef PIP_CAN
|
||||
//piCout << "PICAN read";
|
||||
can_frame frame;
|
||||
int ret = 0;
|
||||
ssize_t ret = 0;
|
||||
ret = ::read(sock, &frame, sizeof(can_frame));
|
||||
if(ret < 0) {/*piCoutObj << "Error while read CAN frame " << ret;*/ return -1;}
|
||||
if (ret < 0) {/*piCoutObj << "Error while read CAN frame " << ret;*/ return -1;}
|
||||
//piCoutObj << "receive CAN frame Id =" << frame.can_id;
|
||||
memcpy(read_to, frame.data, piMini(frame.can_dlc, max_size));
|
||||
readed_id = frame.can_id;
|
||||
@@ -114,7 +114,7 @@ int PICAN::readDevice(void * read_to, int max_size) {
|
||||
}
|
||||
|
||||
|
||||
int PICAN::writeDevice(const void * data, int max_size) {
|
||||
ssize_t PICAN::writeDevice(const void * data, ssize_t max_size) {
|
||||
#ifdef PIP_CAN
|
||||
//piCout << "PICAN write" << can_id << max_size;
|
||||
if (max_size > 8) {piCoutObj << "Can't send CAN frame bigger than 8 bytes (requested " << max_size << ")!"; return -1;}
|
||||
@@ -122,9 +122,9 @@ int PICAN::writeDevice(const void * data, int max_size) {
|
||||
frame.can_id = can_id;
|
||||
frame.can_dlc = max_size;
|
||||
memcpy(frame.data, data, max_size);
|
||||
int ret = 0;
|
||||
ssize_t ret = 0;
|
||||
ret = ::write(sock, &frame, sizeof(can_frame));
|
||||
if(ret < 0) {piCoutObj << "Error while send CAN frame " << ret; return -1;}
|
||||
if (ret < 0) {piCoutObj << "Error while send CAN frame " << ret; return -1;}
|
||||
return max_size;
|
||||
#endif
|
||||
return 0;
|
||||
@@ -148,7 +148,7 @@ int PICAN::readedCANID() const {
|
||||
|
||||
PIString PICAN::constructFullPathDevice() const {
|
||||
PIString ret;
|
||||
ret << path() << ":" << PIString::fromNumber(CANID(),16);
|
||||
ret += path() + ":" + PIString::fromNumber(CANID(), 16);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
class PIP_EXPORT PICAN: public PIIODevice
|
||||
{
|
||||
PIIODEVICE(PICAN, "can")
|
||||
PIIODEVICE(PICAN, "can");
|
||||
public:
|
||||
explicit PICAN(const PIString & path = PIString(), PIIODevice::DeviceMode mode = PIIODevice::ReadWrite);
|
||||
virtual ~PICAN();
|
||||
@@ -41,15 +41,15 @@ public:
|
||||
int readedCANID() const;
|
||||
|
||||
protected:
|
||||
bool openDevice();
|
||||
bool closeDevice();
|
||||
int readDevice(void * read_to, int max_size);
|
||||
int writeDevice(const void * data, int max_size);
|
||||
PIString constructFullPathDevice() const;
|
||||
void configureFromFullPathDevice(const PIString & full_path);
|
||||
PIPropertyStorage constructVariantDevice() const;
|
||||
void configureFromVariantDevice(const PIPropertyStorage & d);
|
||||
DeviceInfoFlags deviceInfoFlags() const {return PIIODevice::Reliable;}
|
||||
bool openDevice() override;
|
||||
bool closeDevice() override;
|
||||
ssize_t readDevice(void * read_to, ssize_t max_size) override;
|
||||
ssize_t writeDevice(const void * data, ssize_t max_size) override;
|
||||
PIString constructFullPathDevice() const override;
|
||||
void configureFromFullPathDevice(const PIString & full_path) override;
|
||||
PIPropertyStorage constructVariantDevice() const override;
|
||||
void configureFromVariantDevice(const PIPropertyStorage & d) override;
|
||||
DeviceInfoFlags deviceInfoFlags() const override {return PIIODevice::Reliable;}
|
||||
|
||||
private:
|
||||
int sock;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user