1 Commits

Author SHA1 Message Date
9588b48105 PIVector2D - add funcs, optimize, tests, fixes, doxygen (#194)
Reviewed-on: #194
Co-authored-by: andrey.bychkov <andrey@signalmodelling.ru>
Co-committed-by: andrey.bychkov <andrey@signalmodelling.ru>
2026-02-27 23:58:44 +03:00
69 changed files with 2403 additions and 3747 deletions

2
.gitignore vendored
View File

@@ -6,3 +6,5 @@ CMakeLists.txt.user*
/include /include
/release /release
/build* /build*
/AGENTS.md
/plans

View File

@@ -5,8 +5,8 @@ if (POLICY CMP0177)
endif() endif()
project(PIP) project(PIP)
set(PIP_MAJOR 5) set(PIP_MAJOR 5)
set(PIP_MINOR 5) set(PIP_MINOR 6)
set(PIP_REVISION 5) set(PIP_REVISION 0)
set(PIP_SUFFIX ) set(PIP_SUFFIX )
set(PIP_COMPANY SHS) set(PIP_COMPANY SHS)
set(PIP_DOMAIN org.SHS) set(PIP_DOMAIN org.SHS)

115
README.md
View File

@@ -40,3 +40,118 @@ You should add ${<out_var>} to your target.
[🇷🇺 Онлайн документация](https://shstk.ru/pip/html/ru/index.html) [🇷🇺 Онлайн документация](https://shstk.ru/pip/html/ru/index.html)
[🇷🇺 Qt-help](https://shstk.ru/pip/pip_ru.qch) [🇷🇺 Qt-help](https://shstk.ru/pip/pip_ru.qch)
## Основные опции сборки
### Стандартные опции (option())
| Опция | Описание | По умолчанию |
|-------|----------|--------------|
| `ICU` | ICU support для конвертации кодовых страниц | ON (кроме Win/Android/Apple) |
| `STD_IOSTREAM` | Поддержка std::iostream операторов | OFF |
| `INTROSPECTION` | Сборка с интроспекцией | OFF |
| `TESTS` | Сборка тестов | OFF |
| `COVERAGE` | Сборка с информацией о покрытии | OFF |
| `PIP_FFTW_F` | Поддержка FFTW для float | ON |
| `PIP_FFTW_L` | Поддержка FFTW для long double | ON |
| `PIP_FFTW_Q` | Поддержка FFTW для quad double | OFF |
### Опции модулей (PIP_BUILD_*)
| Опция | Модуль |
|-------|--------|
| `PIP_BUILD_CONSOLE` | console |
| `PIP_BUILD_CRYPT` | crypt (требует libsodium) |
| `PIP_BUILD_COMPRESS` | compress (требует zlib) |
| `PIP_BUILD_USB` | usb |
| `PIP_BUILD_FFTW` | fftw |
| `PIP_BUILD_OPENCL` | opencl |
| `PIP_BUILD_IO_UTILS` | io_utils |
| `PIP_BUILD_CLIENT_SERVER` | client_server |
| `PIP_BUILD_CLOUD` | cloud |
| `PIP_BUILD_LUA` | lua |
| `PIP_BUILD_HTTP_CLIENT` | http_client (требует libcurl) |
| `PIP_BUILD_HTTP_SERVER` | http_server (требует libmicrohttpd) |
### Дополнительные переменные
| Переменная | Описание |
|------------|----------|
| `PIP_BUILD_DEBUG` | Сборка debug версии |
| `PIP_FREERTOS` | Режим сборки для FreeRTOS |
| `CROSSTOOLS` | Собрать инструменты кросс-сборки под хостовую систему (pip_cmg, pip_rc, ...) |
| `LOCAL` | Локальная установка (bin/lib/include) |
| `PIP_CONTAINERS_MIN_ALLOC` | Переопределить минимальный размер аллокации контейнеров |
| `PIP_CONTAINERS_MAX_POT_ALLOC` | Переопределить максимальный размер дополнительной аллокации (поддерживает X_KiB, X_MiB) |
### Примеры использования
```bash
# Базовая сборка с тестами
cmake -B build -DTESTS=ON
# Сборка с покрытием и ICU
cmake -B build -DTESTS=ON -DCOVERAGE=ON -DICU=ON
# Отключение отдельных модулей
cmake -B build -DPIP_BUILD_CRYPT=OFF -DPIP_BUILD_OPENCL=OFF
# Переопределение параметров контейнеров
cmake -B build -DPIP_CONTAINERS_MIN_ALLOC=64
# Локальная установка
cmake -B build -DLOCAL=ON
```
## PIP Dependencies
### Встроенные (included in 3rd/)
| Библиотека | Назначение | Модуль PIP |
|------------|------------|------------|
| **PCRE2** | Регулярные выражения | main (internal) |
| **BLAKE2** | Хеширование | main (internal) |
| **SipHash** | Хеширование | main (internal) |
| **Lua** | Lua scripting | lua |
| **LuaBridge** | Lua bindings | lua |
### Внешние (системные)
| Библиотека | Опция | Модуль PIP |
|------------|-------|------------|
| **ICU** | `-DICU=ON` | main (string conversion) |
| **zlib** | `PIP_BUILD_COMPRESS` | compress |
| **libsodium** | `PIP_BUILD_CRYPT` | crypt, io_utils, cloud |
| **libusb** | `PIP_BUILD_USB` | usb |
| **FFTW3** (+ threads) | `PIP_BUILD_FFTW` | fftw |
| **OpenCL** | `PIP_BUILD_OPENCL` | opencl |
| **libmicrohttpd** | `PIP_BUILD_HTTP_SERVER` | http_server |
| **libcurl** | `PIP_BUILD_HTTP_CLIENT` | http_client |
### Опциональные (тесты/документация)
| Инструмент | Назначение |
|------------|------------|
| **Google Test** | Тестирование (fetched automatically) |
| **Doxygen** | Генерация документации |
### Схема зависимостей модулей
```
main (core)
├── PCRE2 (встроен)
├── BLAKE2 (встроен)
├── SipHash (встроен)
└── ICU (опционально)
console → main
compress → zlib
crypt → libsodium
usb → libusb
fftw → FFTW3
opencl → OpenCL
io_utils → [crypt, если доступен]
client_server → io_utils
cloud → io_utils, crypt
lua → Lua (встроен), LuaBridge (встроен)
http_server → libmicrohttpd
http_client → libcurl
```

View File

@@ -1,11 +1,9 @@
//! \file piclientserver_client.h /*! \file piclientserver_client.h
//! \ingroup ClientServer * \ingroup ClientServer
//! \brief * \~\brief
//! \~english Client and ServerClient classes * \~english
//! \~russian Классы Client и ServerClient * \~russian
//! \details */
//! \~english Provides client implementation for connecting to servers and server-side client representation.
//! \~russian Обеспечивает реализацию клиента для подключения к серверам и представление клиента на стороне сервера.
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru

View File

@@ -1,11 +1,9 @@
//! \file piclientserver_client_base.h /*! \file piclientserver_client_base.h
//! \ingroup ClientServer * \ingroup ClientServer
//! \brief * \~\brief
//! \~english Base class for client-server communication * \~english
//! \~russian Базовый класс для клиент-серверного взаимодействия * \~russian
//! \details */
//! \~english Provides base functionality for client-server communication with diagnostics support.
//! \~russian Обеспечивает базовую функциональность для клиент-серверного взаимодействия с поддержкой диагностики.
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
@@ -39,112 +37,77 @@ class Server;
class ClientInterface {}; class ClientInterface {};
//! \brief //! ~english Base class for client-server communication with diagnostics support
//! \~english Base class for client and server-side client //! ~russian Базовый класс для клиент-серверного взаимодействия с поддержкой диагностики
//! \~russian Базовый класс для клиента и клиента на стороне сервера
// template<bool EnableDiagnostics = false> // template<bool EnableDiagnostics = false>
class PIP_CLIENT_SERVER_EXPORT ClientBase { class PIP_CLIENT_SERVER_EXPORT ClientBase {
friend class Server; friend class Server;
NO_COPY_CLASS(ClientBase); NO_COPY_CLASS(ClientBase);
public: public:
//! \brief
//! \~english Constructs ClientBase
//! \~russian Создает ClientBase
ClientBase(); ClientBase();
//! \brief
//! \~english Destructor
//! \~russian Деструктор
virtual ~ClientBase(); virtual ~ClientBase();
//! \brief //! ~english Gets underlying TCP connection
//! \~english Gets underlying TCP connection //! ~russian Возвращает TCP-соединение
//! \~russian Возвращает TCP-соединение
const PIEthernet * getTCP() const { return tcp; } const PIEthernet * getTCP() const { return tcp; }
//! \brief //! ~english Closes the connection
//! \~english Closes the connection //! ~russian Закрывает соединение
//! \~russian Закрывает соединение
void close(); void close();
//! \brief //! ~english Gracefully stops and waits for completion
//! \~english Gracefully stops and waits for completion //! ~russian Плавно останавливает и ожидает завершения
//! \~russian Плавно останавливает и ожидает завершения
void stopAndWait(); void stopAndWait();
//! \brief //! ~english Writes byte array to the connection
//! \~english Writes byte array to the connection //! ~russian Записывает массив байтов в соединение
//! \~russian Записывает массив байтов в соединение
int write(const void * d, const size_t s); int write(const void * d, const size_t s);
//! \brief //! ~english Writes byte array to the connection
//! \~english Writes byte array to the connection //! ~russian Записывает массив байтов в соединение
//! \~russian Записывает массив байтов в соединение
int write(const PIByteArray & ba) { return write(ba.data(), ba.size()); } int write(const PIByteArray & ba) { return write(ba.data(), ba.size()); }
//! \brief //! ~english Enables diagnostics collection
//! \~english Enables diagnostics collection //! ~russian Включает сбор диагностики
//! \~russian Включает сбор диагностики
void enableDiagnostics(); void enableDiagnostics();
//! \brief //! ~english Gets current diagnostics state
//! \~english Gets current diagnostics state //! ~russian Возвращает текущее состояние диагностики
//! \~russian Возвращает текущее состояние диагностики
PIDiagnostics::State diagnostics() const; PIDiagnostics::State diagnostics() const;
//! \brief //! ~english Gets current received packet bytes already received (all bytes count passed in \a receivePacketStart())
//! \~english Gets current received packet bytes already received (all bytes count passed in \a receivePacketStart()) //! ~russian Возвращает сколько байт принимаемого пакета получено (общее количество передается в \a receivePacketStart())
//! \~russian Возвращает сколько байт принимаемого пакета получено (общее количество передается в \a receivePacketStart())
int receivePacketProgress() const; int receivePacketProgress() const;
//! \brief
//! \~english Returns stream configuration
//! \~russian Возвращает конфигурацию стрима
const PIStreamPackerConfig & configuration() const { return stream.configuration(); } const PIStreamPackerConfig & configuration() const { return stream.configuration(); }
//! \brief
//! \~english Returns stream configuration
//! \~russian Возвращает конфигурацию стрима
PIStreamPackerConfig & configuration() { return stream.configuration(); } PIStreamPackerConfig & configuration() { return stream.configuration(); }
//! \brief
//! \~english Sets stream configuration
//! \~russian Устанавливает конфигурацию стрима
void setConfiguration(const PIStreamPackerConfig & config) { stream.setConfiguration(config); } void setConfiguration(const PIStreamPackerConfig & config) { stream.setConfiguration(config); }
protected: protected:
//! \brief //! ~english Called when data is received
//! \~english Called when data is received //! ~russian Вызывается при получении данных
//! \~russian Вызывается при получении данных
virtual void readed(PIByteArray data) {} virtual void readed(PIByteArray data) {}
//! \brief //! ~english Called when connection is established
//! \~english Called when connection is established //! ~russian Вызывается при установке соединения
//! \~russian Вызывается при установке соединения
virtual void connected() {} virtual void connected() {}
//! \brief //! ~english Called when connection is closed
//! \~english Called when connection is closed //! ~russian Вызывается при закрытии соединения
//! \~russian Вызывается при закрытии соединения
virtual void disconnected() {} virtual void disconnected() {}
//! \brief //! ~english Called when packet receiving starts
//! \~english Called when packet receiving starts //! ~russian Вызывается при начале получения пакета
//! \~russian Вызывается при начале получения пакета
virtual void receivePacketStart(int size) {} virtual void receivePacketStart(int size) {}
//! \brief //! ~english Called when packet receiving ends
//! \~english Called when packet receiving ends //! ~russian Вызывается при завершении получения пакета
//! \~russian Вызывается при завершении получения пакета
virtual void receivePacketEnd() {} virtual void receivePacketEnd() {}
//! \brief
//! \~english Initializes the client
//! \~russian Инициализирует клиента
void init(); void init();
bool own_tcp = false; bool own_tcp = false;

View File

@@ -1,11 +1,9 @@
//! \file piclientserver_server.h /*! \file piclientserver_server.h
//! \ingroup ClientServer * \ingroup ClientServer
//! \brief * \~\brief
//! \~english TCP Server * \~english
//! \~russian TCP Сервер * \~russian
//! \details */
//! \~english TCP server implementation for client-server communication.
//! \~russian Реализация TCP сервера для клиент-серверного взаимодействия.
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru

View File

@@ -1,7 +1,7 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Module includes Module includes
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU Lesser General Public License as published by

View File

@@ -1,11 +1,9 @@
//! \file picloudbase.h /*! \file picloudbase.h
//! \ingroup Cloud * \ingroup Cloud
//! \brief * \~\brief
//! \~english Base class for PICloudClient and PICloudServer * \~english Base class for PICloudClient and PICloudServer
//! \~russian Базовый класс для PICloudClient и PICloudServer * \~russian Базовый класс для PICloudClient и PICloudServer
//! \details */
//! \~english Provides common functionality for cloud client and server implementations.
//! \~russian Обеспечивает общую функциональность для реализаций облачного клиента и сервера.
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
PICloud Base - Base class for PICloudClient and PICloud Server PICloud Base - Base class for PICloudClient and PICloud Server
@@ -33,20 +31,10 @@
#include "pistreampacker.h" #include "pistreampacker.h"
//! \brief
//! \~english Base class for cloud client and server
//! \~russian Базовый класс для облачного клиента и сервера
class PIP_CLOUD_EXPORT PICloudBase { class PIP_CLOUD_EXPORT PICloudBase {
public: public:
//! \brief
//! \~english Constructs PICloudBase
//! \~russian Создает PICloudBase
PICloudBase(); PICloudBase();
//! \brief
//! \~english Returns server name
//! \~russian Возвращает имя сервера
PIString serverName() const; PIString serverName() const;
protected: protected:

View File

@@ -1,11 +1,9 @@
//! \file picloudclient.h /*! \file picloudclient.h
//! \ingroup Cloud * \ingroup Cloud
//! \brief * \~\brief
//! \~english PICloud Client * \~english PICloud Client
//! \~russian Клиент PICloud * \~russian Клиент PICloud
//! \details */
//! \~english Client implementation for connecting to PICloud servers over TCP.
//! \~russian Реализация клиента для подключения к серверам PICloud по TCP.
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
PICloud Client PICloud Client
@@ -32,9 +30,7 @@
#include "piconditionvar.h" #include "piconditionvar.h"
//! \brief PICloud client implementation //! \brief PICloudClient
//! \~english PICloud client for connecting to servers
//! \~russian Клиент PICloud для подключения к серверам
class PIP_CLOUD_EXPORT PICloudClient class PIP_CLOUD_EXPORT PICloudClient
: public PIIODevice : public PIIODevice
@@ -42,75 +38,23 @@ class PIP_CLOUD_EXPORT PICloudClient
PIIODEVICE(PICloudClient, ""); PIIODEVICE(PICloudClient, "");
public: public:
//! \brief
//! \~english Constructs PICloudClient
//! \~russian Создает PICloudClient
explicit PICloudClient(const PIString & path = PIString(), PIIODevice::DeviceMode mode = PIIODevice::ReadWrite); explicit PICloudClient(const PIString & path = PIString(), PIIODevice::DeviceMode mode = PIIODevice::ReadWrite);
//! \brief
//! \~english Destructor
//! \~russian Деструктор
virtual ~PICloudClient(); virtual ~PICloudClient();
//! \brief
//! \~english Sets server name
//! \~russian Устанавливает имя сервера
void setServerName(const PIString & server_name); void setServerName(const PIString & server_name);
//! \brief
//! \~english Sets keep connection mode
//! \~russian Устанавливает режим поддержания соединения
void setKeepConnection(bool on); void setKeepConnection(bool on);
//! \brief
//! \~english Checks if connected to server
//! \~russian Проверяет подключение к серверу
bool isConnected() const { return is_connected; } bool isConnected() const { return is_connected; }
//! \brief
//! \~english Returns number of bytes available
//! \~russian Возвращает количество доступных байт
ssize_t bytesAvailable() const override { return buff.size(); } ssize_t bytesAvailable() const override { return buff.size(); }
//! \brief
//! \~english Interrupts connection
//! \~russian Прерывает соединение
void interrupt() override; void interrupt() override;
//! \brief
//! \~english Raised when connected to server
//! \~russian Вызывается при подключении к серверу
EVENT(connected); EVENT(connected);
//! \brief
//! \~english Raised when disconnected from server
//! \~russian Вызывается при отключении от сервера
EVENT(disconnected); EVENT(disconnected);
protected: protected:
//! \brief
//! \~english Opens device
//! \~russian Открывает устройство
bool openDevice() override; bool openDevice() override;
//! \brief
//! \~english Closes device
//! \~russian Закрывает устройство
bool closeDevice() override; bool closeDevice() override;
//! \brief
//! \~english Reads data from device
//! \~russian Читает данные из устройства
ssize_t readDevice(void * read_to, ssize_t max_size) override; ssize_t readDevice(void * read_to, ssize_t max_size) override;
//! \brief
//! \~english Writes data to device
//! \~russian Записывает данные в устройство
ssize_t writeDevice(const void * data, ssize_t size) override; ssize_t writeDevice(const void * data, ssize_t size) override;
//! \brief
//! \~english Returns device info flags
//! \~russian Возвращает флаги информации об устройстве
DeviceInfoFlags deviceInfoFlags() const override { return PIIODevice::Reliable; } DeviceInfoFlags deviceInfoFlags() const override { return PIIODevice::Reliable; }
private: private:

View File

@@ -1,11 +1,9 @@
//! \file picloudserver.h /*! \file picloudserver.h
//! \ingroup Cloud * \ingroup Cloud
//! \brief * \~\brief
//! \~english PICloud Server * \~english PICloud Server
//! \~russian Сервер PICloud * \~russian Сервер PICloud
//! \details */
//! \~english Server implementation for accepting PICloud client connections over TCP.
//! \~russian Реализация сервера для приема подключений клиентов PICloud по TCP.
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
PICloud Server PICloud Server
@@ -38,70 +36,25 @@ class PIP_CLOUD_EXPORT PICloudServer
PIIODEVICE(PICloudServer, ""); PIIODEVICE(PICloudServer, "");
public: public:
//! \brief //! PICloudServer
//! \~english Constructs PICloudServer
//! \~russian Создает PICloudServer
explicit PICloudServer(const PIString & path = PIString(), PIIODevice::DeviceMode mode = PIIODevice::ReadWrite); explicit PICloudServer(const PIString & path = PIString(), PIIODevice::DeviceMode mode = PIIODevice::ReadWrite);
//! \brief
//! \~english Destructor
//! \~russian Деструктор
virtual ~PICloudServer(); virtual ~PICloudServer();
//! \brief Connected client representation
//! \~english Represents a client connected to the server
//! \~russian Представляет клиента, подключенного к серверу
class Client: public PIIODevice { class Client: public PIIODevice {
PIIODEVICE(PICloudServer::Client, ""); PIIODEVICE(PICloudServer::Client, "");
friend class PICloudServer; friend class PICloudServer;
public: public:
//! \brief
//! \~english Constructs Client
//! \~russian Создает Client
//! \param srv Parent server / Родительский сервер
//! \param id Client ID / ID клиента
Client(PICloudServer * srv = nullptr, uint id = 0); Client(PICloudServer * srv = nullptr, uint id = 0);
//! \brief
//! \~english Destructor
//! \~russian Деструктор
virtual ~Client(); virtual ~Client();
protected: protected:
//! \brief
//! \~english Opens device
//! \~russian Открывает устройство
bool openDevice() override; bool openDevice() override;
//! \brief
//! \~english Closes device
//! \~russian Закрывает устройство
bool closeDevice() override; bool closeDevice() override;
//! \brief
//! \~english Reads data from device
//! \~russian Читает данные из устройства
ssize_t readDevice(void * read_to, ssize_t max_size) override; ssize_t readDevice(void * read_to, ssize_t max_size) override;
//! \brief
//! \~english Writes data to device
//! \~russian Записывает данные в устройство
ssize_t writeDevice(const void * data, ssize_t size) override; ssize_t writeDevice(const void * data, ssize_t size) override;
//! \brief
//! \~english Returns device info flags
//! \~russian Возвращает флаги информации об устройстве
DeviceInfoFlags deviceInfoFlags() const override { return PIIODevice::Reliable; } DeviceInfoFlags deviceInfoFlags() const override { return PIIODevice::Reliable; }
//! \brief
//! \~english Returns number of bytes available
//! \~russian Возвращает количество доступных байт
ssize_t bytesAvailable() const override { return buff.size(); } ssize_t bytesAvailable() const override { return buff.size(); }
//! \brief
//! \~english Interrupts connection
//! \~russian Прерывает соединение
void interrupt() override; void interrupt() override;
private: private:
@@ -114,45 +67,17 @@ public:
std::atomic_bool is_connected; std::atomic_bool is_connected;
}; };
//! \brief
//! \~english Sets server name
//! \~russian Устанавливает имя сервера
void setServerName(const PIString & server_name); void setServerName(const PIString & server_name);
//! \brief
//! \~english Returns list of connected clients
//! \~russian Возвращает список подключенных клиентов
PIVector<PICloudServer::Client *> clients() const; PIVector<PICloudServer::Client *> clients() const;
//! \brief
//! \~english Raised when new client connects
//! \~russian Вызывается при подключении нового клиента
EVENT1(newConnection, PICloudServer::Client *, client); EVENT1(newConnection, PICloudServer::Client *, client);
protected: protected:
//! \brief
//! \~english Opens device
//! \~russian Открывает устройство
bool openDevice() override; bool openDevice() override;
//! \brief
//! \~english Closes device
//! \~russian Закрывает устройство
bool closeDevice() override; bool closeDevice() override;
//! \brief
//! \~english Reads data from device
//! \~russian Читает данные из устройства
ssize_t readDevice(void * read_to, ssize_t max_size) override; ssize_t readDevice(void * read_to, ssize_t max_size) override;
//! \brief
//! \~english Writes data to device
//! \~russian Записывает данные в устройство
ssize_t writeDevice(const void * data, ssize_t max_size) override; ssize_t writeDevice(const void * data, ssize_t max_size) override;
//! \brief
//! \~english Interrupts connection
//! \~russian Прерывает соединение
void interrupt() override; void interrupt() override;
private: private:

View File

@@ -1,11 +1,9 @@
//! \file picloudtcp.h /*! \file picloudtcp.h
//! \ingroup Cloud * \ingroup Cloud
//! \brief * \~\brief
//! \~english PICloud TCP transport * \~english PICloud TCP transport
//! \~russian TCP слой PICloud * \~russian TCP слой PICloud
//! \details */
//! \~english Low-level TCP protocol implementation for PICloud communication.
//! \~russian Реализация низкоуровневого TCP-протокола для коммуникации PICloud.
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
PICloud TCP transport PICloud TCP transport
@@ -38,118 +36,45 @@ class PIStreamPacker;
namespace PICloud { namespace PICloud {
//! \brief TCP transport protocol
//! \~english TCP transport protocol for cloud communication
//! \~russian TCP транспортный протокол для облачной коммуникации
class PIP_CLOUD_EXPORT TCP { class PIP_CLOUD_EXPORT TCP {
public: public:
//! \brief Protocol version
enum Version { enum Version {
Version_1 = 1, //!< Version 1 / Версия 1 Version_1 = 1,
Version_2 = 2, //!< Version 2 / Версия 2 Version_2 = 2,
}; };
//! \brief Connection role
enum Role { enum Role {
InvalidRole = 0, //!< Invalid role / Неверная роль InvalidRole = 0,
Server = 1, //!< Server role / Роль сервера Server = 1,
Client = 2, //!< Client role / Роль клиента Client = 2,
}; };
//! \brief Message type
enum Type { enum Type {
InvalidType = 0, //!< Invalid type / Неверный тип InvalidType = 0,
Connect = 1, //!< Connect message / Сообщение о подключении Connect = 1,
Disconnect = 2, //!< Disconnect message / Сообщение об отключении Disconnect = 2,
Data = 3, //!< Data message / Сообщение с данными Data = 3,
Ping = 4, //!< Ping message / Сообщение ping Ping = 4,
}; };
//! \brief
//! \~english Constructs TCP transport
//! \~russian Создает TCP транспорт
//! \param s Stream packer instance / Экземпляр стримового упаковщика
TCP(PIStreamPacker * s); TCP(PIStreamPacker * s);
//! \brief
//! \~english Sets connection role
//! \~russian Устанавливает роль соединения
void setRole(Role r); void setRole(Role r);
//! \brief
//! \~english Returns connection role
//! \~russian Возвращает роль соединения
Role role() const { return (Role)header.role; } Role role() const { return (Role)header.role; }
//! \brief
//! \~english Sets server name
//! \~russian Устанавливает имя сервера
void setServerName(const PIString & server_name_); void setServerName(const PIString & server_name_);
//! \brief
//! \~english Returns server name
//! \~russian Возвращает имя сервера
PIString serverName() const; PIString serverName() const;
//! \brief
//! \~english Sends start message
//! \~russian Отправляет сообщение о старте
void sendStart(); void sendStart();
//! \brief
//! \~english Sends connected message
//! \~russian Отправляет сообщение о подключении
void sendConnected(uint client_id); void sendConnected(uint client_id);
//! \brief
//! \~english Sends disconnected message
//! \~russian Отправляет сообщение об отключении
void sendDisconnected(uint client_id); void sendDisconnected(uint client_id);
//! \brief
//! \~english Sends data to all clients
//! \~russian Отправляет данные всем клиентам
int sendData(const PIByteArray & data); int sendData(const PIByteArray & data);
//! \brief
//! \~english Sends data to specific client
//! \~russian Отправляет данные конкретному клиенту
int sendData(const PIByteArray & data, uint client_id); int sendData(const PIByteArray & data, uint client_id);
//! \brief
//! \~english Sends ping message
//! \~russian Отправляет сообщение ping
void sendPing(); void sendPing();
//! \brief
//! \~english Parses header from buffer
//! \~russian Парсит заголовок из буфера
PIPair<PICloud::TCP::Type, PICloud::TCP::Role> parseHeader(PIByteArray & ba); PIPair<PICloud::TCP::Type, PICloud::TCP::Role> parseHeader(PIByteArray & ba);
//! \brief
//! \~english Checks if data can be parsed
//! \~russian Проверяет возможность парсинга данных
bool canParseData(PIByteArray & ba); bool canParseData(PIByteArray & ba);
//! \brief
//! \~english Parses data for server
//! \~russian Парсит данные для сервера
PIPair<uint, PIByteArray> parseDataServer(PIByteArray & ba); PIPair<uint, PIByteArray> parseDataServer(PIByteArray & ba);
//! \brief
//! \~english Parses connect data
//! \~russian Парсит данные подключения
PIByteArray parseConnect_d(PIByteArray & ba); PIByteArray parseConnect_d(PIByteArray & ba);
//! \brief
//! \~english Parses connect message
//! \~russian Парсит сообщение подключения
uint parseConnect(PIByteArray & ba); uint parseConnect(PIByteArray & ba);
//! \brief
//! \~english Parses disconnect message
//! \~russian Парсит сообщение отключения
uint parseDisconnect(PIByteArray & ba); uint parseDisconnect(PIByteArray & ba);
private: private:

View File

@@ -29,12 +29,12 @@
#include "pithread.h" #include "pithread.h"
#include "pitime.h" #include "pitime.h"
#define WAIT_FOR_EXIT \ #define WAIT_FOR_EXIT \
while (!PIKbdListener::exiting) \ while (!PIKbdListener::exiting) \
piMSleep(PIP_MIN_MSLEEP * 5); \ piMSleep(PIP_MIN_MSLEEP * 5); \
if (PIKbdListener::instance()) { \ if (PIKbdListener::instance()) { \
if (!PIKbdListener::instance()->stopAndWait(PISystemTime::fromSeconds(1))) PIKbdListener::instance()->terminate(); \ if (!PIKbdListener::instance()->stopAndWait(PISystemTime::fromSeconds(1))) PIKbdListener::instance()->terminate(); \
} }
class PIP_EXPORT PIKbdListener: public PIThread { class PIP_EXPORT PIKbdListener: public PIThread {

View File

@@ -1,11 +1,9 @@
//! \file piscreen.h /*! \file piscreen.h
//! \ingroup Console * \ingroup Console
//! \brief * \~\brief
//! \~english Console tiling manager * \~english Console tiling manager
//! \~russian Консольный тайловый менеджер * \~russian Консольный тайловый менеджер
//! \details */
//! \~english Main console screen manager providing tile-based UI rendering and keyboard input.
//! \~russian Основной менеджер консольного экрана, обеспечивающий отрисовку UI на основе тайлов и ввод с клавиатуры.
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Console GUI Console GUI
@@ -40,126 +38,46 @@ class PIP_CONSOLE_EXPORT PIScreen
class SystemConsole; class SystemConsole;
public: public:
//! \brief //! Constructs %PIScreen with key handler "slot" and if "startNow" start it
//! \~english Constructs PIScreen
//! \~russian Создает PIScreen
//! \param startNow Start immediately / Запустить немедленно
//! \param slot Keyboard handler function / Обработчик клавиатуры
PIScreen(bool startNow = true, PIKbdListener::KBFunc slot = 0); PIScreen(bool startNow = true, PIKbdListener::KBFunc slot = 0);
//! \brief
//! \~english Destructor
//! \~russian Деструктор
~PIScreen(); ~PIScreen();
//! \brief //! Directly call function from \a PIKbdListener
//! \~english Enables exit capture with key
//! \~russian Включает захват выхода по клавише
void enableExitCapture(int key = 'Q') { listener->enableExitCapture(key); } void enableExitCapture(int key = 'Q') { listener->enableExitCapture(key); }
//! \brief //! Directly call function from \a PIKbdListener
//! \~english Disables exit capture
//! \~russian Отключает захват выхода
void disableExitCapture() { listener->disableExitCapture(); } void disableExitCapture() { listener->disableExitCapture(); }
//! \brief //! Directly call function from \a PIKbdListener
//! \~english Checks if exit is captured
//! \~russian Проверяет, захвачен ли выход
bool exitCaptured() const { return listener->exitCaptured(); } bool exitCaptured() const { return listener->exitCaptured(); }
//! \brief //! Directly call function from \a PIKbdListener
//! \~english Returns exit key
//! \~russian Возвращает клавишу выхода
int exitKey() const { return listener->exitKey(); } int exitKey() const { return listener->exitKey(); }
//! \brief
//! \~english Returns window width
//! \~russian Возвращает ширину окна
int windowWidth() const { return console.width; } int windowWidth() const { return console.width; }
//! \brief
//! \~english Returns window height
//! \~russian Возвращает высоту окна
int windowHeight() const { return console.height; } int windowHeight() const { return console.height; }
//! \brief
//! \~english Checks if mouse is enabled
//! \~russian Проверяет, включена ли мышь
bool isMouseEnabled() const { return mouse_; } bool isMouseEnabled() const { return mouse_; }
//! \brief
//! \~english Sets mouse enabled state
//! \~russian Устанавливает состояние мыши
void setMouseEnabled(bool on); void setMouseEnabled(bool on);
//! \brief
//! \~english Returns root tile
//! \~russian Возвращает корневой тайл
PIScreenTile * rootTile() { return &root; } PIScreenTile * rootTile() { return &root; }
//! \brief
//! \~english Finds tile by name
//! \~russian Находит тайл по имени
PIScreenTile * tileByName(const PIString & name); PIScreenTile * tileByName(const PIString & name);
//! \brief
//! \~english Sets dialog tile
//! \~russian Устанавливает диалоговый тайл
void setDialogTile(PIScreenTile * t); void setDialogTile(PIScreenTile * t);
//! \brief
//! \~english Returns current dialog tile
//! \~russian Возвращает текущий диалоговый тайл
PIScreenTile * dialogTile() const { return tile_dialog; } PIScreenTile * dialogTile() const { return tile_dialog; }
//! \brief
//! \~english Returns screen drawer
//! \~russian Возвращает отрисовщик экрана
PIScreenDrawer * drawer() { return &drawer_; } PIScreenDrawer * drawer() { return &drawer_; }
//! \brief
//! \~english Clears the screen
//! \~russian Очищает экран
void clear() { drawer_.clear(); } void clear() { drawer_.clear(); }
//! \brief
//! \~english Resizes screen
//! \~russian Изменяет размер экрана
void resize(int w, int h) { console.resize(w, h); } void resize(int w, int h) { console.resize(w, h); }
//! \brief
//! \~english Waits for finish
//! \~russian Ожидает завершения
EVENT_HANDLER0(void, waitForFinish); EVENT_HANDLER0(void, waitForFinish);
//! \brief
//! \~english Starts screen
//! \~russian Запускает экран
EVENT_HANDLER0(void, start) { start(false); } EVENT_HANDLER0(void, start) { start(false); }
//! \brief
//! \~english Starts screen
//! \~russian Запускает экран
EVENT_HANDLER1(void, start, bool, wait); EVENT_HANDLER1(void, start, bool, wait);
//! \brief
//! \~english Stops screen
//! \~russian Останавливает экран
EVENT_HANDLER0(void, stop) { stop(false); } EVENT_HANDLER0(void, stop) { stop(false); }
//! \brief
//! \~english Stops screen
//! \~russian Останавливает экран
EVENT_HANDLER1(void, stop, bool, clear); EVENT_HANDLER1(void, stop, bool, clear);
//! \brief
//! \~english Raised on key pressed
//! \~russian Вызывается при нажатии клавиши
EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void *, data); EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void *, data);
//! \brief
//! \~english Raised on tile event
//! \~russian Вызывается при событии тайла
EVENT2(tileEvent, PIScreenTile *, tile, PIScreenTypes::TileEvent, e); EVENT2(tileEvent, PIScreenTile *, tile, PIScreenTypes::TileEvent, e);
//! \handlers //! \handlers

View File

@@ -1,11 +1,9 @@
//! \file piscreenconsole.h /*! \file piscreenconsole.h
//! \ingroup Console * \ingroup Console
//! \brief * \~\brief
//! \~english Tile for PIScreen with PIConsole API * \~english Tile for PIScreen with PIConsole API
//! \~russian Тайл для PIScreen с API PIConsole * \~russian Тайл для PIScreen с API PIConsole
//! \details */
//! \~english Provides tiles for displaying variable data and console-like content.
//! \~russian Обеспечивает тайлы для отображения данных переменных и консольного контента.
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Tile for PIScreen with PIConsole API Tile for PIScreen with PIConsole API
@@ -34,30 +32,17 @@
/// NOTE: incomplete class /// NOTE: incomplete class
/// TODO: write TileVars /// TODO: write TileVars
//! \brief
//! \~english Tile for displaying variable data
//! \~russian Тайл для отображения данных переменных
class PIP_CONSOLE_EXPORT TileVars: public PIScreenTile { class PIP_CONSOLE_EXPORT TileVars: public PIScreenTile {
public: public:
//! \brief
//! \~english Constructs TileVars
//! \~russian Создает TileVars
//! \param n Tile name / Имя тайла
TileVars(const PIString & n = PIString()); TileVars(const PIString & n = PIString());
protected: protected:
//! \brief Variable data structure
struct PIP_CONSOLE_EXPORT Variable { struct PIP_CONSOLE_EXPORT Variable {
Variable() { Variable() {
nx = ny = type = offset = bitFrom = bitCount = size = 0; nx = ny = type = offset = bitFrom = bitCount = size = 0;
format = PIScreenTypes::CellFormat(); format = PIScreenTypes::CellFormat();
ptr = 0; ptr = 0;
} }
//! \brief
//! \~english Checks if variable is empty
//! \~russian Проверяет, пустая ли переменная
bool isEmpty() const { return (ptr == 0); } bool isEmpty() const { return (ptr == 0); }
PIString name; PIString name;
PIScreenTypes::CellFormat format; PIScreenTypes::CellFormat format;
@@ -82,34 +67,15 @@ protected:
ptr = src.ptr; ptr = src.ptr;
}*/ }*/
}; };
//! \brief
//! \~english Returns variables
//! \~russian Возвращает переменные
PIVector<Variable> variables; PIVector<Variable> variables;
PIScreenTypes::Alignment alignment; PIScreenTypes::Alignment alignment;
//! \brief
//! \~english Calculates tile size hint
//! \~russian Вычисляет рекомендуемый размер тайла
void sizeHint(int & w, int & h) const override; void sizeHint(int & w, int & h) const override;
//! \brief
//! \~english Draws tile content
//! \~russian Рисует содержимое тайла
void drawEvent(PIScreenDrawer * d) override; void drawEvent(PIScreenDrawer * d) override;
}; };
//! \brief
//! \~english Console-style tile for PIScreen
//! \~russian Консольный тайл для PIScreen
class PIP_CONSOLE_EXPORT PIScreenConsoleTile: public PIScreenTile { class PIP_CONSOLE_EXPORT PIScreenConsoleTile: public PIScreenTile {
public: public:
//! \brief
//! \~english Constructs PIScreenConsoleTile
//! \~russian Создает PIScreenConsoleTile
PIScreenConsoleTile(); PIScreenConsoleTile();
}; };

View File

@@ -1,11 +1,9 @@
//! \file piscreendrawer.h /*! \file piscreendrawer.h
//! \ingroup Console * \ingroup Console
//! \brief * \~\brief
//! \~english Drawer for PIScreen * \~english Drawer for PIScreen
//! \~russian Отрисовщик для PIScreen * \~russian Отрисовщик для PIScreen
//! \details */
//! \~english Provides drawing primitives for console screen rendering.
//! \~russian Обеспечивает примитивы отрисовки для рендеринга консольного экрана.
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Drawer for PIScreen Drawer for PIScreen
@@ -32,51 +30,31 @@
#include "piscreentypes.h" #include "piscreentypes.h"
#include "pistring.h" #include "pistring.h"
//! \brief Screen drawer for console rendering
//! \~english Console screen drawer for rendering graphics
//! \~russian Отрисовщик консольного экрана для рендеринга графики
class PIP_CONSOLE_EXPORT PIScreenDrawer { class PIP_CONSOLE_EXPORT PIScreenDrawer {
friend class PIScreen; friend class PIScreen;
PIScreenDrawer(PIVector<PIVector<PIScreenTypes::Cell>> & c); PIScreenDrawer(PIVector<PIVector<PIScreenTypes::Cell>> & c);
public: public:
//! \brief ASCII art characters
enum ArtChar { enum ArtChar {
LineVertical = 1, //!< Vertical line / Вертикальная линия LineVertical = 1,
LineHorizontal, //!< Horizontal line / Горизонтальная линия LineHorizontal,
Cross, //!< Cross / Крест Cross,
CornerTopLeft, //!< Top-left corner / Угол сверху-слева CornerTopLeft,
CornerTopRight, //!< Top-right corner / Угол сверху-справа CornerTopRight,
CornerBottomLeft, //!< Bottom-left corner / Угол снизу-слева CornerBottomLeft,
CornerBottomRight, //!< Bottom-right corner / Угол снизу-справа CornerBottomRight,
Unchecked, //!< Unchecked box / Неотмеченная клетка Unchecked,
Checked //!< Checked box / Отмеченная клетка Checked
}; };
//! \brief
//! \~english Clears the screen
//! \~russian Очищает экран
void clear(); void clear();
//! \brief
//! \~english Clears rectangle
//! \~russian Очищает прямоугольник
void clearRect(int x0, int y0, int x1, int y1) { fillRect(x0, y0, x1, y1, ' '); } void clearRect(int x0, int y0, int x1, int y1) { fillRect(x0, y0, x1, y1, ' '); }
//! \brief
//! \~english Draws pixel
//! \~russian Рисует пиксель
void drawPixel(int x, void drawPixel(int x,
int y, int y,
const PIChar & c, const PIChar & c,
PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_char = PIScreenTypes::Default,
PIScreenTypes::Color col_back = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Default,
PIScreenTypes::CharFlags flags_char = 0); PIScreenTypes::CharFlags flags_char = 0);
//! \brief
//! \~english Draws line
//! \~russian Рисует линию
void drawLine(int x0, void drawLine(int x0,
int y0, int y0,
int x1, int x1,
@@ -85,10 +63,6 @@ public:
PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_char = PIScreenTypes::Default,
PIScreenTypes::Color col_back = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Default,
PIScreenTypes::CharFlags flags_char = 0); PIScreenTypes::CharFlags flags_char = 0);
//! \brief
//! \~english Draws rectangle
//! \~russian Рисует прямоугольник
void drawRect(int x0, void drawRect(int x0,
int y0, int y0,
int x1, int x1,
@@ -97,10 +71,6 @@ public:
PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_char = PIScreenTypes::Default,
PIScreenTypes::Color col_back = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Default,
PIScreenTypes::CharFlags flags_char = 0); PIScreenTypes::CharFlags flags_char = 0);
//! \brief
//! \~english Draws frame
//! \~russian Рисует рамку
void drawFrame(int x0, void drawFrame(int x0,
int y0, int y0,
int x1, int x1,
@@ -108,20 +78,12 @@ public:
PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_char = PIScreenTypes::Default,
PIScreenTypes::Color col_back = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Default,
PIScreenTypes::CharFlags flags_char = 0); PIScreenTypes::CharFlags flags_char = 0);
//! \brief
//! \~english Draws text
//! \~russian Рисует текст
void drawText(int x, void drawText(int x,
int y, int y,
const PIString & s, const PIString & s,
PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_char = PIScreenTypes::Default,
PIScreenTypes::Color col_back = PIScreenTypes::Transparent, PIScreenTypes::Color col_back = PIScreenTypes::Transparent,
PIScreenTypes::CharFlags flags_char = 0); PIScreenTypes::CharFlags flags_char = 0);
//! \brief
//! \~english Fills rectangle
//! \~russian Заполняет прямоугольник
void fillRect(int x0, void fillRect(int x0,
int y0, int y0,
int x1, int x1,
@@ -130,20 +92,10 @@ public:
PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_char = PIScreenTypes::Default,
PIScreenTypes::Color col_back = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Default,
PIScreenTypes::CharFlags flags_char = 0); PIScreenTypes::CharFlags flags_char = 0);
//! \brief
//! \~english Fills rectangle with content
//! \~russian Заполняет прямоугольник содержимым
void fillRect(int x0, int y0, int x1, int y1, PIVector<PIVector<PIScreenTypes::Cell>> & content); void fillRect(int x0, int y0, int x1, int y1, PIVector<PIVector<PIScreenTypes::Cell>> & content);
//! \brief
//! \~english Returns art character by type
//! \~russian Возвращает символ искусства по типу
PIChar artChar(const ArtChar type) const { return arts_.value(type, PIChar(' ')); } PIChar artChar(const ArtChar type) const { return arts_.value(type, PIChar(' ')); }
//! \brief
//! \~english Clears cell matrix
//! \~russian Очищает матрицу ячеек
static void clear(PIVector<PIVector<PIScreenTypes::Cell>> & cells); static void clear(PIVector<PIVector<PIScreenTypes::Cell>> & cells);
private: private:

View File

@@ -1,11 +1,9 @@
//! \file piscreentile.h /*! \file piscreentile.h
//! \ingroup Console * \ingroup Console
//! \brief * \~\brief
//! \~english Basic PIScreen tile * \~english Basic PIScreen tile
//! \~russian Базовый тайл для PIScreen * \~russian Базовый тайл для PIScreen
//! \details */
//! \~english Base class for all screen tiles providing layout and event handling.
//! \~russian Базовый класс для всех экранных тайлов, обеспечивающий компоновку и обработку событий.
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Basic PIScreen tile Basic PIScreen tile
@@ -34,89 +32,27 @@
class PIScreenDrawer; class PIScreenDrawer;
//! \brief
//! \~english Base tile class for console screen
//! \~russian Базовый класс тайла для консольного экрана
class PIP_CONSOLE_EXPORT PIScreenTile: public PIObject { class PIP_CONSOLE_EXPORT PIScreenTile: public PIObject {
friend class PIScreen; friend class PIScreen;
PIOBJECT_SUBCLASS(PIScreenTile, PIObject); PIOBJECT_SUBCLASS(PIScreenTile, PIObject);
public: public:
//! \brief
//! \~english Constructs PIScreenTile
//! \~russian Создает PIScreenTile
//! \param n Tile name / Имя тайла
//! \param d Layout direction / Направление компоновки
//! \param p Size policy / Политика размера
PIScreenTile(const PIString & n = PIString(), PIScreenTile(const PIString & n = PIString(),
PIScreenTypes::Direction d = PIScreenTypes::Vertical, PIScreenTypes::Direction d = PIScreenTypes::Vertical,
PIScreenTypes::SizePolicy p = PIScreenTypes::Preferred); PIScreenTypes::SizePolicy p = PIScreenTypes::Preferred);
//! \brief
//! \~english Destructor
//! \~russian Деструктор
virtual ~PIScreenTile(); virtual ~PIScreenTile();
//! \brief
//! \~english Adds child tile
//! \~russian Добавляет дочерний тайл
void addTile(PIScreenTile * t); void addTile(PIScreenTile * t);
//! \brief
//! \~english Takes ownership of tile
//! \~russian Забирает владение тайла
void takeTile(PIScreenTile * t); void takeTile(PIScreenTile * t);
//! \brief
//! \~english Removes child tile
//! \~russian Удаляет дочерний тайл
void removeTile(PIScreenTile * t); void removeTile(PIScreenTile * t);
//! \brief
//! \~english Returns parent tile
//! \~russian Возвращает родительский тайл
PIScreenTile * parentTile() const { return parent; } PIScreenTile * parentTile() const { return parent; }
//! \brief
//! \~english Returns child tiles
//! \~russian Возвращает дочерние тайлы
//! \param only_visible Only visible tiles / Только видимые тайлы
PIVector<PIScreenTile *> children(bool only_visible = false); PIVector<PIScreenTile *> children(bool only_visible = false);
//! \brief
//! \~english Returns child under mouse position
//! \~russian Возвращает тайл под мышью
PIScreenTile * childUnderMouse(int x, int y); PIScreenTile * childUnderMouse(int x, int y);
//! \brief
//! \~english Shows tile
//! \~russian Показывает тайл
void show() { visible = true; } void show() { visible = true; }
//! \brief
//! \~english Hides tile
//! \~russian Скрывает тайл
void hide() { visible = false; } void hide() { visible = false; }
//! \brief
//! \~english Sets focus to this tile
//! \~russian Устанавливает фокус на этот тайл
void setFocus(); void setFocus();
//! \brief
//! \~english Checks if tile has focus
//! \~russian Проверяет, имеет ли тайл фокус
bool hasFocus() const { return has_focus; } bool hasFocus() const { return has_focus; }
//! \brief
//! \~english Sets all margins
//! \~russian Устанавливает все отступы
void setMargins(int m) { marginLeft = marginRight = marginTop = marginBottom = m; } void setMargins(int m) { marginLeft = marginRight = marginTop = marginBottom = m; }
//! \brief
//! \~english Sets individual margins
//! \~russian Устанавливает отдельные отступы
void setMargins(int l, int r, int t, int b) { void setMargins(int l, int r, int t, int b) {
marginLeft = l; marginLeft = l;
marginRight = r; marginRight = r;
@@ -124,24 +60,9 @@ public:
marginBottom = b; marginBottom = b;
} }
//! \brief
//! \~english Returns tile X position
//! \~russian Возвращает позицию X тайла
int x() const { return x_; } int x() const { return x_; }
//! \brief
//! \~english Returns tile Y position
//! \~russian Возвращает позицию Y тайла
int y() const { return y_; } int y() const { return y_; }
//! \brief
//! \~english Returns tile width
//! \~russian Возвращает ширину тайла
int width() const { return width_; } int width() const { return width_; }
//! \brief
//! \~english Returns tile height
//! \~russian Возвращает высоту тайла
int height() const { return height_; } int height() const { return height_; }
PIScreenTypes::Direction direction; PIScreenTypes::Direction direction;
@@ -156,64 +77,29 @@ public:
bool visible; bool visible;
protected: protected:
//! \brief //! Returns desired tile size in "w" and "h"
//! \~english Returns desired tile size in "w" and "h"
//! \~russian Возвращает желаемый размер тайла в "w" и "h"
virtual void sizeHint(int & w, int & h) const; virtual void sizeHint(int & w, int & h) const;
//! \brief //! Tile has been resized to "w"x"h"
//! \~english Tile has been resized to "w"x"h"
//! \~russian Тайл был изменен на "w"x"h"
virtual void resizeEvent(int w, int h) {} virtual void resizeEvent(int w, int h) {}
//! \brief //! Draw tile with drawer "d" in world-space coordinates
//! \~english Draw tile with drawer "d" in world-space coordinates
//! \~russian Рисует тайл отрисовщиком "d" в мировых координатах
virtual void drawEvent(PIScreenDrawer * d) {} virtual void drawEvent(PIScreenDrawer * d) {}
//! \brief //! Return "true" if you process key
//! \~english Return "true" if you process key
//! \~russian Возвращает "true" если вы обрабатываете клавишу
virtual bool keyEvent(PIKbdListener::KeyEvent key) { return false; } virtual bool keyEvent(PIKbdListener::KeyEvent key) { return false; }
//! \brief //! Return "true" if you process event
//! \~english Return "true" if you process event
//! \~russian Возвращает "true" если вы обрабатываете событие
virtual bool mouseEvent(PIKbdListener::MouseEvent me) { return false; } virtual bool mouseEvent(PIKbdListener::MouseEvent me) { return false; }
//! \brief //! Return "true" if you process wheel
//! \~english Return "true" if you process wheel
//! \~russian Возвращает "true" если вы обрабатываете колесо
virtual bool wheelEvent(PIKbdListener::WheelEvent we) { return false; } virtual bool wheelEvent(PIKbdListener::WheelEvent we) { return false; }
//! \brief
//! \~english Raises tile event
//! \~russian Вызывает событие тайла
void raiseEvent(PIScreenTypes::TileEvent e); void raiseEvent(PIScreenTypes::TileEvent e);
//! \brief
//! \~english Sets screen reference
//! \~russian Устанавливает ссылку на экран
void setScreen(PIScreenTypes::PIScreenBase * s); void setScreen(PIScreenTypes::PIScreenBase * s);
//! \brief
//! \~english Deletes all children
//! \~russian Удаляет всех потомков
void deleteChildren(); void deleteChildren();
//! \brief
//! \~english Internal draw event
//! \~russian Внутреннее событие отрисовки
void drawEventInternal(PIScreenDrawer * d); void drawEventInternal(PIScreenDrawer * d);
//! \brief
//! \~english Performs layout
//! \~russian Выполняет компоновку
void layout(); void layout();
//! \brief
//! \~english Checks if layout is needed
//! \~russian Проверяет, нужна ли компоновка
bool needLayout() { return size_policy != PIScreenTypes::Ignore; } bool needLayout() { return size_policy != PIScreenTypes::Ignore; }
PIVector<PIScreenTile *> tiles; PIVector<PIScreenTile *> tiles;

View File

@@ -1,11 +1,9 @@
//! \file piscreentiles.h /*! \file piscreentiles.h
//! \ingroup Console * \ingroup Console
//! \brief * \~\brief
//! \~english Various tiles for PIScreen * \~english Various tiles for PIScreen
//! \~russian Различные тайлы для PIScreen * \~russian Различные тайлы для PIScreen
//! \details */
//! \~english Provides ready-to-use tile implementations for common UI elements.
//! \~russian Обеспечивает готовые к использованию реализации тайлов для общих элементов UI.
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Various tiles for PIScreen Various tiles for PIScreen
@@ -32,326 +30,125 @@
#include "piscreentile.h" #include "piscreentile.h"
//! \brief
//! \~english Tile for displaying simple text content
//! \~russian Тайл для отображения простого текстового контента
class PIP_CONSOLE_EXPORT TileSimple: public PIScreenTile { class PIP_CONSOLE_EXPORT TileSimple: public PIScreenTile {
PIOBJECT_SUBCLASS(TileSimple, PIScreenTile); PIOBJECT_SUBCLASS(TileSimple, PIScreenTile);
public: public:
//! \brief Row type
typedef PIPair<PIString, PIScreenTypes::CellFormat> Row; typedef PIPair<PIString, PIScreenTypes::CellFormat> Row;
//! \brief
//! \~english Constructs TileSimple
//! \~russian Создает TileSimple
//! \param n Tile name / Имя тайла
TileSimple(const PIString & n = PIString()); TileSimple(const PIString & n = PIString());
//! \brief
//! \~english Constructs TileSimple with row
//! \~russian Создает TileSimple со строкой
//! \param r Row content / Содержимое строки
TileSimple(const Row & r); TileSimple(const Row & r);
//! \brief
//! \~english Destructor
//! \~russian Деструктор
virtual ~TileSimple() {} virtual ~TileSimple() {}
//! \brief Tile content rows
PIVector<Row> content; PIVector<Row> content;
//! \brief Text alignment
PIScreenTypes::Alignment alignment; PIScreenTypes::Alignment alignment;
protected: protected:
//! \brief
//! \~english Calculates tile size hint
//! \~russian Вычисляет рекомендуемый размер тайла
void sizeHint(int & w, int & h) const override; void sizeHint(int & w, int & h) const override;
//! \brief
//! \~english Draws tile content
//! \~russian Рисует содержимое тайла
void drawEvent(PIScreenDrawer * d) override; void drawEvent(PIScreenDrawer * d) override;
}; };
class TileList; class TileList;
//! \brief
//! \~english Scrollbar for list containers
//! \~russian Полоса прокрутки для списков
class PIP_CONSOLE_EXPORT TileScrollBar: public PIScreenTile { class PIP_CONSOLE_EXPORT TileScrollBar: public PIScreenTile {
PIOBJECT_SUBCLASS(TileScrollBar, PIScreenTile); PIOBJECT_SUBCLASS(TileScrollBar, PIScreenTile);
friend class TileList; friend class TileList;
public: public:
//! \brief
//! \~english Constructs TileScrollBar
//! \~russian Создает TileScrollBar
//! \param n Tile name / Имя тайла
TileScrollBar(const PIString & n = PIString()); TileScrollBar(const PIString & n = PIString());
//! \brief
//! \~english Destructor
//! \~russian Деструктор
virtual ~TileScrollBar() {} virtual ~TileScrollBar() {}
//! \brief
//! \~english Sets minimum value
//! \~russian Устанавливает минимальное значение
void setMinimum(int v); void setMinimum(int v);
//! \brief
//! \~english Sets maximum value
//! \~russian Устанавливает максимальное значение
void setMaximum(int v); void setMaximum(int v);
//! \brief
//! \~english Sets current value
//! \~russian Устанавливает текущее значение
void setValue(int v); void setValue(int v);
//! \brief
//! \~english Returns minimum value
//! \~russian Возвращает минимальное значение
int minimum() const { return minimum_; } int minimum() const { return minimum_; }
//! \brief
//! \~english Returns maximum value
//! \~russian Возвращает максимальное значение
int maximum() const { return maximum_; } int maximum() const { return maximum_; }
//! \brief
//! \~english Returns current value
//! \~russian Возвращает текущее значение
int value() const { return value_; } int value() const { return value_; }
//! \brief Scrollbar thickness
int thickness; int thickness;
protected: protected:
//! \brief Validates scrollbar state
//! \~english Validates scrollbar state
//! \~russian Проверяет состояние полосы прокрутки
void _check(); void _check();
//! \brief
//! \~english Calculates tile size hint
//! \~russian Вычисляет рекомендуемый размер тайла
void sizeHint(int & w, int & h) const override; void sizeHint(int & w, int & h) const override;
//! \brief
//! \~english Draws tile content
//! \~russian Рисует содержимое тайла
void drawEvent(PIScreenDrawer * d) override; void drawEvent(PIScreenDrawer * d) override;
//! \brief
//! \~english Handles mouse events
//! \~russian Обрабатывает события мыши
bool mouseEvent(PIKbdListener::MouseEvent me) override; bool mouseEvent(PIKbdListener::MouseEvent me) override;
int minimum_, maximum_, value_; int minimum_, maximum_, value_;
PIChar line_char; PIChar line_char;
}; };
//! \brief
//! \~english Scrollable list tile
//! \~russian Прокручиваемый список
class PIP_CONSOLE_EXPORT TileList: public PIScreenTile { class PIP_CONSOLE_EXPORT TileList: public PIScreenTile {
PIOBJECT_SUBCLASS(TileList, PIScreenTile); PIOBJECT_SUBCLASS(TileList, PIScreenTile);
public: public:
//! \brief Selection mode
enum SelectionMode { enum SelectionMode {
NoSelection, //!< No selection / Без выделения NoSelection,
SingleSelection, //!< Single item selection / Выделение одного элемента SingleSelection,
MultiSelection //!< Multiple items selection / Выделение нескольких элементов MultiSelection
}; };
//! \brief Event type
enum EventType { enum EventType {
SelectionChanged, //!< Selection changed / Выделение изменено SelectionChanged,
RowPressed //!< Row pressed / Строка нажата RowPressed
}; };
//! \brief
//! \~english Constructs TileList
//! \~russian Создает TileList
//! \param n Tile name / Имя тайла
//! \param sm Selection mode / Режим выделения
TileList(const PIString & n = PIString(), SelectionMode sm = NoSelection); TileList(const PIString & n = PIString(), SelectionMode sm = NoSelection);
//! \brief
//! \~english Destructor
//! \~russian Деструктор
virtual ~TileList() {} virtual ~TileList() {}
//! \brief Row type
typedef PIPair<PIString, PIScreenTypes::CellFormat> Row; typedef PIPair<PIString, PIScreenTypes::CellFormat> Row;
//! \brief List content
PIDeque<Row> content; PIDeque<Row> content;
//! \brief Text alignment
PIScreenTypes::Alignment alignment; PIScreenTypes::Alignment alignment;
//! \brief Selection mode
SelectionMode selection_mode; SelectionMode selection_mode;
//! \brief Selected indices
PISet<int> selected; PISet<int> selected;
//! \brief Line height
int lhei, cur, offset; int lhei, cur, offset;
protected: protected:
//! \brief
//! \~english Calculates tile size hint
//! \~russian Вычисляет рекомендуемый размер тайла
void sizeHint(int & w, int & h) const override; void sizeHint(int & w, int & h) const override;
//! \brief
//! \~english Called when resized
//! \~russian Вызывается при изменении размера
void resizeEvent(int w, int h) override; void resizeEvent(int w, int h) override;
//! \brief
//! \~english Draws tile content
//! \~russian Рисует содержимое тайла
void drawEvent(PIScreenDrawer * d) override; void drawEvent(PIScreenDrawer * d) override;
//! \brief
//! \~english Handles key events
//! \~russian Обрабатывает события клавиатуры
bool keyEvent(PIKbdListener::KeyEvent key) override; bool keyEvent(PIKbdListener::KeyEvent key) override;
//! \brief
//! \~english Handles mouse events
//! \~russian Обрабатывает события мыши
bool mouseEvent(PIKbdListener::MouseEvent me) override; bool mouseEvent(PIKbdListener::MouseEvent me) override;
//! \brief
//! \~english Handles wheel events
//! \~russian Обрабатывает события колеса
bool wheelEvent(PIKbdListener::WheelEvent we) override; bool wheelEvent(PIKbdListener::WheelEvent we) override;
TileScrollBar * scroll; TileScrollBar * scroll;
bool mouse_sel; bool mouse_sel;
}; };
//! \brief
//! \~english Clickable button tile
//! \~russian Кликабельная кнопка
class PIP_CONSOLE_EXPORT TileButton: public PIScreenTile { class PIP_CONSOLE_EXPORT TileButton: public PIScreenTile {
PIOBJECT_SUBCLASS(TileButton, PIScreenTile); PIOBJECT_SUBCLASS(TileButton, PIScreenTile);
public: public:
//! \brief
//! \~english Constructs TileButton
//! \~russian Создает TileButton
//! \param n Tile name / Имя тайла
TileButton(const PIString & n = PIString()); TileButton(const PIString & n = PIString());
//! \brief
//! \~english Destructor
//! \~russian Деструктор
virtual ~TileButton() {} virtual ~TileButton() {}
//! \brief Event type
enum EventType { enum EventType {
ButtonClicked //!< Button clicked / Кнопка нажата ButtonClicked
}; };
//! \brief Button format
PIScreenTypes::CellFormat format; PIScreenTypes::CellFormat format;
//! \brief Button text
PIString text; PIString text;
protected: protected:
//! \brief
//! \~english Calculates tile size hint
//! \~russian Вычисляет рекомендуемый размер тайла
void sizeHint(int & w, int & h) const override; void sizeHint(int & w, int & h) const override;
//! \brief
//! \~english Draws tile content
//! \~russian Рисует содержимое тайла
void drawEvent(PIScreenDrawer * d) override; void drawEvent(PIScreenDrawer * d) override;
//! \brief
//! \~english Handles key events
//! \~russian Обрабатывает события клавиатуры
bool keyEvent(PIKbdListener::KeyEvent key) override; bool keyEvent(PIKbdListener::KeyEvent key) override;
//! \brief
//! \~english Handles mouse events
//! \~russian Обрабатывает события мыши
bool mouseEvent(PIKbdListener::MouseEvent me) override; bool mouseEvent(PIKbdListener::MouseEvent me) override;
}; };
//! \brief
//! \~english Group of buttons with selection
//! \~russian Группа кнопок с выбором
class PIP_CONSOLE_EXPORT TileButtons: public PIScreenTile { class PIP_CONSOLE_EXPORT TileButtons: public PIScreenTile {
PIOBJECT_SUBCLASS(TileButtons, PIScreenTile); PIOBJECT_SUBCLASS(TileButtons, PIScreenTile);
public: public:
//! \brief
//! \~english Constructs TileButtons
//! \~russian Создает TileButtons
//! \param n Tile name / Имя тайла
TileButtons(const PIString & n = PIString()); TileButtons(const PIString & n = PIString());
//! \brief
//! \~english Destructor
//! \~russian Деструктор
virtual ~TileButtons() {} virtual ~TileButtons() {}
//! \brief Event type
enum EventType { enum EventType {
ButtonSelected //!< Button selected / Кнопка выбрана ButtonSelected
}; };
//! \brief Button type
typedef PIPair<PIString, PIScreenTypes::CellFormat> Button; typedef PIPair<PIString, PIScreenTypes::CellFormat> Button;
//! \brief Button alignment
PIScreenTypes::Alignment alignment; PIScreenTypes::Alignment alignment;
//! \brief Button content
PIVector<Button> content; PIVector<Button> content;
//! \brief Current selection
int cur; int cur;
protected: protected:
//! \brief
//! \~english Calculates tile size hint
//! \~russian Вычисляет рекомендуемый размер тайла
void sizeHint(int & w, int & h) const override; void sizeHint(int & w, int & h) const override;
//! \brief
//! \~english Draws tile content
//! \~russian Рисует содержимое тайла
void drawEvent(PIScreenDrawer * d) override; void drawEvent(PIScreenDrawer * d) override;
//! \brief
//! \~english Handles key events
//! \~russian Обрабатывает события клавиатуры
bool keyEvent(PIKbdListener::KeyEvent key) override; bool keyEvent(PIKbdListener::KeyEvent key) override;
//! \brief
//! \~english Handles mouse events
//! \~russian Обрабатывает события мыши
bool mouseEvent(PIKbdListener::MouseEvent me) override; bool mouseEvent(PIKbdListener::MouseEvent me) override;
//! \brief Button rectangle
struct Rect { struct Rect {
Rect(int _x0 = 0, int _y0 = 0, int _x1 = 0, int _y1 = 0): x0(_x0), y0(_y0), x1(_x1), y1(_y1) {} 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; int x0, y0, x1, y1;
@@ -360,192 +157,74 @@ protected:
}; };
//! \brief
//! \~english Checkbox with toggle state
//! \~russian Флажок с переключаемым состоянием
class PIP_CONSOLE_EXPORT TileCheck: public PIScreenTile { class PIP_CONSOLE_EXPORT TileCheck: public PIScreenTile {
PIOBJECT_SUBCLASS(TileCheck, PIScreenTile); PIOBJECT_SUBCLASS(TileCheck, PIScreenTile);
public: public:
//! \brief
//! \~english Constructs TileCheck
//! \~russian Создает TileCheck
//! \param n Tile name / Имя тайла
TileCheck(const PIString & n = PIString()); TileCheck(const PIString & n = PIString());
//! \brief
//! \~english Destructor
//! \~russian Деструктор
virtual ~TileCheck() {} virtual ~TileCheck() {}
//! \brief Event type
enum EventType { enum EventType {
Toggled //!< State toggled / Состояние переключено Toggled
}; };
//! \brief Checkbox format
PIScreenTypes::CellFormat format; PIScreenTypes::CellFormat format;
//! \brief Checkbox text
PIString text; PIString text;
//! \brief Checkbox state
bool toggled; bool toggled;
protected: protected:
//! \brief
//! \~english Calculates tile size hint
//! \~russian Вычисляет рекомендуемый размер тайла
void sizeHint(int & w, int & h) const override; void sizeHint(int & w, int & h) const override;
//! \brief
//! \~english Draws tile content
//! \~russian Рисует содержимое тайла
void drawEvent(PIScreenDrawer * d) override; void drawEvent(PIScreenDrawer * d) override;
//! \brief
//! \~english Handles key events
//! \~russian Обрабатывает события клавиатуры
bool keyEvent(PIKbdListener::KeyEvent key) override; bool keyEvent(PIKbdListener::KeyEvent key) override;
//! \brief
//! \~english Handles mouse events
//! \~russian Обрабатывает события мыши
bool mouseEvent(PIKbdListener::MouseEvent me) override; bool mouseEvent(PIKbdListener::MouseEvent me) override;
}; };
//! \brief
//! \~english Progress bar for displaying progress
//! \~russian Индикатор прогресса
class PIP_CONSOLE_EXPORT TileProgress: public PIScreenTile { class PIP_CONSOLE_EXPORT TileProgress: public PIScreenTile {
PIOBJECT_SUBCLASS(TileProgress, PIScreenTile); PIOBJECT_SUBCLASS(TileProgress, PIScreenTile);
public: public:
//! \brief
//! \~english Constructs TileProgress
//! \~russian Создает TileProgress
//! \param n Tile name / Имя тайла
TileProgress(const PIString & n = PIString()); TileProgress(const PIString & n = PIString());
//! \brief
//! \~english Destructor
//! \~russian Деструктор
virtual ~TileProgress() {} virtual ~TileProgress() {}
//! \brief Progress format
PIScreenTypes::CellFormat format; PIScreenTypes::CellFormat format;
//! \brief Prefix text
PIString prefix; PIString prefix;
//! \brief Suffix text
PIString suffix; PIString suffix;
//! \brief Maximum value
double maximum; double maximum;
//! \brief Current value
double value; double value;
protected: protected:
//! \brief
//! \~english Calculates tile size hint
//! \~russian Вычисляет рекомендуемый размер тайла
void sizeHint(int & w, int & h) const override; void sizeHint(int & w, int & h) const override;
//! \brief
//! \~english Draws tile content
//! \~russian Рисует содержимое тайла
void drawEvent(PIScreenDrawer * d) override; void drawEvent(PIScreenDrawer * d) override;
}; };
//! \brief
//! \~english Tile for displaying console output
//! \~russian Тайл для отображения консольного вывода
class PIP_CONSOLE_EXPORT TilePICout: public TileList { class PIP_CONSOLE_EXPORT TilePICout: public TileList {
PIOBJECT_SUBCLASS(TilePICout, PIScreenTile); PIOBJECT_SUBCLASS(TilePICout, PIScreenTile);
public: public:
//! \brief
//! \~english Constructs TilePICout
//! \~russian Создает TilePICout
//! \param n Tile name / Имя тайла
TilePICout(const PIString & n = PIString()); TilePICout(const PIString & n = PIString());
//! \brief
//! \~english Destructor
//! \~russian Деструктор
virtual ~TilePICout() {} virtual ~TilePICout() {}
//! \brief Output format
PIScreenTypes::CellFormat format; PIScreenTypes::CellFormat format;
//! \brief Maximum lines
int max_lines; int max_lines;
protected: protected:
//! \brief
//! \~english Draws tile content
//! \~russian Рисует содержимое тайла
void drawEvent(PIScreenDrawer * d) override; void drawEvent(PIScreenDrawer * d) override;
//! \brief
//! \~english Handles key events
//! \~russian Обрабатывает события клавиатуры
bool keyEvent(PIKbdListener::KeyEvent key) override; bool keyEvent(PIKbdListener::KeyEvent key) override;
}; };
//! \brief
//! \~english Text input tile
//! \~russian Тайл текстового ввода
class PIP_CONSOLE_EXPORT TileInput: public PIScreenTile { class PIP_CONSOLE_EXPORT TileInput: public PIScreenTile {
PIOBJECT_SUBCLASS(TileInput, PIScreenTile); PIOBJECT_SUBCLASS(TileInput, PIScreenTile);
public: public:
//! \brief
//! \~english Constructs TileInput
//! \~russian Создает TileInput
//! \param n Tile name / Имя тайла
TileInput(const PIString & n = PIString()); TileInput(const PIString & n = PIString());
//! \brief
//! \~english Destructor
//! \~russian Деструктор
virtual ~TileInput() {} virtual ~TileInput() {}
//! \brief Input format
PIScreenTypes::CellFormat format; PIScreenTypes::CellFormat format;
//! \brief Input text
PIString text; PIString text;
//! \brief Maximum text length
int max_length; int max_length;
protected: protected:
//! \brief
//! \~english Calculates tile size hint
//! \~russian Вычисляет рекомендуемый размер тайла
void sizeHint(int & w, int & h) const override; void sizeHint(int & w, int & h) const override;
//! \brief
//! \~english Draws tile content
//! \~russian Рисует содержимое тайла
void drawEvent(PIScreenDrawer * d) override; void drawEvent(PIScreenDrawer * d) override;
//! \brief
//! \~english Handles key events
//! \~russian Обрабатывает события клавиатуры
bool keyEvent(PIKbdListener::KeyEvent key) override; bool keyEvent(PIKbdListener::KeyEvent key) override;
//! \brief
//! \~english Resets cursor position
//! \~russian Сбрасывает позицию курсора
void reserCursor(); void reserCursor();
int cur, offset; int cur, offset;
bool inv; bool inv;

View File

@@ -1,11 +1,9 @@
//! \file piscreentypes.h /*! \file piscreentypes.h
//! \ingroup Console * \ingroup Console
//! \brief * \~\brief
//! \~english Types for PIScreen * \~english Types for PIScreen
//! \~russian Типы для PIScreen * \~russian Типы для PIScreen
//! \details */
//! \~english Provides common types used by screen tiles and drawer.
//! \~russian Обеспечивает общие типы, используемые тайлами и отрисовщиком экрана.
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Types for PIScreen Types for PIScreen
@@ -36,9 +34,7 @@ class PIScreenTile;
namespace PIScreenTypes { namespace PIScreenTypes {
//! \brief Color for chars or background //! Color for chars or background
//! \~english Console color values
//! \~russian Значения цветов консоли
enum Color { enum Color {
Default /** Default */, Default /** Default */,
Black /** Black */, Black /** Black */,
@@ -52,9 +48,7 @@ enum Color {
Transparent /** Save previous color */ Transparent /** Save previous color */
}; };
//! \brief Flags for chars //! Flags for chars
//! \~english Character formatting flags
//! \~russian Флаги форматирования символов
enum CharFlag { enum CharFlag {
Bold /** Bold or bright */ = 0x1, Bold /** Bold or bright */ = 0x1,
Blink /** Blink text */ = 0x2, Blink /** Blink text */ = 0x2,
@@ -62,18 +56,14 @@ enum CharFlag {
Inverse = 0x08 Inverse = 0x08
}; };
//! \brief Alignment //! Alignment
//! \~english Text alignment modes
//! \~russian Режимы выравнивания текста
enum Alignment { enum Alignment {
Left /** Left */, Left /** Left */,
Center /** Center */, Center /** Center */,
Right /** Right */ Right /** Right */
}; };
//! \brief Size policy //! Size policy
//! \~english Tile sizing policies
//! \~russian Политики размеров тайлов
enum SizePolicy { enum SizePolicy {
Fixed /** Fixed size */, Fixed /** Fixed size */,
Preferred /** Preferred size */, Preferred /** Preferred size */,
@@ -81,17 +71,13 @@ enum SizePolicy {
Ignore /** Ignore layout logic */ Ignore /** Ignore layout logic */
}; };
//! \brief Direction //! Direction
//! \~english Layout directions
//! \~russian Направления компоновки
enum Direction { enum Direction {
Horizontal /** Horizontal */, Horizontal /** Horizontal */,
Vertical /** Vertical */ Vertical /** Vertical */
}; };
//! \brief Focus flags //! Focus flags
//! \~english Tile focus behavior flags
//! \~russian Флаги поведения фокуса тайла
enum FocusFlag { enum FocusFlag {
CanHasFocus /** Tile can has focus */ = 0x1, CanHasFocus /** Tile can has focus */ = 0x1,
NextByTab /** Focus passed to next tile by tab key */ = 0x2, NextByTab /** Focus passed to next tile by tab key */ = 0x2,
@@ -106,19 +92,8 @@ enum FocusFlag {
typedef PIFlags<CharFlag> CharFlags; typedef PIFlags<CharFlag> CharFlags;
typedef PIFlags<FocusFlag> FocusFlags; typedef PIFlags<FocusFlag> FocusFlags;
//! \brief Cell format union
//! \~english Packed cell formatting data
//! \~russian Упакованные данные форматирования ячейки
union PIP_CONSOLE_EXPORT CellFormat { union PIP_CONSOLE_EXPORT CellFormat {
//! \brief
//! \~english Constructs CellFormat from raw value
//! \~russian Создает CellFormat из сырого значения
CellFormat(ushort f = 0) { raw_format = f; } CellFormat(ushort f = 0) { raw_format = f; }
//! \brief
//! \~english Constructs CellFormat from color and flags
//! \~russian Создает CellFormat из цвета и флагов
CellFormat(Color col_char, Color col_back = Default, CharFlags flags_ = 0) { CellFormat(Color col_char, Color col_back = Default, CharFlags flags_ = 0) {
color_char = col_char; color_char = col_char;
color_back = col_back; color_back = col_back;
@@ -130,49 +105,19 @@ union PIP_CONSOLE_EXPORT CellFormat {
ushort color_back: 4; ushort color_back: 4;
ushort flags : 8; ushort flags : 8;
}; };
//! \brief
//! \~english Equality operator
//! \~russian Оператор равенства
bool operator==(const CellFormat & c) const { return raw_format == c.raw_format; } bool operator==(const CellFormat & c) const { return raw_format == c.raw_format; }
//! \brief
//! \~english Inequality operator
//! \~russian Оператор неравенства
bool operator!=(const CellFormat & c) const { return raw_format != c.raw_format; } bool operator!=(const CellFormat & c) const { return raw_format != c.raw_format; }
}; };
//! \brief Screen cell
//! \~english Single character cell with formatting
//! \~russian Одна символьная ячейка с форматированием
struct PIP_CONSOLE_EXPORT Cell { struct PIP_CONSOLE_EXPORT Cell {
//! \brief
//! \~english Constructs Cell
//! \~russian Создает Cell
Cell(PIChar c = PIChar(' '), CellFormat f = CellFormat()) { Cell(PIChar c = PIChar(' '), CellFormat f = CellFormat()) {
symbol = c; symbol = c;
format = f; format = f;
} }
//! \brief Cell format
CellFormat format; CellFormat format;
//! \brief Cell character
PIChar symbol; PIChar symbol;
//! \brief
//! \~english Equality operator
//! \~russian Оператор равенства
bool operator==(const Cell & c) const { return format == c.format && symbol == c.symbol; } bool operator==(const Cell & c) const { return format == c.format && symbol == c.symbol; }
//! \brief
//! \~english Inequality operator
//! \~russian Оператор неравенства
bool operator!=(const Cell & c) const { return format != c.format || symbol != c.symbol; } bool operator!=(const Cell & c) const { return format != c.format || symbol != c.symbol; }
//! \brief
//! \~english Assignment operator
//! \~russian Оператор присваивания
Cell & operator=(const Cell & c) { Cell & operator=(const Cell & c) {
symbol = c.symbol; symbol = c.symbol;
if (c.format.color_back == Transparent) { if (c.format.color_back == Transparent) {
@@ -184,52 +129,18 @@ struct PIP_CONSOLE_EXPORT Cell {
} }
}; };
//! \brief Tile event data
//! \~english Event data passed to tiles
//! \~russian Данные события, передаваемые тайлам
struct PIP_CONSOLE_EXPORT TileEvent { struct PIP_CONSOLE_EXPORT TileEvent {
//! \brief
//! \~english Constructs TileEvent
//! \~russian Создает TileEvent
//! \param t Event type / Тип события
//! \param d Event data / Данные события
TileEvent(int t = -1, const PIVariant & d = PIVariant()): type(t), data(d) {} TileEvent(int t = -1, const PIVariant & d = PIVariant()): type(t), data(d) {}
//! \brief Event type
int type; int type;
//! \brief Event data
PIVariant data; PIVariant data;
}; };
//! \brief Base screen interface
//! \~english Base interface for screen tiles
//! \~russian Базовый интерфейс для экранных тайлов
class PIP_CONSOLE_EXPORT PIScreenBase { class PIP_CONSOLE_EXPORT PIScreenBase {
public: public:
//! \brief
//! \~english Constructs PIScreenBase
//! \~russian Создает PIScreenBase
PIScreenBase() {} PIScreenBase() {}
//! \brief
//! \~english Destructor
//! \~russian Деструктор
virtual ~PIScreenBase() {} virtual ~PIScreenBase() {}
//! \brief
//! \~english Handles internal tile event
//! \~russian Обрабатывает внутреннее событие тайла
virtual void tileEventInternal(PIScreenTile *, TileEvent) {} virtual void tileEventInternal(PIScreenTile *, TileEvent) {}
//! \brief
//! \~english Handles tile removal
//! \~russian Обрабатывает удаление тайла
virtual void tileRemovedInternal(PIScreenTile *) {} virtual void tileRemovedInternal(PIScreenTile *) {}
//! \brief
//! \~english Handles tile focus change
//! \~russian Обрабатывает изменение фокуса тайла
virtual void tileSetFocusInternal(PIScreenTile *) {} virtual void tileSetFocusInternal(PIScreenTile *) {}
}; };

View File

@@ -1,11 +1,9 @@
//! \file piterminal.h /*! \file piterminal.h
//! \ingroup Console * \ingroup Console
//! \brief * \~\brief
//! \~english Virtual terminal * \~english Virtual terminal
//! \~russian Виртуальный терминал * \~russian Виртуальный терминал
//! \details */
//! \~english Provides terminal emulation for reading console input and output.
//! \~russian Обеспечивает эмуляцию терминала для чтения ввода и вывода консоли.
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Virtual terminal Virtual terminal
@@ -37,66 +35,22 @@ class PIP_CONSOLE_EXPORT PITerminal: public PIThread {
PIOBJECT_SUBCLASS(PITerminal, PIThread); PIOBJECT_SUBCLASS(PITerminal, PIThread);
public: public:
//! \brief //! Constructs %PITerminal
//! \~english Constructs PITerminal
//! \~russian Создает PITerminal
PITerminal(); PITerminal();
//! \brief
//! \~english Destructor
//! \~russian Деструктор
~PITerminal(); ~PITerminal();
//! \brief
//! \~english Returns number of columns
//! \~russian Возвращает количество колонок
int columns() const { return size_x; } int columns() const { return size_x; }
//! \brief
//! \~english Returns number of rows
//! \~russian Возвращает количество строк
int rows() const { return size_y; } int rows() const { return size_y; }
//! \brief
//! \~english Resizes terminal
//! \~russian Изменяет размер терминала
//! \param cols Number of columns / Количество колонок
//! \param rows Number of rows / Количество строк
bool resize(int cols, int rows); bool resize(int cols, int rows);
//! \brief
//! \~english Writes data to terminal
//! \~russian Записывает данные в терминал
void write(const PIByteArray & d); void write(const PIByteArray & d);
//! \brief
//! \~english Writes special key to terminal
//! \~russian Записывает специальную клавишу в терминал
void write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers m); void write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers m);
//! \brief
//! \~english Writes key event to terminal
//! \~russian Записывает событие клавиши в терминал
void write(PIKbdListener::KeyEvent ke); void write(PIKbdListener::KeyEvent ke);
//! \brief
//! \~english Returns terminal content
//! \~russian Возвращает содержимое терминала
PIVector<PIVector<PIScreenTypes::Cell>> content(); PIVector<PIVector<PIScreenTypes::Cell>> content();
//! \brief
//! \~english Checks if key is special
//! \~russian Проверяет, является ли клавиша специальной
static bool isSpecialKey(int k); static bool isSpecialKey(int k);
//! \brief
//! \~english Initializes terminal
//! \~russian Инициализирует терминал
bool initialize(); bool initialize();
//! \brief
//! \~english Destroys terminal
//! \~russian Уничтожает терминал
void destroy(); void destroy();
private: private:

View File

@@ -1,17 +1,8 @@
//! \addtogroup Containers /*! \file piset.h
//! \{ * \brief Set container
//! \file piset.h *
//! \brief * This file declare PISet
//! \~english Declares \a PISet */
//! \~russian Объявление \a PISet
//! \~\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 PIP - Platform Independent Primitives
Set container Set container
@@ -36,33 +27,13 @@
#include "pimap.h" #include "pimap.h"
//! \addtogroup Containers /*! \brief Set of any type
//! \{ * \details This class used to store collection of unique elements
//! \class PISet * of any type. You can only add values to set with \a operator<< or
//! \brief * with function \a insert(). You can discover if value already in
//! \~english A set is a collection of unique elements. * set with \a operator[] or with function \a find(). These function
//! \~russian Множество - это коллекция уникальных элементов. * has logarithmic complexity.
//! \~\} */
//! \details
//! \~english
//! This class is used to store a collection of unique elements of any type.
//! You can add values to the set using \a operator<< or the \a insert() function.
//! You can check if a value already exists in the set using \a operator[] or the \a contains() function.
//! These operations have logarithmic complexity.
//! To iterate over all elements, use STL-style iterators \a begin() and \a end().
//!
//! The set is implemented as a wrapper around \a PIMap, where keys are the elements
//! and values are dummy byte values (used only for storage).
//! \~russian
//! Этот класс используется для хранения коллекции уникальных элементов любого типа.
//! Вы можете добавлять значения в множество с помощью \a operator<< или функции \a insert().
//! Вы можете проверить, существует ли значение в множестве, используя \a operator[] или функцию \a contains().
//! Эти операции имеют логарифмическую сложность.
//! Для перебора всех элементов используйте итераторы в стиле STL \a begin() и \a end().
//!
//! Множество реализовано как обёртка над \a PIMap, где ключами являются элементы,
//! а значениями являются фиктивные байтовые значения (используются только для хранения).
//! \~\sa \a PIMap, \a PIVector
template<typename T> template<typename T>
class PISet: public PIMap<T, uchar> { class PISet: public PIMap<T, uchar> {
typedef PIMap<T, uchar> _CSet; typedef PIMap<T, uchar> _CSet;
@@ -72,31 +43,26 @@ class PISet: public PIMap<T, uchar> {
friend PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PISet<T1> & v); friend PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PISet<T1> & v);
public: public:
//! \~english Constructs an empty set. //! Contructs an empty set
//! \~russian Создает пустое множество.
PISet() {} PISet() {}
//! \~english Constructs a set with one element `value`. //! Contructs set with one element "value"
//! \~russian Создает множество с одним элементом `value`.
explicit PISet(const T & value) { _CSet::insert(value, 0); } explicit PISet(const T & value) { _CSet::insert(value, 0); }
//! \~english Constructs a set with two elements `v0` and `v1`. //! Contructs set with elements "v0" and "v1"
//! \~russian Создает множество с двумя элементами `v0` и `v1`.
PISet(const T & v0, const T & v1) { PISet(const T & v0, const T & v1) {
_CSet::insert(v0, 0); _CSet::insert(v0, 0);
_CSet::insert(v1, 0); _CSet::insert(v1, 0);
} }
//! \~english Constructs a set with three elements `v0`, `v1` and `v2`. //! Contructs set with elements "v0", "v1" and "v2"
//! \~russian Создает множество с тремя элементами `v0`, `v1` и `v2`.
PISet(const T & v0, const T & v1, const T & v2) { PISet(const T & v0, const T & v1, const T & v2) {
_CSet::insert(v0, 0); _CSet::insert(v0, 0);
_CSet::insert(v1, 0); _CSet::insert(v1, 0);
_CSet::insert(v2, 0); _CSet::insert(v2, 0);
} }
//! \~english Constructs a set with four elements `v0`, `v1`, `v2` and `v3`. //! Contructs set with elements "v0", "v1", "v2" and "v3"
//! \~russian Создает множество с четырьмя элементами `v0`, `v1`, `v2` и `v3`.
PISet(const T & v0, const T & v1, const T & v2, const T & v3) { PISet(const T & v0, const T & v1, const T & v2, const T & v3) {
_CSet::insert(v0, 0); _CSet::insert(v0, 0);
_CSet::insert(v1, 0); _CSet::insert(v1, 0);
@@ -188,8 +154,7 @@ public:
inline const_iterator begin() const { return const_iterator(this, 0); } inline const_iterator begin() const { return const_iterator(this, 0); }
inline const_iterator end() const { return const_iterator(this, _CSet::size()); } inline const_iterator end() const { return const_iterator(this, _CSet::size()); }
//! \~english Constructs a set from a vector of elements. //! Contructs set from vector of elements
//! \~russian Создает множество из вектора элементов.
explicit PISet(const PIVector<T> & values) { explicit PISet(const PIVector<T> & values) {
if (values.isEmpty()) return; if (values.isEmpty()) return;
for (int i = 0; i < values.size_s(); ++i) { for (int i = 0; i < values.size_s(); ++i) {
@@ -197,8 +162,7 @@ public:
} }
} }
//! \~english Constructs a set from a deque of elements. //! Contructs set from deque of elements
//! \~russian Создает множество из deque элементов.
explicit PISet(const PIDeque<T> & values) { explicit PISet(const PIDeque<T> & values) {
if (values.isEmpty()) return; if (values.isEmpty()) return;
for (int i = 0; i < values.size_s(); ++i) { for (int i = 0; i < values.size_s(); ++i) {
@@ -208,8 +172,6 @@ public:
typedef T key_type; typedef T key_type;
//! \~english Inserts element `t` into the set.
//! \~russian Вставляет элемент `t` в множество.
PISet<T> & operator<<(const T & t) { PISet<T> & operator<<(const T & t) {
_CSet::insert(t, 0); _CSet::insert(t, 0);
return *this; return *this;
@@ -223,62 +185,52 @@ public:
return *this; return *this;
} }
//! \~english Tests if element `t` exists in the set. //! \~english Tests if element `key` exists in the set.
//! \~russian Проверяет наличие элемента `t` в множестве. //! \~russian Проверяет наличие элемента `key` в массиве.
inline bool contains(const T & t) const { return _CSet::contains(t); } inline bool contains(const T & t) const { return _CSet::contains(t); }
//! \~english Tests if element `t` exists in the set. //! Returns if element "t" exists in this set
//! \~russian Проверяет наличие элемента `t` в множестве.
bool operator[](const T & t) const { return _CSet::contains(t); } bool operator[](const T & t) const { return _CSet::contains(t); }
//! \~english Removes element `t` from the set. //! Returns if element "t" exists in this set
//! \~russian Удаляет элемент `t` из множества.
PISet<T> & remove(const T & t) { PISet<T> & remove(const T & t) {
_CSet::remove(t); _CSet::remove(t);
return *this; return *this;
} }
//! \~english Returns the union of this set with set `v`. //! Unite set with "v"
//! \~russian Возвращает объединение этого множества с множеством `v`.
PISet<T> & unite(const PISet<T> & v) { PISet<T> & unite(const PISet<T> & v) {
for (const auto & i: v) for (const auto & i: v)
_CSet::insert(i, 0); _CSet::insert(i, 0);
return *this; return *this;
} }
//! \~english Returns the difference of this set and set `v`. //! Subtract set with "v"
//! \~russian Возвращает разность этого множества и множества `v`.
PISet<T> & subtract(const PISet<T> & v) { PISet<T> & subtract(const PISet<T> & v) {
for (const auto & i: v) for (const auto & i: v)
_CSet::remove(i); _CSet::remove(i);
return *this; return *this;
} }
//! \~english Returns the intersection of this set with set `v`. //! Intersect set with "v"
//! \~russian Возвращает пересечение этого множества с множеством `v`.
PISet<T> & intersect(const PISet<T> & v) { PISet<T> & intersect(const PISet<T> & v) {
_CSet::removeWhere([&v](const T & k, uchar) { return !v.contains(k); }); _CSet::removeWhere([&v](const T & k, uchar) { return !v.contains(k); });
return *this; return *this;
} }
//! \~english Returns the union of this set with set `v`. //! Unite set with "v"
//! \~russian Возвращает объединение этого множества с множеством `v`.
PISet<T> & operator+=(const PISet<T> & v) { return unite(v); } PISet<T> & operator+=(const PISet<T> & v) { return unite(v); }
//! \~english Returns the union of this set with set `v`. //! Unite set with "v"
//! \~russian Возвращает объединение этого множества с множеством `v`.
PISet<T> & operator|=(const PISet<T> & v) { return unite(v); } PISet<T> & operator|=(const PISet<T> & v) { return unite(v); }
//! \~english Returns the difference of this set and set `v`. //! Subtract set with "v"
//! \~russian Возвращает разность этого множества и множества `v`.
PISet<T> & operator-=(const PISet<T> & v) { return subtract(v); } PISet<T> & operator-=(const PISet<T> & v) { return subtract(v); }
//! \~english Returns the intersection of this set with set `v`. //! Intersect set with "v"
//! \~russian Возвращает пересечение этого множества с множеством `v`.
PISet<T> & operator&=(const PISet<T> & v) { return intersect(v); } PISet<T> & operator&=(const PISet<T> & v) { return intersect(v); }
//! \~english Converts the set to a vector. //! Returns content of set as PIVector
//! \~russian Преобразует множество в вектор.
PIVector<T> toVector() const { PIVector<T> toVector() const {
PIVector<T> ret; PIVector<T> ret;
for (const auto & i: *this) for (const auto & i: *this)
@@ -286,8 +238,7 @@ public:
return ret; return ret;
} }
//! \~english Converts the set to a deque. //! Returns content of set as PIDeque
//! \~russian Преобразует множество в deque.
PIDeque<T> toDeque() const { PIDeque<T> toDeque() const {
PIDeque<T> ret; PIDeque<T> ret;
for (const auto & i: *this) for (const auto & i: *this)
@@ -297,8 +248,7 @@ public:
}; };
//! \~english Returns the union of two sets. //! \relatesalso PISet \brief Returns unite of two sets
//! \~russian Возвращает объединение двух множеств.
template<typename T> template<typename T>
PISet<T> operator+(const PISet<T> & v0, const PISet<T> & v1) { PISet<T> operator+(const PISet<T> & v0, const PISet<T> & v1) {
PISet<T> ret(v0); PISet<T> ret(v0);
@@ -306,8 +256,7 @@ PISet<T> operator+(const PISet<T> & v0, const PISet<T> & v1) {
return ret; return ret;
} }
//! \~english Returns the difference of two sets. //! \relatesalso PISet \brief Returns subtraction of two sets
//! \~russian Возвращает разность двух множеств.
template<typename T> template<typename T>
PISet<T> operator-(const PISet<T> & v0, const PISet<T> & v1) { PISet<T> operator-(const PISet<T> & v0, const PISet<T> & v1) {
PISet<T> ret(v0); PISet<T> ret(v0);
@@ -315,8 +264,7 @@ PISet<T> operator-(const PISet<T> & v0, const PISet<T> & v1) {
return ret; return ret;
} }
//! \~english Returns the union of two sets. //! \relatesalso PISet \brief Returns unite of two sets
//! \~russian Возвращает объединение двух множеств.
template<typename T> template<typename T>
PISet<T> operator|(const PISet<T> & v0, const PISet<T> & v1) { PISet<T> operator|(const PISet<T> & v0, const PISet<T> & v1) {
PISet<T> ret(v0); PISet<T> ret(v0);
@@ -324,8 +272,7 @@ PISet<T> operator|(const PISet<T> & v0, const PISet<T> & v1) {
return ret; return ret;
} }
//! \~english Returns the intersection of two sets. //! \relatesalso PISet \brief Returns intersetion of two sets
//! \~russian Возвращает пересечение двух множеств.
template<typename T> template<typename T>
PISet<T> operator&(const PISet<T> & v0, const PISet<T> & v1) { PISet<T> operator&(const PISet<T> & v0, const PISet<T> & v1) {
PISet<T> ret(v0); PISet<T> ret(v0);
@@ -334,9 +281,6 @@ PISet<T> operator&(const PISet<T> & v0, const PISet<T> & v1) {
} }
//! \relatesalso PICout
//! \~english Output operator to \a PICout
//! \~russian Оператор вывода в \a PICout
template<typename Type> template<typename Type>
inline PICout operator<<(PICout s, const PISet<Type> & v) { inline PICout operator<<(PICout s, const PISet<Type> & v) {
s.space(); s.space();
@@ -353,6 +297,4 @@ inline PICout operator<<(PICout s, const PISet<Type> & v) {
return s; return s;
} }
//! \}
#endif // PISET_H #endif // PISET_H

View File

@@ -835,8 +835,8 @@ public:
//! piCout << v.contains({1,4}); // true //! piCout << v.contains({1,4}); // true
//! piCout << v.contains({1,5}); // false //! piCout << v.contains({1,5}); // false
//! \endcode //! \endcode
//! \~\sa \a every(), \a any(), \a entries(), \a forEach() //! \~\sa \a every(), \a any(), \a entries(), \a forEach(), \a contains()
inline bool contains(const PIVector<T> & v, ssize_t start = 0) const { inline bool containsAll(const PIVector<T> & v, ssize_t start = 0) const {
if (start < 0) { if (start < 0) {
start = piv_size + start; start = piv_size + start;
if (start < 0) start = 0; if (start < 0) start = 0;
@@ -854,6 +854,24 @@ public:
return true; return true;
} }
//! \~english Tests if any element of `v` exists in the array.
//! \~russian Проверяет наличие хотя бы одного из элементов `v` в массиве.
//! \~\sa \a containsAll(), \a contains()
inline bool containsAny(const PIVector<T> & v, ssize_t start = 0) const {
if (start < 0) {
start = piv_size + start;
if (start < 0) start = 0;
}
for (const T & e: v) {
for (size_t i = start; i < piv_size; ++i) {
if (e == piv_data[i]) {
return true;
}
}
}
return false;
}
//! \~english Count elements equal `e` in the array. //! \~english Count elements equal `e` in the array.
//! \~russian Подсчитывает количество элементов, совпадающих с элементом `e` в массиве. //! \~russian Подсчитывает количество элементов, совпадающих с элементом `e` в массиве.
//! \~\details //! \~\details
@@ -1303,14 +1321,16 @@ public:
//! piCout << v; // {1, 3, 7, 5} //! piCout << v; // {1, 3, 7, 5}
//! \endcode //! \endcode
//! \~\sa \a append(), \a prepend(), \a remove() //! \~\sa \a append(), \a prepend(), \a remove()
inline PIVector<T> & insert(size_t index, const T & e = T()) { inline PIVector<T> & insert(size_t index, const T & e = T(), size_t count = 1) {
alloc(piv_size + 1); alloc(piv_size + count);
if (index < piv_size - 1) { if (index < piv_size - count) {
const size_t os = piv_size - index - 1; const size_t os = piv_size - index - count;
memmove(reinterpret_cast<void *>(piv_data + index + 1), reinterpret_cast<const void *>(piv_data + index), os * sizeof(T)); memmove(reinterpret_cast<void *>(piv_data + index + count), reinterpret_cast<const void *>(piv_data + index), os * sizeof(T));
}
PIINTROSPECTION_CONTAINER_USED(T, count)
for (size_t i = 0; i < count; ++i) {
elementNew(piv_data + index + i, e);
} }
PIINTROSPECTION_CONTAINER_USED(T, 1)
elementNew(piv_data + index, e);
return *this; return *this;
} }
@@ -1349,8 +1369,8 @@ public:
alloc(piv_size + v.piv_size); alloc(piv_size + v.piv_size);
if (os > 0) { if (os > 0) {
memmove(reinterpret_cast<void *>(piv_data + index + v.piv_size), memmove(reinterpret_cast<void *>(piv_data + index + v.piv_size),
reinterpret_cast<const void *>(piv_data + index), reinterpret_cast<const void *>(piv_data + index),
os * sizeof(T)); os * sizeof(T));
} }
newT(piv_data + index, v.piv_data, v.piv_size); newT(piv_data + index, v.piv_data, v.piv_size);
return *this; return *this;
@@ -1372,8 +1392,8 @@ public:
alloc(piv_size + init_list.size()); alloc(piv_size + init_list.size());
if (os > 0) { if (os > 0) {
memmove(reinterpret_cast<void *>(piv_data + index + init_list.size()), memmove(reinterpret_cast<void *>(piv_data + index + init_list.size()),
reinterpret_cast<const void *>(piv_data + index), reinterpret_cast<const void *>(piv_data + index),
os * sizeof(T)); os * sizeof(T));
} }
newT(piv_data + index, init_list.begin(), init_list.size()); newT(piv_data + index, init_list.begin(), init_list.size());
return *this; return *this;

View File

@@ -1,15 +1,8 @@
//! \addtogroup Containers /*! \file pivector2d.h
//! \{ * \brief 2D wrapper around PIVector
//! \file pivector2d.h *
//! \brief * This file declares PIVector2D
//! \~english Declares \a PIVector2D */
//! \~russian Объявление \a PIVector2D
//! \~\authors
//! \~english
//! Andrey Bychkov work.a.b@yandex.ru;
//! \~russian
//! Андрей Бычков work.a.b@yandex.ru;
//! \~\}
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
2D wrapper around PIVector 2D wrapper around PIVector
@@ -32,7 +25,6 @@
#ifndef PIVECTOR2D_H #ifndef PIVECTOR2D_H
#define PIVECTOR2D_H #define PIVECTOR2D_H
#include "pipair.h"
#include "pivector.h" #include "pivector.h"
//! \addtogroup Containers //! \addtogroup Containers
@@ -50,7 +42,7 @@
//! (use \a resize(), \a addRow(), \a removeRow(), \a removeColumn() instead), but you can modify the values of existing elements. //! (use \a resize(), \a addRow(), \a removeRow(), \a removeColumn() instead), but you can modify the values of existing elements.
//! \~russian //! \~russian
//! Этот класс используется для хранения двумерного массива элементов любого типа в виде единого непрерывного блока памяти (обычного //! Этот класс используется для хранения двумерного массива элементов любого типа в виде единого непрерывного блока памяти (обычного
//! PIVector). Доступ к элементам осуществляется с помощью операторов `[][]`, где первый индекс — это строка, а второй — столбец. Со //! \a PIVector). Доступ к элементам осуществляется с помощью операторов `[][]`, где первый индекс — это строка, а второй — столбец. Со
//! строками можно работать как с объектами \a PIVector, что позволяет изменять отдельные элементы или присваивать целые строки. Нельзя //! строками можно работать как с объектами \a PIVector, что позволяет изменять отдельные элементы или присваивать целые строки. Нельзя
//! напрямую добавлять или удалять элементы, чтобы изменить размеры массива после создания (используйте \a resize(), \a addRow(), \a //! напрямую добавлять или удалять элементы, чтобы изменить размеры массива после создания (используйте \a resize(), \a addRow(), \a
//! removeRow(), \a removeColumn() для этого), но можно изменять значения существующих элементов. //! removeRow(), \a removeColumn() для этого), но можно изменять значения существующих элементов.
@@ -59,21 +51,51 @@
template<typename T> template<typename T>
class PIVector2D { class PIVector2D {
public: public:
//! \~english Constructs an empty 2D array. //! \brief
//! \~russian Создает пустой двумерный массив. //! \~english Index structure for 2D array elements (row, column).
//! \~russian Структура индекса для элементов двумерного массива (строка, столбец).
struct Index {
//! \~english Row index in the 2D array.
//! \~russian Индекс строки в двумерном массиве.
ssize_t row = -1;
//! \~english Column index in the 2D array.
//! \~russian Индекс столбца в двумерном массиве.
ssize_t col = -1;
//! \~english Default constructor. Initializes row and col to -1 (invalid index).
//! \~russian Конструктор по умолчанию. Инициализирует row и col значениями -1 (некорректный индекс).
inline Index() = default;
//! \~english Constructs an Index with the given row and column values.
//! \~russian Создаёт Index с заданными значениями строки и столбца.
inline Index(ssize_t r, ssize_t c): row(r), col(c) {}
//! \~english Checks if the index is valid (both row and column are non-negative).
//! \~russian Проверяет, является ли индекс корректным (строка и столбец неотрицательны).
//! \~\sa isNotValid()
inline bool isValid() const { return row >= 0 && col >= 0; }
//! \~english Checks if the index is invalid (either row or column is negative).
//! \~russian Проверяет, является ли индекс некорректным (строка или столбец отрицательны).
//! \~\sa isValid()
inline bool isNotValid() const { return !isValid(); }
};
//! \~english Constructs an empty 2D array. No memory is allocated.
//! \~russian Создаёт пустой двумерный массив. Память не выделяется.
//! \details
//! \~english After this constructor, \a rows() and \a cols() return 0, and \a isEmpty() returns true.
//! \~russian После этого конструктора \a rows() и \a cols() возвращают 0, а \a isEmpty() возвращает true.
//! \~\sa PIVector::PIVector()
inline PIVector2D() { rows_ = cols_ = 0; } inline PIVector2D() { rows_ = cols_ = 0; }
//! \~english Constructs a 2D array with the given dimensions, filled with copies of `f`. //! \~english Constructs a 2D array with the given dimensions, filled with copies of `f`.
//! \~russian Создает двумерный массив заданного размера, заполненный копиями `f`. //! \~russian Создаёт двумерный массив заданного размера, заполненный копиями `f`.
//! \param rows Number of rows. //! \details
//! \param cols Number of columns. //! \~english The underlying storage is a single contiguous block of memory of size `rows * cols`.
//! \param f Value to fill the array with. //! All elements are initialized with the value `f`.
//! \~english \param rows Количество строк. //! \~russian Внутреннее хранилище представляет собой единый непрерывный блок памяти размером `rows * cols`.
//! \~russian \param rows Количество строк. //! Все элементы инициализируются значением `f`.
//! \~english \param cols Количество столбцов. //! \~\sa PIVector::PIVector(size_t, const T&)
//! \~russian \param cols Количество столбцов.
//! \~english \param f Значение для заполнения массива.
//! \~russian \param f Значение для заполнения массива.
inline PIVector2D(size_t rows, size_t cols, const T & f = T()) { inline PIVector2D(size_t rows, size_t cols, const T & f = T()) {
rows_ = rows; rows_ = rows;
cols_ = cols; cols_ = cols;
@@ -81,22 +103,35 @@ public:
} }
//! \~english Constructs a 2D array from an existing 1D vector, reshaping it. //! \~english Constructs a 2D array from an existing 1D vector, reshaping it.
//! \~russian Создает двумерный массив из существующего одномерного вектора, изменяя его форму. //! \~russian Создаёт двумерный массив из существующего одномерного вектора, изменяя его форму.
//! \param rows Number of rows. //! \details
//! \param cols Number of columns. //! \~english The constructor copies the data from `v` into the internal flat vector.
//! \param v The source 1D vector. Its size must be at least `rows * cols`. //! If `v` is larger than `rows * cols`, the excess elements are ignored (the vector is truncated).
//! If `v` is smaller, other values filled whith default cunstructor T()
//! \~russian Конструктор копирует данные из `v` во внутренний плоский вектор.
//! Если `v` больше, чем `rows * cols`, лишние элементы игнорируются (вектор обрезается).
//! Если `v` меньше, остальные значения будут заполнены из конструктора по умолчанию T()
//! \~\sa PIVector::PIVector(const PIVector&), reshape()
inline PIVector2D(size_t rows, size_t cols, const PIVector<T> & v): rows_(rows), cols_(cols), mat(v) { mat.resize(rows * cols); } inline PIVector2D(size_t rows, size_t cols, const PIVector<T> & v): rows_(rows), cols_(cols), mat(v) { mat.resize(rows * cols); }
//! \~english Move constructs a 2D array from an existing 1D vector, reshaping it. //! \~english Move constructs a 2D array from an existing 1D vector, reshaping it.
//! \~russian Конструктор перемещения из существующего одномерного вектора, изменяя его форму. //! \~russian Конструктор перемещения из существующего одномерного вектора, изменяя его форму.
//! \param rows Number of rows. //! \details
//! \param cols Number of columns. //! \~english The data is moved from `v` into the internal flat vector, avoiding a copy.
//! \param v The source 1D vector (rvalue reference). Its size must be at least `rows * cols`. //! After construction, `v` is left in a valid but unspecified state.
//! \~russian Данные перемещаются из `v` во внутренний плоский вектор, что позволяет избежать копирования.
//! После завершения конструктора `v` остаётся в корректном, но неопределённом состоянии.
//! \~\sa PIVector::PIVector(PIVector&&)
inline PIVector2D(size_t rows, size_t cols, PIVector<T> && v): rows_(rows), cols_(cols), mat(std::move(v)) { mat.resize(rows * cols); } inline PIVector2D(size_t rows, size_t cols, PIVector<T> && v): rows_(rows), cols_(cols), mat(std::move(v)) { mat.resize(rows * cols); }
//! \~english Constructs a 2D array from a vector of vectors (jagged array). Assumes all inner vectors have the same size. //! \~english Constructs a 2D array from a vector of vectors (jagged array). Assumes all inner vectors have the same size.
//! \~russian Создает двумерный массив из вектора векторов (рваного массива). Предполагается, что все внутренние векторы имеют //! \~russian Создаёт двумерный массив из вектора векторов (рваного массива). Предполагается, что все внутренние векторы имеют
//! одинаковый размер. \param v The source vector of vectors. //! одинаковый размер.
//! \details
//! \~english If the input is empty, the constructed array is also empty. Otherwise, the number of columns is taken from the size of the
//! first inner vector. All inner vectors are concatenated in the internal flat storage.
//! \~russian Если входной массив пуст, создаётся пустой двумерный массив. В противном случае количество столбцов берётся из размера
//! первого внутреннего вектора. Все внутренние векторы конкатенируются во внутреннем плоском хранилище. \sa PIVector::append()
inline PIVector2D(const PIVector<PIVector<T>> & v) { inline PIVector2D(const PIVector<PIVector<T>> & v) {
rows_ = v.size(); rows_ = v.size();
if (rows_) { if (rows_) {
@@ -110,240 +145,97 @@ public:
if (mat.isEmpty()) rows_ = cols_ = 0; if (mat.isEmpty()) rows_ = cols_ = 0;
} }
//! \~english Number of rows. //! \~english Returns the number of rows in the 2D array.
//! \~russian Количество строк. //! \~russian Возвращает количество строк в двумерном массиве.
//! \return Number of rows.
//! \details
//! \~english The result is always non-negative. If the array is empty, returns 0.
//! \~russian Результат всегда неотрицательный. Если массив пуст, возвращает 0.
//! \~\sa cols(), size(), PIVector::size()
inline size_t rows() const { return rows_; } inline size_t rows() const { return rows_; }
//! \~english Number of columns. //! \~english Returns the number of columns in the 2D array.
//! \~russian Количество столбцов. //! \~russian Возвращает количество столбцов в двумерном массиве.
//! \return Number of columns.
//! \details
//! \~english The result is always non-negative. If the array is empty, returns 0.
//! \~russian Результат всегда неотрицательный. Если массив пуст, возвращает 0.
//! \~\sa rows(), size(), PIVector::size()
inline size_t cols() const { return cols_; } inline size_t cols() const { return cols_; }
//! \~english Total number of elements (`rows * cols`). //! \~english Returns the total number of elements (`rows * cols`).
//! \~russian Общее количество элементов (`строки * столбцы`). //! \~russian Возвращает общее количество элементов (`строки * столбцы`).
//! \return Total number of elements.
//! \details
//! \~english This is equivalent to the size of the underlying flat vector.
//! \~russian Это эквивалентно размеру внутреннего плоского вектора.
//! \~\sa rows(), cols(), PIVector::size()
inline size_t size() const { return mat.size(); } inline size_t size() const { return mat.size(); }
//! \~english Total number of elements as signed value. //! \~english Returns the total number of elements as a signed value.
//! \~russian Общее количество элементов в виде знакового числа. //! \~russian Возвращает общее количество элементов в виде знакового числа.
//! \return Signed size.
//! \~\sa size(), PIVector::size_s()
inline ssize_t size_s() const { return mat.size_s(); } inline ssize_t size_s() const { return mat.size_s(); }
//! \~english Total number of elements. //! \~english Returns the total number of elements (same as \a size()).
//! \~russian Общее количество элементов. //! \~russian Возвращает общее количество элементов (то же, что и \a size()).
//! \return Total number of elements.
//! \~\sa size(), PIVector::length()
inline size_t length() const { return mat.length(); } inline size_t length() const { return mat.length(); }
//! \~english Number of elements that the underlying container has currently allocated space for. //! \~english Returns the number of elements that the underlying container has currently allocated space for.
//! \~russian Количество элементов, для которого сейчас выделена память во внутреннем контейнере. //! \~russian Возвращает количество элементов, для которого сейчас выделена память во внутреннем контейнере.
//! \return Capacity of the flat vector.
//! \details
//! \~english This value may be larger than \a size(). It indicates how many elements can be added before a reallocation is needed.
//! \~russian Это значение может быть больше, чем \a size(). Оно показывает, сколько элементов можно добавить до того, как потребуется
//! перераспределение памяти. \sa reserve(), PIVector::capacity()
inline size_t capacity() const { return mat.capacity(); } inline size_t capacity() const { return mat.capacity(); }
//! \~english Checks if the array has no elements. //! \~english Checks if the array has no elements.
//! \~russian Проверяет, пуст ли массив. //! \~russian Проверяет, пуст ли массив.
//! \return \c true if the array is empty, \c false otherwise.
//! \details
//! \~english An empty array has both rows and columns equal to 0.
//! \~russian Пустой массив имеет и строки, и столбцы равные 0.
//! \~\sa isNotEmpty(), PIVector::isEmpty()
inline bool isEmpty() const { return mat.isEmpty(); } inline bool isEmpty() const { return mat.isEmpty(); }
//! \~english Checks if the array has elements. //! \~english Checks if the array has at least one element.
//! \~russian Проверяет, не пуст ли массив. //! \~russian Проверяет, не пуст ли массив.
//! \return \c true if the array is not empty, \c false otherwise.
//! \~\sa isEmpty(), PIVector::isNotEmpty()
inline bool isNotEmpty() const { return mat.isNotEmpty(); } inline bool isNotEmpty() const { return mat.isNotEmpty(); }
class RowConst;
class ColConst;
class Row;
class Col;
//! \class Row
//! \brief
//! \~english Proxy class representing a single row in a \a PIVector2D for modification.
//! \~russian Прокси-класс, представляющий одну строку в \a PIVector2D для модификации.
class Row {
friend class PIVector2D<T>;
private:
inline Row(PIVector2D<T> * p, size_t row): p_(&(p->mat)) {
st_ = p->cols_ * row;
sz_ = p->cols_;
}
PIVector<T> * p_;
size_t st_, sz_;
public:
//! \~english Size of the row (number of columns).
//! \~russian Размер строки (количество столбцов).
inline size_t size() const { return sz_; }
//! \~english Accesses the element at the given column index within the row.
//! \~russian Доступ к элементу по заданному индексу столбца в строке.
inline T & operator[](size_t index) { return (*p_)[st_ + index]; }
//! \~english Const access to the element at the given column index within the row.
//! \~russian Константный доступ к элементу по заданному индексу столбца в строке.
inline const T & operator[](size_t index) const { return (*p_)[st_ + index]; }
//! \~english Returns a pointer to the row data starting at an optional offset.
//! \~russian Возвращает указатель на данные строки, начиная с опционального смещения.
inline T * data(size_t index = 0) { return p_->data(st_ + index); }
//! \~english Returns a const pointer to the row data starting at an optional offset.
//! \~russian Возвращает константный указатель на данные строки, начиная с опционального смещения.
inline const T * data(size_t index = 0) const { return p_->data(st_ + index); }
//! \~english Assigns the contents of another Row to this row.
//! \~russian Присваивает этой строке содержимое другой строки.
inline Row & operator=(const Row & other) {
if (p_ == other.p_ && st_ == other.st_) return *this;
const size_t sz = piMin<size_t>(sz_, other.sz_);
p_->_copyRaw(p_->data(st_), other.data(), sz);
return *this;
}
//! \~english Assigns the contents of a \a PIVector to this row.
//! \~russian Присваивает этой строке содержимое \a PIVector.
inline Row & operator=(const PIVector<T> & other) {
const size_t sz = piMin<size_t>(sz_, other.size());
p_->_copyRaw(p_->data(st_), other.data(), sz);
return *this;
}
//! \~english Converts the row to a \a PIVector.
//! \~russian Преобразует строку в \a PIVector.
inline PIVector<T> toVector() const { return PIVector<T>(p_->data(st_), sz_); }
// --- Поиск в строке ---
inline ssize_t indexOf(const T & e, ssize_t start = 0) const {
if (start < 0) start = 0;
for (size_t i = (size_t)start; i < sz_; ++i) {
if ((*p_)[st_ + i] == e) return (ssize_t)i;
}
return -1;
}
inline ssize_t lastIndexOf(const T & e, ssize_t start = -1) const {
ssize_t from = (start < 0 || (size_t)start >= sz_) ? (ssize_t)sz_ - 1 : start;
for (ssize_t i = from; i >= 0; --i) {
if ((*p_)[st_ + i] == e) return i;
}
return -1;
}
inline ssize_t indexWhere(std::function<bool(const T & e)> test, ssize_t start = 0) const {
if (start < 0) start = 0;
for (size_t i = (size_t)start; i < sz_; ++i) {
if (test((*p_)[st_ + i])) return (ssize_t)i;
}
return -1;
}
inline ssize_t lastIndexWhere(std::function<bool(const T & e)> test, ssize_t start = -1) const {
ssize_t from = (start < 0 || (size_t)start >= sz_) ? (ssize_t)sz_ - 1 : start;
for (ssize_t i = from; i >= 0; --i) {
if (test((*p_)[st_ + i])) return i;
}
return -1;
}
};
//! \class Col
//! \brief
//! \~english Proxy class representing a single column in a \a PIVector2D for modification.
//! \~russian Прокси-класс, представляющий один столбец в \a PIVector2D для модификации.
class Col {
friend class PIVector2D<T>;
private:
inline Col(PIVector2D<T> * p, size_t col): p_(&(p->mat)) {
step_ = p->cols_;
col_ = col;
sz_ = p->rows_;
}
PIVector<T> * p_;
size_t step_, col_, sz_;
public:
//! \~english Size of the column (number of rows).
//! \~russian Размер столбца (количество строк).
inline size_t size() const { return sz_; }
//! \~english Accesses the element at the given row index within the column.
//! \~russian Доступ к элементу по заданному индексу строки в столбце.
inline T & operator[](size_t index) { return (*p_)[index * step_ + col_]; }
//! \~english Const access to the element at the given row index within the column.
//! \~russian Константный доступ к элементу по заданному индексу строки в столбце.
inline const T & operator[](size_t index) const { return (*p_)[index * step_ + col_]; }
//! \~english Returns a pointer to the column data starting at an optional row offset.
//! \~russian Возвращает указатель на данные столбца, начиная с опционального смещения по строкам.
inline T * data(size_t index = 0) { return p_->data(index * step_ + col_); }
//! \~english Returns a const pointer to the column data starting at an optional row offset.
//! \~russian Возвращает константный указатель на данные столбца, начиная с опционального смещения по строкам.
inline const T * data(size_t index = 0) const { return p_->data(index * step_ + col_); }
//! \~english Assigns the contents of another Col to this column.
//! \~russian Присваивает этому столбцу содержимое другого столбца.
inline Col & operator=(const Col & other) {
if (p_ == other.p_ && col_ == other.col_) return *this;
const size_t sz = piMin<size_t>(sz_, other.sz_);
for (size_t i = 0; i < sz; ++i)
(*p_)[i * step_ + col_] = other[i];
return *this;
}
//! \~english Assigns the contents of a \a PIVector to this column.
//! \~russian Присваивает этому столбцу содержимое \a PIVector.
inline Col & operator=(const PIVector<T> & other) {
const size_t sz = piMin<size_t>(sz_, other.size());
for (size_t i = 0; i < sz; ++i)
(*p_)[i * step_ + col_] = other[i];
return *this;
}
//! \~english Converts the column to a \a PIVector.
//! \~russian Преобразует столбец в \a PIVector.
inline PIVector<T> toVector() const {
PIVector<T> ret;
ret.reserve(sz_);
for (size_t i = 0; i < sz_; i++)
ret << (*p_)[i * step_ + col_];
return ret;
}
// --- Поиск в столбце ---
inline ssize_t indexOf(const T & e, ssize_t start = 0) const {
if (start < 0) start = 0;
for (size_t i = (size_t)start; i < sz_; ++i) {
if ((*p_)[i * step_ + col_] == e) return (ssize_t)i;
}
return -1;
}
inline ssize_t lastIndexOf(const T & e, ssize_t start = -1) const {
ssize_t from = (start < 0 || (size_t)start >= sz_) ? (ssize_t)sz_ - 1 : start;
for (ssize_t i = from; i >= 0; --i) {
if ((*p_)[i * step_ + col_] == e) return i;
}
return -1;
}
inline ssize_t indexWhere(std::function<bool(const T & e)> test, ssize_t start = 0) const {
if (start < 0) start = 0;
for (size_t i = (size_t)start; i < sz_; ++i) {
if (test((*p_)[i * step_ + col_])) return (ssize_t)i;
}
return -1;
}
inline ssize_t lastIndexWhere(std::function<bool(const T & e)> test, ssize_t start = -1) const {
ssize_t from = (start < 0 || (size_t)start >= sz_) ? (ssize_t)sz_ - 1 : start;
for (ssize_t i = from; i >= 0; --i) {
if (test((*p_)[i * step_ + col_])) return i;
}
return -1;
}
};
//! \class RowConst //! \class RowConst
//! \brief //! \brief
//! \~english Proxy class representing a single read-only row in a \a PIVector2D. //! \~english Proxy class representing a single read-only row in a \a PIVector2D.
//! \~russian Прокси-класс, представляющий одну строку в \a PIVector2D только для чтения. //! \~russian Прокси-класс, представляющий одну строку в \a PIVector2D только для чтения.
//! \details
//! \~english Returned by const \a operator[] or \a row(). Provides const access to row elements.
//! \~russian Возвращается константными версиями \a operator[] или \a row(). Предоставляет константный доступ к элементам строки.
//! \~\sa Row, ColConst
class RowConst { class RowConst {
friend class PIVector2D<T>; friend class PIVector2D<T>;
private: protected:
inline RowConst(const PIVector2D<T> * p, size_t row): p_(&(p->mat)) { inline RowConst(const PIVector2D<T> * p, size_t row): p_(&(p->mat)), st_(p->cols_ * row), sz_(p->cols_) {}
st_ = p->cols_ * row;
sz_ = p->cols_;
}
const PIVector<T> * p_; const PIVector<T> * p_;
size_t st_, sz_; const size_t st_, sz_;
public: public:
//! \~english Copy constructor from modifiable Row to read-only RowConst.
//! \~russian Конструктор копирования из модифицируемого класса Row в константный RowConst.
//! \~\sa Row
inline RowConst(const PIVector2D<T>::Row & r): p_(r.p_), st_(r.st_), sz_(r.sz_) {}
//! \~english Size of the row (number of columns). //! \~english Size of the row (number of columns).
//! \~russian Размер строки (количество столбцов). //! \~russian Размер строки (количество столбцов).
inline size_t size() const { return sz_; } inline size_t size() const { return sz_; }
@@ -360,7 +252,12 @@ public:
//! \~russian Преобразует строку в \a PIVector. //! \~russian Преобразует строку в \a PIVector.
inline PIVector<T> toVector() const { return PIVector<T>(p_->data(st_), sz_); } inline PIVector<T> toVector() const { return PIVector<T>(p_->data(st_), sz_); }
// --- Поиск в строке (только чтение) --- //! \~english Returns the first index of element `e` in the row, starting from `start`.
//! \~russian Возвращает первый индекс элемента `e` в строке, начиная с позиции `start`.
//! \details
//! \~english See \a PIVector::indexOf() for details on negative start handling.
//! \~russian Подробнее об обработке отрицательного `start` см. \a PIVector::indexOf().
//! \~\sa PIVector::indexOf()
inline ssize_t indexOf(const T & e, ssize_t start = 0) const { inline ssize_t indexOf(const T & e, ssize_t start = 0) const {
if (start < 0) start = 0; if (start < 0) start = 0;
for (size_t i = (size_t)start; i < sz_; ++i) { for (size_t i = (size_t)start; i < sz_; ++i) {
@@ -368,6 +265,11 @@ public:
} }
return -1; return -1;
} }
//! \~english Returns the last index of element `e` in the row, searching backwards from `start`.
//! \~russian Возвращает последний индекс элемента `e` в строке, выполняя поиск в обратном направлении от `start`.
//! \return Index if found, -1 otherwise.
//! \~\sa PIVector::lastIndexOf()
inline ssize_t lastIndexOf(const T & e, ssize_t start = -1) const { inline ssize_t lastIndexOf(const T & e, ssize_t start = -1) const {
ssize_t from = (start < 0 || (size_t)start >= sz_) ? (ssize_t)sz_ - 1 : start; ssize_t from = (start < 0 || (size_t)start >= sz_) ? (ssize_t)sz_ - 1 : start;
for (ssize_t i = from; i >= 0; --i) { for (ssize_t i = from; i >= 0; --i) {
@@ -375,6 +277,10 @@ public:
} }
return -1; return -1;
} }
//! \~english Returns the first index where the predicate `test` returns true, starting from `start`.
//! \~russian Возвращает первый индекс, для которого предикат `test` возвращает true, начиная с `start`.
//! \~\sa PIVector::indexWhere()
inline ssize_t indexWhere(std::function<bool(const T & e)> test, ssize_t start = 0) const { inline ssize_t indexWhere(std::function<bool(const T & e)> test, ssize_t start = 0) const {
if (start < 0) start = 0; if (start < 0) start = 0;
for (size_t i = (size_t)start; i < sz_; ++i) { for (size_t i = (size_t)start; i < sz_; ++i) {
@@ -382,6 +288,11 @@ public:
} }
return -1; return -1;
} }
//! \~english Returns the last index where the predicate `test` returns true, searching backwards from `start`.
//! \~russian Возвращает последний индекс, для которого предикат `test` возвращает true,
//! выполняя поиск в обратном направлении от `start`.
//! \~\sa PIVector::lastIndexWhere()
inline ssize_t lastIndexWhere(std::function<bool(const T & e)> test, ssize_t start = -1) const { inline ssize_t lastIndexWhere(std::function<bool(const T & e)> test, ssize_t start = -1) const {
ssize_t from = (start < 0 || (size_t)start >= sz_) ? (ssize_t)sz_ - 1 : start; ssize_t from = (start < 0 || (size_t)start >= sz_) ? (ssize_t)sz_ - 1 : start;
for (ssize_t i = from; i >= 0; --i) { for (ssize_t i = from; i >= 0; --i) {
@@ -389,25 +300,92 @@ public:
} }
return -1; return -1;
} }
//! \~english Applies a function to each element of the row (read-only).
//! \~russian Применяет функцию к каждому элементу строки (только чтение).
//! \details
//! \~english The function can't modify the elements.
//! \~russian Функция не может изменять элементы.
//! \~\sa forEach (modifiable)
inline void forEach(std::function<void(const T &)> func) const {
for (size_t i = 0; i < sz_; ++i) {
func((*p_)[st_ + i]);
}
}
//! \~english Checks if the row contains the element `e`.
//! \~russian Проверяет, содержит ли строка элемент `e`.
//! \~\sa PIVector::contains()
inline bool contains(const T & e, ssize_t start = 0) const { return indexOf(e, start) != -1; }
//! \~english Counts occurrences of `e` in the row.
//! \~russian Подсчитывает количество вхождений `e` в строке.
//! \~\sa PIVector::entries()
inline int entries(const T & e, ssize_t start = 0) const {
if (start < 0) start = 0;
int count = 0;
for (size_t i = (size_t)start; i < sz_; ++i) {
if ((*p_)[st_ + i] == e) ++count;
}
return count;
}
//! \~english Counts elements in the row that pass the `test`.
//! \~russian Подсчитывает элементы в строке, проходящие `test`.
//! \~\sa PIVector::entries(std::function)
inline int entries(std::function<bool(const T & e)> test, ssize_t start = 0) const {
if (start < 0) start = 0;
int count = 0;
for (size_t i = (size_t)start; i < sz_; ++i) {
if (test((*p_)[st_ + i])) ++count;
}
return count;
}
//! \~english Tests if any element in the row passes the `test`.
//! \~russian Проверяет, проходит ли какой-либо элемент в строке `test`.
//! \~\sa PIVector::any()
inline bool any(std::function<bool(const T & e)> test) const {
for (size_t i = 0; i < sz_; ++i) {
if (test((*p_)[st_ + i])) return true;
}
return false;
}
//! \~english Tests if all elements in the row pass the `test`.
//! \~russian Проверяет, проходят ли все элементы в строке `test`.
//! \~\sa PIVector::every()
inline bool every(std::function<bool(const T & e)> test) const {
for (size_t i = 0; i < sz_; ++i) {
if (!test((*p_)[st_ + i])) return false;
}
return true;
}
}; };
//! \class ColConst //! \class ColConst
//! \brief //! \brief
//! \~english Proxy class representing a single read-only column in a \a PIVector2D. //! \~english Proxy class representing a single read-only column in a \a PIVector2D.
//! \~russian Прокси-класс, представляющий один столбец в \a PIVector2D только для чтения. //! \~russian Прокси-класс, представляющий один столбец в \a PIVector2D только для чтения.
//! \details
//! \~english Returned by const \a col(). Provides const access to column elements.
//! \~russian Возвращается константной версией \a col(). Предоставляет константный доступ к элементам столбца.
//! \~\sa Col, RowConst
class ColConst { class ColConst {
friend class PIVector2D<T>; friend class PIVector2D<T>;
private: protected:
inline ColConst(const PIVector2D<T> * p, size_t col): p_(&(p->mat)) { inline ColConst(const PIVector2D<T> * p, size_t col): p_(&(p->mat)), step_(p->cols_), col_(col), sz_(p->rows_) {}
step_ = p->cols_;
col_ = col;
sz_ = p->rows_;
}
const PIVector<T> * p_; const PIVector<T> * p_;
size_t step_, col_, sz_; const size_t step_, col_, sz_;
public: public:
//! \~english Copy constructor from modifiable Col to read-only ColConst.
//! \~russian Конструктор копирования из модифицируемого класса Col в константный ColConst.
//! \~\sa Col
inline ColConst(const PIVector2D<T>::Col & c): p_(c.p_), step_(c.step_), col_(c.col_), sz_(c.sz_) {}
//! \~english Size of the column (number of rows). //! \~english Size of the column (number of rows).
//! \~russian Размер столбца (количество строк). //! \~russian Размер столбца (количество строк).
inline size_t size() const { return sz_; } inline size_t size() const { return sz_; }
@@ -430,7 +408,12 @@ public:
return ret; return ret;
} }
// --- Поиск в столбце (только чтение) --- //! \~english Returns the first index of element `e` in the row, starting from `start`.
//! \~russian Возвращает первый индекс элемента `e` в строке, начиная с позиции `start`.
//! \details
//! \~english See \a PIVector::indexOf() for details on negative start handling.
//! \~russian Подробнее об обработке отрицательного `start` см. \a PIVector::indexOf().
//! \~\sa PIVector::indexOf()
inline ssize_t indexOf(const T & e, ssize_t start = 0) const { inline ssize_t indexOf(const T & e, ssize_t start = 0) const {
if (start < 0) start = 0; if (start < 0) start = 0;
for (size_t i = (size_t)start; i < sz_; ++i) { for (size_t i = (size_t)start; i < sz_; ++i) {
@@ -438,6 +421,10 @@ public:
} }
return -1; return -1;
} }
//! \~english Returns the last index of element `e` in the row, searching backwards from `start`.
//! \~russian Возвращает последний индекс элемента `e` в строке, выполняя поиск в обратном направлении от `start`.
//! \~\sa PIVector::lastIndexOf()
inline ssize_t lastIndexOf(const T & e, ssize_t start = -1) const { inline ssize_t lastIndexOf(const T & e, ssize_t start = -1) const {
ssize_t from = (start < 0 || (size_t)start >= sz_) ? (ssize_t)sz_ - 1 : start; ssize_t from = (start < 0 || (size_t)start >= sz_) ? (ssize_t)sz_ - 1 : start;
for (ssize_t i = from; i >= 0; --i) { for (ssize_t i = from; i >= 0; --i) {
@@ -445,6 +432,10 @@ public:
} }
return -1; return -1;
} }
//! \~english Returns the first index where the predicate `test` returns true, starting from `start`.
//! \~russian Возвращает первый индекс, для которого предикат `test` возвращает true, начиная с `start`.
//! \~\sa PIVector::indexWhere()
inline ssize_t indexWhere(std::function<bool(const T & e)> test, ssize_t start = 0) const { inline ssize_t indexWhere(std::function<bool(const T & e)> test, ssize_t start = 0) const {
if (start < 0) start = 0; if (start < 0) start = 0;
for (size_t i = (size_t)start; i < sz_; ++i) { for (size_t i = (size_t)start; i < sz_; ++i) {
@@ -452,6 +443,11 @@ public:
} }
return -1; return -1;
} }
//! \~english Returns the last index where the predicate `test` returns true, searching backwards from `start`.
//! \~russian Возвращает последний индекс, для которого предикат `test` возвращает true,
//! выполняя поиск в обратном направлении от `start`.
//! \~\sa PIVector::lastIndexWhere()
inline ssize_t lastIndexWhere(std::function<bool(const T & e)> test, ssize_t start = -1) const { inline ssize_t lastIndexWhere(std::function<bool(const T & e)> test, ssize_t start = -1) const {
ssize_t from = (start < 0 || (size_t)start >= sz_) ? (ssize_t)sz_ - 1 : start; ssize_t from = (start < 0 || (size_t)start >= sz_) ? (ssize_t)sz_ - 1 : start;
for (ssize_t i = from; i >= 0; --i) { for (ssize_t i = from; i >= 0; --i) {
@@ -459,22 +455,277 @@ public:
} }
return -1; return -1;
} }
//! \~english Applies a function to each element of the column (read-only).
//! \~russian Применяет функцию к каждому элементу столбца (только чтение).
//! \details
//! \~english The function can't modify the elements.
//! \~russian Функция не может изменять элементы.
//! \~\sa forEach (modifiable)
inline void forEach(std::function<void(const T &)> func) const {
for (size_t i = 0; i < sz_; ++i) {
func((*p_)[i * step_ + col_]);
}
}
//! \~english Checks if the column contains the element `e`.
//! \~russian Проверяет, содержит ли столбец элемент `e`.
//! \~\sa PIVector::contains()
inline bool contains(const T & e, ssize_t start = 0) const { return indexOf(e, start) != -1; }
//! \~english Counts occurrences of `e` in the column.
//! \~russian Подсчитывает количество вхождений `e` в столбце.
//! \~\sa PIVector::entries()
inline int entries(const T & e, ssize_t start = 0) const {
if (start < 0) start = 0;
int count = 0;
for (size_t i = (size_t)start; i < sz_; ++i) {
if ((*p_)[i * step_ + col_] == e) ++count;
}
return count;
}
//! \~english Counts elements in the column that pass the `test`.
//! \~russian Подсчитывает элементы в столбце, проходящие `test`.
//! \~\sa PIVector::entries(std::function)
inline int entries(std::function<bool(const T & e)> test, ssize_t start = 0) const {
if (start < 0) start = 0;
int count = 0;
for (size_t i = (size_t)start; i < sz_; ++i) {
if (test((*p_)[i * step_ + col_])) ++count;
}
return count;
}
//! \~english Tests if any element in the column passes the `test`.
//! \~russian Проверяет, проходит ли какой-либо элемент в столбце `test`.
//! \~\sa PIVector::any()
inline bool any(std::function<bool(const T & e)> test) const {
for (size_t i = 0; i < sz_; ++i) {
if (test((*p_)[i * step_ + col_])) return true;
}
return false;
}
//! \~english Tests if all elements in the column pass the `test`.
//! \~russian Проверяет, проходят ли все элементы в столбце `test`.
//! \~\sa PIVector::every()
inline bool every(std::function<bool(const T & e)> test) const {
for (size_t i = 0; i < sz_; ++i) {
if (!test((*p_)[i * step_ + col_])) return false;
}
return true;
}
}; };
//! \class Row
//! \brief
//! \~english Proxy class representing a single row in a \a PIVector2D for modification.
//! \~russian Прокси-класс, представляющий одну строку в \a PIVector2D для модификации.
//! \details
//! \~english Objects of this class are returned by non-const \a operator[] or \a row().
//! They provide array-like access to the elements of a specific row and allow operations such as assignment from another row or a \a
//! PIVector, searching, filling, and iteration.
//! \~russian Объекты этого класса возвращаются неконстантными операторами \a operator[] или методом \a row().
//! Они предоставляют доступ к элементам конкретной строки, подобный массиву, и позволяют выполнять такие операции, как присваивание из
//! другой строки или \a PIVector, поиск, заполнение и итерацию. \sa Col, RowConst
class Row: public RowConst {
friend class PIVector2D<T>;
private:
inline Row(PIVector2D<T> * p, size_t row): RowConst(p, row), p_(&(p->mat)) {}
PIVector<T> * p_;
public:
using RowConst::operator[];
using RowConst::data;
using RowConst::size;
//! \~english Accesses the element at the given column index within the row.
//! \~russian Доступ к элементу по заданному индексу столбца в строке.
//! \details
//! \~english No bounds checking is performed; use with caution.
//! \~russian Проверка границ не выполняется; используйте с осторожностью.
//! \~\sa PIVector::operator[]
inline T & operator[](size_t index) { return (*p_)[this->st_ + index]; }
//! \~english Returns a pointer to the row data starting at an optional offset.
//! \~russian Возвращает указатель на данные строки, начиная с опционального смещения.
//! \details
//! \~english The pointer can be used for direct memory operations. It remains valid as long as the underlying 2D array is not
//! reallocated.
//! \~russian Указатель можно использовать для прямых операций с памятью. Он остаётся действительным, пока не произойдёт
//! перераспределение памяти внутреннего двумерного массива. \sa PIVector::data()
inline T * data(size_t index = 0) { return p_->data(this->st_ + index); }
//! \~english Assigns the contents of another Row to this row.
//! \~russian Присваивает этой строке содержимое другой строки.
//! \details
//! \~english Only the minimum of the two row sizes is copied; if this row is shorter, excess elements in `other` are ignored.
//! \~russian Копируется только минимум из размеров двух строк; если эта строка короче, лишние элементы из `other` игнорируются.
//! \~\sa PIVector::operator=
inline Row & operator=(const Row & other) {
if (p_ == other.p_ && this->st_ == other.st_) return *this;
const size_t sz = piMin<size_t>(this->sz_, other.sz_);
p_->_copyRaw(p_->data(this->st_), other.data(), sz);
return *this;
}
//! \~english Assigns the contents of a \a PIVector to this row.
//! \~russian Присваивает этой строке содержимое \a PIVector.
//! \details
//! \~english Only the minimum of the row size and vector size is copied.
//! \~russian Копируется только минимум из размера строки и размера вектора.
//! \~\sa PIVector::operator=
inline Row & operator=(const PIVector<T> & other) {
const size_t sz = piMin<size_t>(this->sz_, other.size());
p_->_copyRaw(p_->data(this->st_), other.data(), sz);
return *this;
}
//! \~english Applies a function to each element of the row (modifiable).
//! \~russian Применяет функцию к каждому элементу строки (с возможностью изменения).
//! \param func Function that takes a reference to T.
//! \details
//! \~english The function can modify the elements.
//! \~russian Функция может изменять элементы.
//! \~\sa PIVector::forEach()
inline void forEach(std::function<void(T &)> func) {
for (size_t i = 0; i < this->sz_; ++i) {
func((*p_)[this->st_ + i]);
}
}
//! \~english Fills the row with copies of `value`.
//! \~russian Заполняет строку копиями `value`.
//! \~\sa PIVector::fill()
inline void fill(const T & value) {
for (size_t i = 0; i < this->sz_; ++i) {
(*p_)[this->st_ + i] = value;
}
}
};
//! \class Col
//! \brief
//! \~english Proxy class representing a single column in a \a PIVector2D for modification.
//! \~russian Прокси-класс, представляющий один столбец в \a PIVector2D для модификации.
//! \details
//! \~english Objects of this class are returned by non-const \a col(). They provide column-wise access and operations similar to \a
//! Row.
//! \~russian Объекты этого класса возвращаются неконстантным методом \a col(). Они предоставляют доступ к столбцам и операции,
//! аналогичные \a Row. \sa Row, ColConst
class Col: public ColConst {
friend class PIVector2D<T>;
private:
inline Col(PIVector2D<T> * p, size_t col): ColConst(p, col), p_(&(p->mat)) {}
PIVector<T> * p_;
public:
using ColConst::operator[];
using ColConst::data;
using ColConst::size;
//! \~english Accesses the element at the given row index within the column.
//! \~russian Доступ к элементу по заданному индексу строки в столбце.
//! \return Reference to the element.
inline T & operator[](size_t index) { return (*p_)[index * this->step_ + this->col_]; }
//! \~english Returns a pointer to the column data starting at an optional row offset.
//! \~russian Возвращает указатель на данные столбца, начиная с опционального смещения по строкам.
//! \details
//! \~english Note that column elements are not stored contiguously in memory, so this pointer cannot be used to iterate over the
//! whole column.
//! \~russian Обратите внимание, что элементы столбца не хранятся в памяти непрерывно, поэтому этот указатель нельзя использовать
//! для итерации по всему столбцу.
inline T * data(size_t index = 0) { return p_->data(index * this->step_ + this->col_); }
//! \~english Assigns the contents of another Col to this column.
//! \~russian Присваивает этому столбцу содержимое другого столбца.
inline Col & operator=(const Col & other) {
if (p_ == other.p_ && this->col_ == other.col_) return *this;
const size_t sz = piMin<size_t>(this->sz_, other.sz_);
for (size_t i = 0; i < sz; ++i)
(*p_)[i * this->step_ + this->col_] = other[i];
return *this;
}
//! \~english Assigns the contents of a \a PIVector to this column.
//! \~russian Присваивает этому столбцу содержимое \a PIVector.
inline Col & operator=(const PIVector<T> & other) {
const size_t sz = piMin<size_t>(this->sz_, other.size());
for (size_t i = 0; i < sz; ++i)
(*p_)[i * this->step_ + this->col_] = other[i];
return *this;
}
//! \~english Applies a function to each element of the column (modifiable).
//! \~russian Применяет функцию к каждому элементу столбца (с возможностью изменения).
//! \details
//! \~english The function can modify the elements.
//! \~russian Функция может изменять элементы.
//! \~\sa PIVector::forEach()
inline void forEach(std::function<void(T &)> func) {
for (size_t i = 0; i < this->sz_; ++i) {
func((*p_)[i * this->step_ + this->col_]);
}
}
//! \~english Fills the column with copies of `value`.
//! \~russian Заполняет столбец копиями `value`.
//! \~\sa PIVector::fill()
inline void fill(const T & value) {
for (size_t i = 0; i < this->sz_; ++i) {
(*p_)[i * this->step_ + this->col_] = value;
}
}
};
//! \~english Returns a reference to the element at the given row and column. //! \~english Returns a reference to the element at the given row and column.
//! \~russian Возвращает ссылку на элемент по заданной строке и столбцу. //! \~russian Возвращает ссылку на элемент по заданной строке и столбцу.
//! \details
//! \~english No bounds checking is performed.
//! \~russian Проверка границ не выполняется.
//! \~\sa at() (const version), PIVector::operator[]
inline T & element(size_t row, size_t col) { return mat[row * cols_ + col]; } inline T & element(size_t row, size_t col) { return mat[row * cols_ + col]; }
//! \~english Returns a const reference to the element at the given row and column. //! \~english Returns a const reference to the element at the given row and column.
//! \~russian Возвращает константную ссылку на элемент по заданной строке и столбцу. //! \~russian Возвращает константную ссылку на элемент по заданной строке и столбцу.
inline const T & element(size_t row, size_t col) const { return mat[row * cols_ + col]; } inline const T & element(size_t row, size_t col) const { return mat[row * cols_ + col]; }
//! \~english Returns a const reference to the element at the given row and column (bounds-checked only in debug). //! \~english Returns a const reference to the element at the given row and column
//! \~russian Возвращает константную ссылку на элемент по заданной строке и столбцу (проверка границ только в отладочном режиме). //! \~russian Возвращает константную ссылку на элемент по заданной строке и столбцу
//! \details
//! \~english No bounds checking is performed.
//! \~russian Проверка границ не выполняется.
inline const T & at(size_t row, size_t col) const { return mat[row * cols_ + col]; } inline const T & at(size_t row, size_t col) const { return mat[row * cols_ + col]; }
//! \~english Returns a reference to the element at the given Index.
//! \~russian Возвращает ссылку на элемент по заданному Index.
inline T & operator[](const Index & idx) { return element(idx.row, idx.col); }
//! \~english Returns a const reference to the element at the given Index.
//! \~russian Возвращает константную ссылку на элемент по заданному Index.
inline const T & operator[](const Index & idx) const { return element(idx.row, idx.col); }
//! \~english Returns a reference to the element at the given Index.
//! \~russian Возвращает ссылку на элемент по заданному Index.
inline T & element(const Index & idx) { return element(idx.row, idx.col); }
//! \~english Returns a const reference to the element at the given Index.
//! \~russian Возвращает константную ссылку на элемент по заданному Index.
inline const T & element(const Index & idx) const { return element(idx.row, idx.col); }
//! \~english Returns a const reference to the element at the given Index (bounds-checked only in debug).
//! \~russian Возвращает константную ссылку на элемент по заданному Index (проверка границ только в отладочном режиме).
inline const T & at(const Index & idx) const { return at(idx.row, idx.col); }
//! \~english Returns a proxy object for the row at the given index for modification. //! \~english Returns a proxy object for the row at the given index for modification.
//! \~russian Возвращает прокси-объект для строки по заданному индексу для модификации. //! \~russian Возвращает прокси-объект для строки по заданному индексу для модификации.
//! \~\sa row(), Col
inline Row operator[](size_t index) { return Row(this, index); } inline Row operator[](size_t index) { return Row(this, index); }
//! \~english Returns a proxy object for the row at the given index for read-only access. //! \~english Returns a proxy object for the row at the given index for read-only access.
@@ -483,6 +734,7 @@ public:
//! \~english Returns a pointer to the underlying flat data starting at an optional offset. //! \~english Returns a pointer to the underlying flat data starting at an optional offset.
//! \~russian Возвращает указатель на внутренние плоские данные, начиная с опционального смещения. //! \~russian Возвращает указатель на внутренние плоские данные, начиная с опционального смещения.
//! \~\sa PIVector::data()
inline T * data(size_t index = 0) { return mat.data(index); } inline T * data(size_t index = 0) { return mat.data(index); }
//! \~english Returns a const pointer to the underlying flat data starting at an optional offset. //! \~english Returns a const pointer to the underlying flat data starting at an optional offset.
@@ -492,6 +744,7 @@ public:
//! \~english Returns a proxy object for the row at the given index for modification. //! \~english Returns a proxy object for the row at the given index for modification.
//! \~russian Возвращает прокси-объект для строки по заданному индексу для модификации. //! \~russian Возвращает прокси-объект для строки по заданному индексу для модификации.
//! \~\sa operator[]
inline Row row(size_t index) { return Row(this, index); } inline Row row(size_t index) { return Row(this, index); }
//! \~english Returns a proxy object for the row at the given index for read-only access. //! \~english Returns a proxy object for the row at the given index for read-only access.
@@ -500,21 +753,13 @@ public:
//! \~english Returns a proxy object for the column at the given index for modification. //! \~english Returns a proxy object for the column at the given index for modification.
//! \~russian Возвращает прокси-объект для столбца по заданному индексу для модификации. //! \~russian Возвращает прокси-объект для столбца по заданному индексу для модификации.
//! \~\sa col() const
inline Col col(size_t index) { return Col(this, index); } inline Col col(size_t index) { return Col(this, index); }
//! \~english Returns a proxy object for the column at the given index for read-only access. //! \~english Returns a proxy object for the column at the given index for read-only access.
//! \~russian Возвращает прокси-объект для столбца по заданному индексу только для чтения. //! \~russian Возвращает прокси-объект для столбца по заданному индексу только для чтения.
inline ColConst col(size_t index) const { return ColConst(this, index); } inline ColConst col(size_t index) const { return ColConst(this, index); }
//! \~english Replaces a row with the contents of another Row object.
//! \~russian Заменяет строку содержимым другого объекта Row.
inline PIVector2D<T> & setRow(size_t row, const Row & other) {
const size_t sz = piMin<size_t>(cols_, other.sz_);
mat._copyRaw(mat.data(cols_ * row), other.data(), sz);
return *this;
}
//! \~english Replaces a row with the contents of a read-only RowConst object. //! \~english Replaces a row with the contents of a read-only RowConst object.
//! \~russian Заменяет строку содержимым объекта RowConst только для чтения. //! \~russian Заменяет строку содержимым объекта RowConst только для чтения.
inline PIVector2D<T> & setRow(size_t row, const RowConst & other) { inline PIVector2D<T> & setRow(size_t row, const RowConst & other) {
@@ -533,25 +778,18 @@ public:
//! \~english Appends a new row to the bottom of the array from another Row object. //! \~english Appends a new row to the bottom of the array from another Row object.
//! \~russian Добавляет новую строку в конец массива из другого объекта Row. //! \~russian Добавляет новую строку в конец массива из другого объекта Row.
inline PIVector2D<T> & addRow(const Row & other) { //! \details
if (cols_ == 0) cols_ = other.sz_; //! \~english If the array was empty, its column count is set to the size of the source row.
const size_t sz = piMin<size_t>(cols_, other.sz_); //! Otherwise, only `min(cols(), other.size())` elements are copied; the rest of the new row is default-initialized.
const size_t ps = mat.size(); //! \~russian Если массив был пуст, количество столбцов устанавливается равным размеру исходной строки.
mat.resize(mat.size() + cols_); //! В противном случае копируется только `min(cols(), other.size())` элементов; остальные элементы новой строки инициализируются по
mat._copyRaw(mat.data(ps), other.data(), sz); //! умолчанию.
rows_++; //! \~\sa PIVector::push_back()
return *this;
}
//! \~english Appends a new row to the bottom of the array from a read-only RowConst object.
//! \~russian Добавляет новую строку в конец массива из объекта RowConst только для чтения.
inline PIVector2D<T> & addRow(const RowConst & other) { inline PIVector2D<T> & addRow(const RowConst & other) {
if (cols_ == 0) cols_ = other.sz_; if (cols_ == 0) cols_ = other.sz_;
const size_t sz = piMin<size_t>(cols_, other.sz_); mat.append(other.toVector());
const size_t ps = mat.size();
mat.resize(mat.size() + cols_);
mat._copyRaw(mat.data(ps), other.data(), sz);
rows_++; rows_++;
mat.resize(rows_ * cols_);
return *this; return *this;
} }
@@ -559,37 +797,191 @@ public:
//! \~russian Добавляет новую строку в конец массива из \a PIVector. //! \~russian Добавляет новую строку в конец массива из \a PIVector.
inline PIVector2D<T> & addRow(const PIVector<T> & other) { inline PIVector2D<T> & addRow(const PIVector<T> & other) {
if (cols_ == 0) cols_ = other.size(); if (cols_ == 0) cols_ = other.size();
const size_t sz = piMin<size_t>(cols_, other.size()); mat.append(other);
const size_t ps = mat.size();
mat.resize(mat.size() + cols_);
mat._copyRaw(mat.data(ps), other.data(), sz);
rows_++; rows_++;
mat.resize(rows_ * cols_);
return *this;
}
//! \~english Appends \a count new empty rows to the bottom of the array, filled with value \a f.
//! \~russian Добавляет \a count новых пустых строк в конец массива, заполненных значением \a f.
//! \details
//! \~english If the array was empty (no columns defined), the column count is set to 1.
//! The new rows are filled with the default value \a f.
//! \~russian Если массив был пуст (количество столбцов не определено), количество столбцов устанавливается равным 1.
//! Новые строки заполняются значением по умолчанию \a f.
//! \~\sa addRow(), appendColumns()
inline PIVector2D<T> & appendRows(size_t count, const T & f = T()) {
if (count == 0) return *this;
if (cols_ == 0) ++cols_;
mat.resize(mat.size() + count * cols_, f);
rows_ += count;
return *this;
}
//! \~english Appends \a count new empty columns to the end of each row of the array.
//! \~russian Добавляет \a count новых пустых столбцов в конец каждой строки массива.
//! \details
//! \~english If the array was empty (rows not defined), the array becomes a single row with \a count columns.
//! If the array already has rows, new elements are inserted at the end of each existing row.
//! \~russian Если массив был пуст (строки не определены), массив становится одной строкой с \a count столбцов.
//! Если массив уже содержит строки, новые элементы добавляются в конец каждой существующей строки.
//! \~\sa appendRows(), addColumn()
inline PIVector2D<T> & appendColumns(size_t count, const T & f = T()) {
if (count == 0) return *this;
if (rows_ == 0) {
mat.resize(count, f);
rows_ = 1;
cols_ = count;
return *this;
}
const size_t newCols = cols_ + count;
mat.reserve(rows_ * newCols);
for (size_t r = rows_; r > 0; --r) {
mat.insert(r * cols_, f, count);
}
cols_ = newCols;
return *this;
}
//! \~english Deletes `count` rows starting from the specified row index.
//! \~russian Удаляет `count` строк, начиная с указанного индекса строки.
//! \details
//! \~english Removes the specified rows from the array and updates the row count. If all elements are deleted (array becomes empty),
//! both rows and columns are set to 0.
//! \~russian Удаляет указанные строки из массива и обновляет количество строк. Если все элементы удалены (массив становится пустым),
//! количество строк и столбцов устанавливается в 0.
//! \~\sa deleteColumns()
inline PIVector2D<T> & deleteRows(size_t row_start, size_t count) {
if (row_start >= rows_ || count == 0) return *this;
mat.remove(row_start * cols_, cols_ * count);
if (isEmpty()) {
cols_ = 0;
rows_ = 0;
} else {
rows_ -= count;
}
return *this;
}
//! \~english Removes the specified columns from the array and updates the column count.
//! \~russian Удаляет указанные столбцы из массива и обновляет количество столбцов.
//! \details
//! \~english Removes \a count columns starting from \a col_start. If \a col_start is out of range or \a count is 0,
//! the function does nothing. If \a count extends beyond the last column, only available columns are deleted.
//! \~russian Удаляет \a count столбцов начиная с \a col_start. Если \a col_start выходит за границы или \a count равен 0,
//! функция ничего не делает. Если \a count выходит за последний столбец, удаляются только доступные столбцы.
//! \~\sa removeColumn(), deleteRows()
inline PIVector2D<T> & deleteColumns(size_t col_start, size_t count) {
if (col_start >= cols_ || rows_ == 0) return *this;
count = piMin(count, cols_ - col_start);
if (count == 0) return *this;
for (size_t r = 0; r < rows_; ++r) {
mat.remove(r * (cols_ - count) + col_start, count);
}
cols_ -= count;
mat.resize(rows_ * cols_);
return *this;
}
//! \~english Appends a new column to the right of the array from a \a ColConst.
//! \~russian Добавляет новую строку в конец массива из \a ColConst.
inline PIVector2D<T> & addColumn(const ColConst & other) {
if (other.size() == 0) return *this;
if (isEmpty()) {
mat.reserve(other.size());
for (size_t r = 0; r < other.size(); ++r) {
mat.append(other[r]);
}
rows_ = mat.size();
cols_ = 1;
return *this;
}
const size_t newCols = cols_ + 1;
mat.reserve(rows_ * newCols);
for (size_t r = rows_; r > 0; --r) {
if (r - 1 < other.size()) {
mat.insert(r * cols_, other[r - 1]);
} else {
mat.insert(r * cols_);
}
}
cols_ = newCols;
return *this;
}
//! \~english Appends a new column to the right of the array from a \a PIVector.
//! \~russian Добавляет новую строку в конец массива из \a PIVector.
inline PIVector2D<T> & addColumn(const PIVector<T> & other) {
if (other.size() == 0) return *this;
if (isEmpty()) {
mat.append(other);
rows_ = mat.size();
cols_ = 1;
return *this;
}
const size_t newCols = cols_ + 1;
mat.reserve(rows_ * newCols);
for (size_t r = rows_; r > 0; --r) {
if (r - 1 < other.size()) {
mat.insert(r * cols_, other[r - 1]);
} else {
mat.insert(r * cols_);
}
}
cols_ = newCols;
return *this; return *this;
} }
//! \~english Resizes the 2D array to new dimensions. //! \~english Resizes the 2D array to new dimensions.
//! \~russian Изменяет размер двумерного массива. //! \~russian Изменяет размер двумерного массива.
//! \details //! \details
//! \~english If the new dimensions are larger, new elements are filled with `f`. //! \~english If the new dimensions are larger, new elements are appended and filled with copies of `f`.
//! If they are smaller, the array is truncated. //! If they are smaller, the array is truncated (excess elements are destroyed). The underlying memory may be reallocated.
//! \~russian Если новые размеры больше, новые элементы заполняются `f`. //! \~russian Если новые размеры больше текущих, новые элементы добавляются в конец и заполняются копиями `f`.
//! Если они меньше, массив обрезается. //! Если новые размеры меньше, массив усекается (лишние элементы уничтожаются). Внутренняя память может быть перераспределена.
//! \code
//! PIVector2D<int> mat(2, 3, 0); // 2x3 matrix filled with 0
//! mat.resize(3, 4, 1); // becomes 3x4, new elements filled with 1
//! \endcode
//! \~\sa PIVector::resize()
inline PIVector2D<T> & resize(size_t rows, size_t cols, const T & f = T()) { inline PIVector2D<T> & resize(size_t rows, size_t cols, const T & f = T()) {
if (rows == rows_ && cols == cols_) return *this; if (rows == rows_ && cols == cols_) return *this;
PIVector2D<T> tmp(rows, cols, f); if (rows_ == 0 || cols_ == 0) {
size_t copyRows = piMin(rows_, rows); mat.resize(rows * cols, f);
size_t copyCols = piMin(cols_, cols); rows_ = rows;
for (size_t r = 0; r < copyRows; ++r) { cols_ = cols;
for (size_t c = 0; c < copyCols; ++c) { return *this;
tmp.element(r, c) = element(r, c); }
} if (rows != rows_ && cols == cols_) {
mat.resize(rows * cols_, f);
rows_ = rows;
return *this;
}
if (cols > cols_) {
appendColumns(cols - cols_, f);
}
if (rows > rows_) {
appendRows(rows - rows_, f);
}
if (cols < cols_) {
deleteColumns(cols, cols_ - cols);
}
if (rows < rows_) {
deleteRows(rows, rows_ - rows);
} }
swap(tmp);
return *this; return *this;
} }
//! \~english Equality operator. //! \~english Equality operator.
//! \~russian Оператор равенства. //! \~russian Оператор равенства.
//! \~\sa PIVector::operator==
inline bool operator==(const PIVector2D<T> & t) const { inline bool operator==(const PIVector2D<T> & t) const {
if (cols_ != t.cols_ || rows_ != t.rows_) return false; if (cols_ != t.cols_ || rows_ != t.rows_) return false;
return mat == t.mat; return mat == t.mat;
@@ -601,6 +993,10 @@ public:
//! \~english Converts the 2D array to a vector of vectors (PIVector<PIVector<T>>). //! \~english Converts the 2D array to a vector of vectors (PIVector<PIVector<T>>).
//! \~russian Преобразует двумерный массив в вектор векторов (PIVector<PIVector<T>>). //! \~russian Преобразует двумерный массив в вектор векторов (PIVector<PIVector<T>>).
//! \details
//! \~english Each row vector is a copy of the corresponding row.
//! \~russian Каждый вектор-строка является копией соответствующей строки.
//! \~\sa fromVectors(), PIVector::PIVector(const T*, size_t)
inline PIVector<PIVector<T>> toVectors() const { inline PIVector<PIVector<T>> toVectors() const {
PIVector<PIVector<T>> ret; PIVector<PIVector<T>> ret;
ret.reserve(rows_); ret.reserve(rows_);
@@ -623,6 +1019,10 @@ public:
//! \~english Swaps this 2D array with another. //! \~english Swaps this 2D array with another.
//! \~russian Меняет местами этот двумерный массив с другим. //! \~russian Меняет местами этот двумерный массив с другим.
//! \details
//! \~english Swaps the flat vectors and the dimension members. Very fast, no memory allocation.
//! \~russian Обменивает внутренние плоские векторы и члены, хранящие размеры. Очень быстро, без выделения памяти.
//! \~\sa PIVector::swap()
inline void swap(PIVector2D<T> & other) { inline void swap(PIVector2D<T> & other) {
mat.swap(other.mat); mat.swap(other.mat);
piSwap<size_t>(rows_, other.rows_); piSwap<size_t>(rows_, other.rows_);
@@ -640,6 +1040,10 @@ public:
//! \~english Clears the array, removing all elements and setting dimensions to 0. //! \~english Clears the array, removing all elements and setting dimensions to 0.
//! \~russian Очищает массив, удаляя все элементы и устанавливая размеры в 0. //! \~russian Очищает массив, удаляя все элементы и устанавливая размеры в 0.
//! \details
//! \~english The capacity of the underlying flat vector may remain unchanged.
//! \~russian Ёмкость внутреннего плоского вектора может остаться неизменной.
//! \~\sa PIVector::clear()
inline void clear() { inline void clear() {
rows_ = cols_ = 0; rows_ = cols_ = 0;
mat.clear(); mat.clear();
@@ -648,64 +1052,70 @@ public:
//! \~english Checks if the underlying flat vector contains the element `e`. //! \~english Checks if the underlying flat vector contains the element `e`.
//! \~russian Проверяет, содержит ли внутренний плоский вектор элемент `e`. //! \~russian Проверяет, содержит ли внутренний плоский вектор элемент `e`.
inline bool contains(const T & e, ssize_t start = 0) const { return mat.contains(e, start); } //! \~\sa PIVector::contains()
inline bool contains(const T & e) const { return mat.contains(e); }
//! \~english Checks if the underlying flat vector contains all elements of `v`.
//! \~russian Проверяет, содержит ли внутренний плоский вектор все элементы `v`.
inline bool contains(const PIVector<T> & v, ssize_t start = 0) const { return mat.contains(v, start); }
//! \~english Counts occurrences of `e` in the underlying flat vector. //! \~english Counts occurrences of `e` in the underlying flat vector.
//! \~russian Подсчитывает количество вхождений `e` во внутреннем плоском векторе. //! \~russian Подсчитывает количество вхождений `e` во внутреннем плоском векторе.
inline int entries(const T & e, ssize_t start = 0) const { return mat.entries(e, start); } //! \~\sa PIVector::entries()
inline int entries(const T & e) const { return mat.entries(e); }
//! \~english Counts elements in the flat vector that pass the `test`. //! \~english Counts elements in the flat vector that pass the `test`.
//! \~russian Подсчитывает элементы в плоском векторе, проходящие `test`. //! \~russian Подсчитывает элементы в плоском векторе, проходящие `test`.
inline int entries(std::function<bool(const T & e)> test, ssize_t start = 0) const { return mat.entries(test, start); } //! \~\sa PIVector::entries(std::function)
inline int entries(std::function<bool(const T & e)> test) const { return mat.entries(test); }
//! \~english Returns the first index (row, col) of `e` in the 2D array. //! \~english Returns the first index (row, col) of `e` in the 2D array.
//! \~russian Возвращает первый индекс (строка, столбец) элемента `e` в двумерном массиве. //! \~russian Возвращает первый индекс (строка, столбец) элемента `e` в двумерном массиве.
inline PIPair<ssize_t, ssize_t> indexOf(const T & e, ssize_t start = 0) const { //! \~\sa PIVector::indexOf()
ssize_t flat = mat.indexOf(e, start); inline Index indexOf(const T & e) const {
if (flat < 0 || cols_ == 0) return PIPair<ssize_t, ssize_t>(-1, -1); ssize_t flat = mat.indexOf(e);
return PIPair<ssize_t, ssize_t>(flat / cols_, flat % cols_); if (flat < 0 || cols_ == 0) return Index{-1, -1};
return Index{flat / static_cast<ssize_t>(cols_), flat % static_cast<ssize_t>(cols_)};
} }
//! \~english Returns the first index (row, col) in the 2D array that passes the `test`. //! \~english Returns the first index (row, col) in the 2D array that passes the `test`.
//! \~russian Возвращает первый индекс (строка, столбец) в двумерном массиве, проходящий `test`. //! \~russian Возвращает первый индекс (строка, столбец) в двумерном массиве, проходящий `test`.
inline PIPair<ssize_t, ssize_t> indexWhere(std::function<bool(const T & e)> test, ssize_t start = 0) const { //! \~\sa PIVector::indexWhere()
inline Index indexWhere(std::function<bool(const T & e)> test, ssize_t start = 0) const {
ssize_t flat = mat.indexWhere(test, start); ssize_t flat = mat.indexWhere(test, start);
if (flat < 0 || cols_ == 0) return PIPair<ssize_t, ssize_t>(-1, -1); if (flat < 0 || cols_ == 0) return Index{-1, -1};
return PIPair<ssize_t, ssize_t>(flat / cols_, flat % cols_); return Index{flat / static_cast<ssize_t>(cols_), flat % static_cast<ssize_t>(cols_)};
} }
//! \~english Returns the last index (row, col) of `e` in the 2D array. //! \~english Returns the last index (row, col) of `e` in the 2D array.
//! \~russian Возвращает последний индекс (строка, столбец) элемента `e` в двумерном массиве. //! \~russian Возвращает последний индекс (строка, столбец) элемента `e` в двумерном массиве.
inline PIPair<ssize_t, ssize_t> lastIndexOf(const T & e, ssize_t start = -1) const { //! \~\sa PIVector::lastIndexOf()
inline Index lastIndexOf(const T & e, ssize_t start = -1) const {
ssize_t flat = mat.lastIndexOf(e, start); ssize_t flat = mat.lastIndexOf(e, start);
if (flat < 0 || cols_ == 0) return PIPair<ssize_t, ssize_t>(-1, -1); if (flat < 0 || cols_ == 0) return Index{-1, -1};
return PIPair<ssize_t, ssize_t>(flat / cols_, flat % cols_); return Index{flat / static_cast<ssize_t>(cols_), flat % static_cast<ssize_t>(cols_)};
} }
//! \~english Returns the last index (row, col) in the 2D array that passes the `test`. //! \~english Returns the last index (row, col) in the 2D array that passes the `test`.
//! \~russian Возвращает последний индекс (строка, столбец) в двумерном массиве, проходящий `test`. //! \~russian Возвращает последний индекс (строка, столбец) в двумерном массиве, проходящий `test`.
inline PIPair<ssize_t, ssize_t> lastIndexWhere(std::function<bool(const T & e)> test, ssize_t start = -1) const { //! \~\sa PIVector::lastIndexWhere()
inline Index lastIndexWhere(std::function<bool(const T & e)> test, ssize_t start = -1) const {
ssize_t flat = mat.lastIndexWhere(test, start); ssize_t flat = mat.lastIndexWhere(test, start);
if (flat < 0 || cols_ == 0) return PIPair<ssize_t, ssize_t>(-1, -1); if (flat < 0 || cols_ == 0) return Index{-1, -1};
return PIPair<ssize_t, ssize_t>(flat / cols_, flat % cols_); return Index{flat / static_cast<ssize_t>(cols_), flat % static_cast<ssize_t>(cols_)};
} }
//! \~english Tests if any element in the flat vector passes the `test`. //! \~english Tests if any element in the flat vector passes the `test`.
//! \~russian Проверяет, проходит ли какой-либо элемент в плоском векторе `test`. //! \~russian Проверяет, проходит ли какой-либо элемент в плоском векторе `test`.
//! \~\sa PIVector::any()
inline bool any(std::function<bool(const T & e)> test) const { return mat.any(test); } inline bool any(std::function<bool(const T & e)> test) const { return mat.any(test); }
//! \~english Tests if all elements in the flat vector pass the `test`. //! \~english Tests if all elements in the flat vector pass the `test`.
//! \~russian Проверяет, проходят ли все элементы в плоском векторе `test`. //! \~russian Проверяет, проходят ли все элементы в плоском векторе `test`.
//! \~\sa PIVector::every()
inline bool every(std::function<bool(const T & e)> test) const { return mat.every(test); } inline bool every(std::function<bool(const T & e)> test) const { return mat.every(test); }
//! \~english Fills the entire 2D array with copies of `e`. //! \~english Fills the entire 2D array with copies of `e`.
//! \~russian Заполняет весь двумерный массив копиями `e`. //! \~russian Заполняет весь двумерный массив копиями `e`.
//! \~\sa PIVector::fill()
inline PIVector2D<T> & fill(const T & e = T()) { inline PIVector2D<T> & fill(const T & e = T()) {
mat.fill(e); mat.fill(e);
return *this; return *this;
@@ -713,6 +1123,7 @@ public:
//! \~english Fills the entire 2D array using a generator function `f` based on flat index. //! \~english Fills the entire 2D array using a generator function `f` based on flat index.
//! \~russian Заполняет весь двумерный массив, используя функцию-генератор `f` на основе плоского индекса. //! \~russian Заполняет весь двумерный массив, используя функцию-генератор `f` на основе плоского индекса.
//! \~\sa PIVector::fill(std::function)
inline PIVector2D<T> & fill(std::function<T(size_t i)> f) { inline PIVector2D<T> & fill(std::function<T(size_t i)> f) {
mat.fill(f); mat.fill(f);
return *this; return *this;
@@ -724,6 +1135,7 @@ public:
//! \~english Assigns new size and fills with value. //! \~english Assigns new size and fills with value.
//! \~russian Задаёт новый размер и заполняет значением. //! \~russian Задаёт новый размер и заполняет значением.
//! \~\sa PIVector::assign(size_t, const T&)
inline PIVector2D<T> & assign(size_t rows, size_t cols, const T & f = T()) { inline PIVector2D<T> & assign(size_t rows, size_t cols, const T & f = T()) {
mat.assign(rows * cols, f); mat.assign(rows * cols, f);
rows_ = rows; rows_ = rows;
@@ -732,9 +1144,15 @@ public:
} }
// TODO: исправить - при транспонировании количество строк становится количеством столбцов и наоборот
//! \~english Returns a transposed 2D array (rows become columns and vice versa). //! \~english Returns a transposed 2D array (rows become columns and vice versa).
//! \~russian Возвращает транспонированный двумерный массив (строки становятся столбцами и наоборот). //! \~russian Возвращает транспонированный двумерный массив (строки становятся столбцами и наоборот).
//! \details
//! \~english The element at (r, c) in the original becomes at (c, r) in the result.
//! \~russian Элемент (r, c) исходного массива становится элементом (c, r) в результате.
//! \code
//! PIVector2D<int> mat(2, 3, ...);
//! auto t = mat.transposed(); // now 3x2
//! \endcode
inline PIVector2D<T> transposed() const { inline PIVector2D<T> transposed() const {
if (isEmpty()) return PIVector2D<T>(); if (isEmpty()) return PIVector2D<T>();
PIVector2D<T> result(cols_, rows_); PIVector2D<T> result(cols_, rows_);
@@ -748,6 +1166,7 @@ public:
//! \~english Reverses the order of rows in place. //! \~english Reverses the order of rows in place.
//! \~russian Изменяет порядок строк на обратный на месте. //! \~russian Изменяет порядок строк на обратный на месте.
//! \~\sa reverseColumns(), PIVector::reverse()
inline PIVector2D<T> & reverseRows() { inline PIVector2D<T> & reverseRows() {
const size_t half = rows_ / 2; const size_t half = rows_ / 2;
for (size_t i = 0; i < half; ++i) { for (size_t i = 0; i < half; ++i) {
@@ -762,6 +1181,7 @@ public:
//! \~english Reverses the order of columns in each row in place. //! \~english Reverses the order of columns in each row in place.
//! \~russian Изменяет порядок столбцов в каждой строке на обратный на месте. //! \~russian Изменяет порядок столбцов в каждой строке на обратный на месте.
//! \~\sa reverseRows(), PIVector::reverse()
inline PIVector2D<T> & reverseColumns() { inline PIVector2D<T> & reverseColumns() {
for (size_t r = 0; r < rows_; ++r) { for (size_t r = 0; r < rows_; ++r) {
Row currentRow = row(r); Row currentRow = row(r);
@@ -775,10 +1195,14 @@ public:
//! \~english Returns a sub-2D array (a range of rows and columns). //! \~english Returns a sub-2D array (a range of rows and columns).
//! \~russian Возвращает подмассив (диапазон строк и столбцов). //! \~russian Возвращает подмассив (диапазон строк и столбцов).
//! \details
//! \~english If the range exceeds the array boundaries, it is clipped. If rowCount or colCount is 0, an empty array is returned.
//! \~russian Если диапазон выходит за границы массива, он обрезается. Если rowCount или colCount равны 0, возвращается пустой массив.
//! \~\sa PIVector::getRange()
inline PIVector2D<T> getRange(size_t rowStart, size_t rowCount, size_t colStart, size_t colCount) const { inline PIVector2D<T> getRange(size_t rowStart, size_t rowCount, size_t colStart, size_t colCount) const {
if (rowStart >= rows_ || colStart >= cols_ || rowCount == 0 || colCount == 0) return PIVector2D<T>(); if (rowStart >= rows_ || colStart >= cols_ || rowCount == 0 || colCount == 0) return PIVector2D<T>();
size_t actualRowCount = piMin(rowCount, rows_ - rowStart); const size_t actualRowCount = piMin<size_t>(rowCount, rows_ - rowStart);
size_t actualColCount = piMin(colCount, cols_ - colStart); const size_t actualColCount = piMin<size_t>(colCount, cols_ - colStart);
PIVector2D<T> result(actualRowCount, actualColCount); PIVector2D<T> result(actualRowCount, actualColCount);
for (size_t r = 0; r < actualRowCount; ++r) { for (size_t r = 0; r < actualRowCount; ++r) {
@@ -791,6 +1215,10 @@ public:
//! \~english Applies a function to each element and returns a new 2D array of a different type. //! \~english Applies a function to each element and returns a new 2D array of a different type.
//! \~russian Применяет функцию к каждому элементу и возвращает новый двумерный массив другого типа. //! \~russian Применяет функцию к каждому элементу и возвращает новый двумерный массив другого типа.
//! \details
//! \~english The original array is not modified.
//! \~russian Исходный массив не изменяется.
//! \~\sa PIVector::map()
template<typename ST> template<typename ST>
inline PIVector2D<ST> map(std::function<ST(const T & e)> f) const { inline PIVector2D<ST> map(std::function<ST(const T & e)> f) const {
return PIVector2D<ST>(rows_, cols_, mat.template map<ST>(f)); return PIVector2D<ST>(rows_, cols_, mat.template map<ST>(f));
@@ -798,6 +1226,7 @@ public:
//! \~english Applies a function (with row and col indices) to each element and returns a new 2D array. //! \~english Applies a function (with row and col indices) to each element and returns a new 2D array.
//! \~russian Применяет функцию (с индексами строки и столбца) к каждому элементу и возвращает новый двумерный массив. //! \~russian Применяет функцию (с индексами строки и столбца) к каждому элементу и возвращает новый двумерный массив.
//! \~\sa PIVector::mapIndexed()
template<typename ST> template<typename ST>
inline PIVector2D<ST> mapIndexed(std::function<ST(size_t row, size_t col, const T & e)> f) const { inline PIVector2D<ST> mapIndexed(std::function<ST(size_t row, size_t col, const T & e)> f) const {
PIVector<ST> mappedMat; PIVector<ST> mappedMat;
@@ -810,20 +1239,22 @@ public:
return PIVector2D<ST>(rows_, cols_, std::move(mappedMat)); return PIVector2D<ST>(rows_, cols_, std::move(mappedMat));
} }
// --- Итерация по строкам и столбцам ---
//! \~english Applies a function to each row (modifiable). //! \~english Applies a function to each row (modifiable).
//! \~russian Применяет функцию к каждой строке (с возможностью изменения). //! \~russian Применяет функцию к каждой строке (с возможностью изменения).
//! \~\sa forEachRow() const, PIVector::forEach()
inline PIVector2D<T> & forEachRow(std::function<void(Row)> f) { inline PIVector2D<T> & forEachRow(std::function<void(Row)> f) {
for (size_t r = 0; r < rows_; ++r) for (size_t r = 0; r < rows_; ++r)
f(row(r)); f(row(r));
return *this; return *this;
} }
//! \~english Applies a function to each row (read-only). //! \~english Applies a function to each row (read-only).
//! \~russian Применяет функцию к каждой строке (только чтение). //! \~russian Применяет функцию к каждой строке (только чтение).
inline void forEachRow(std::function<void(RowConst)> f) const { inline void forEachRow(std::function<void(RowConst)> f) const {
for (size_t r = 0; r < rows_; ++r) for (size_t r = 0; r < rows_; ++r)
f(row(r)); f(row(r));
} }
//! \~english Applies a function to each column (modifiable). //! \~english Applies a function to each column (modifiable).
//! \~russian Применяет функцию к каждому столбцу (с возможностью изменения). //! \~russian Применяет функцию к каждому столбцу (с возможностью изменения).
inline PIVector2D<T> & forEachColumn(std::function<void(Col)> f) { inline PIVector2D<T> & forEachColumn(std::function<void(Col)> f) {
@@ -831,8 +1262,10 @@ public:
f(col(c)); f(col(c));
return *this; return *this;
} }
//! \~english Applies a function to each column (read-only). //! \~english Applies a function to each column (read-only).
//! \~russian Применяет функцию к каждому столбцу (только чтение). //! \~russian Применяет функцию к каждому столбцу (только чтение).
//! \param f Function taking a \a ColConst.
inline void forEachColumn(std::function<void(ColConst)> f) const { inline void forEachColumn(std::function<void(ColConst)> f) const {
for (size_t c = 0; c < cols_; ++c) for (size_t c = 0; c < cols_; ++c)
f(col(c)); f(col(c));
@@ -840,6 +1273,7 @@ public:
//! \~english Accumulates a value across all elements. //! \~english Accumulates a value across all elements.
//! \~russian Аккумулирует значение по всем элементам. //! \~russian Аккумулирует значение по всем элементам.
//! \~\sa PIVector::reduce()
template<typename ST> template<typename ST>
inline ST reduce(std::function<ST(const T & e, const ST & acc)> f, const ST & initial = ST()) const { inline ST reduce(std::function<ST(const T & e, const ST & acc)> f, const ST & initial = ST()) const {
return mat.template reduce<ST>(f, initial); return mat.template reduce<ST>(f, initial);
@@ -847,6 +1281,7 @@ public:
//! \~english Accumulates a value across all elements with indices. //! \~english Accumulates a value across all elements with indices.
//! \~russian Аккумулирует значение по всем элементам с индексами. //! \~russian Аккумулирует значение по всем элементам с индексами.
//! \~\sa PIVector::reduceIndexed()
template<typename ST> template<typename ST>
inline ST reduceIndexed(std::function<ST(size_t row, size_t col, const T & e, const ST & acc)> f, const ST & initial = ST()) const { inline ST reduceIndexed(std::function<ST(size_t row, size_t col, const T & e, const ST & acc)> f, const ST & initial = ST()) const {
ST ret(initial); ST ret(initial);
@@ -860,52 +1295,45 @@ public:
//! \~english Removes a row from the 2D array. //! \~english Removes a row from the 2D array.
//! \~russian Удаляет строку из двумерного массива. //! \~russian Удаляет строку из двумерного массива.
inline PIVector2D<T> & removeRow(size_t row) { //! \details
if (row >= rows_) return *this; //! \~english If the last row is removed and the array becomes empty, \a cols() is set to 0.
size_t startIdx = row * cols_; //! \~russian Если удаляется последняя строка и массив становится пустым, \a cols() устанавливается в 0.
mat.remove(startIdx, cols_); //! \~\sa removeColumn(), PIVector::remove()
rows_--; inline PIVector2D<T> & removeRow(size_t row) { return deleteRows(row, 1); }
if (rows_ == 0) cols_ = 0;
return *this;
}
//! \~english Removes a column from the 2D array. //! \~english Removes a column from the 2D array.
//! \~russian Удаляет столбец из двумерного массива. //! \~russian Удаляет столбец из двумерного массива.
inline PIVector2D<T> & removeColumn(size_t col) { //! \details
if (col >= cols_ || rows_ == 0) return *this; //! \~english This operation is more expensive than removing a row because elements must be moved.
PIVector2D<T> result(rows_, cols_ - 1); //! \~russian Эта операция дороже, чем удаление строки, поскольку требуется перемещение элементов.
for (size_t r = 0; r < rows_; ++r) { //! \~\sa removeRow(), PIVector::remove()
for (size_t c = 0, nc = 0; c < cols_; ++c) { inline PIVector2D<T> & removeColumn(size_t col) { return deleteColumns(col, 1); }
if (c == col) continue;
result.element(r, nc++) = element(r, c);
}
}
swap(result);
return *this;
}
//! \~english Removes all rows that satisfy a condition. //! \~english Removes all rows that satisfy a condition.
//! \~russian Удаляет все строки, удовлетворяющие условию. //! \~russian Удаляет все строки, удовлетворяющие условию.
//! \details
//! \~english Rows are removed from the bottom to avoid index shifting issues.
//! \~russian Строки удаляются снизу вверх, чтобы избежать проблем со смещением индексов.
//! \~\sa removeColumnsWhere(), PIVector::removeWhere()
inline PIVector2D<T> & removeRowsWhere(std::function<bool(const RowConst &)> test) { inline PIVector2D<T> & removeRowsWhere(std::function<bool(const RowConst &)> test) {
ssize_t r = rows_ - 1; ssize_t r = rows_;
while (r >= 0) { while (--r >= 0) {
if (test(RowConst(this, r))) { if (test(RowConst(this, r))) {
removeRow(r); removeRow(r);
} }
--r;
} }
return *this; return *this;
} }
//! \~english Removes all columns that satisfy a condition. //! \~english Removes all columns that satisfy a condition.
//! \~russian Удаляет все столбцы, удовлетворяющие условию. //! \~russian Удаляет все столбцы, удовлетворяющие условию.
//! \~\sa removeRowsWhere()
inline PIVector2D<T> & removeColumnsWhere(std::function<bool(const ColConst &)> test) { inline PIVector2D<T> & removeColumnsWhere(std::function<bool(const ColConst &)> test) {
ssize_t c = cols_ - 1; ssize_t c = cols_;
while (c >= 0) { while (--c >= 0) {
if (test(ColConst(this, c))) { if (test(ColConst(this, c))) {
removeColumn(c); removeColumn(c);
} }
--c;
} }
return *this; return *this;
} }
@@ -913,6 +1341,7 @@ public:
//! \~english Returns a new 2D array containing only the rows that pass the test. //! \~english Returns a new 2D array containing only the rows that pass the test.
//! \~russian Возвращает новый двумерный массив, содержащий только строки, прошедшие проверку. //! \~russian Возвращает новый двумерный массив, содержащий только строки, прошедшие проверку.
//! \~\sa filterColumns(), PIVector::filter()
inline PIVector2D<T> filterRows(std::function<bool(const RowConst &)> test) const { inline PIVector2D<T> filterRows(std::function<bool(const RowConst &)> test) const {
PIVector2D<T> result; PIVector2D<T> result;
for (size_t r = 0; r < rows_; ++r) { for (size_t r = 0; r < rows_; ++r) {
@@ -926,6 +1355,7 @@ public:
//! \~english Returns a new 2D array containing only the columns that pass the test. //! \~english Returns a new 2D array containing only the columns that pass the test.
//! \~russian Возвращает новый двумерный массив, содержащий только столбцы, прошедшие проверку. //! \~russian Возвращает новый двумерный массив, содержащий только столбцы, прошедшие проверку.
//! \~\sa filterRows()
inline PIVector2D<T> filterColumns(std::function<bool(const ColConst &)> test) const { inline PIVector2D<T> filterColumns(std::function<bool(const ColConst &)> test) const {
if (isEmpty()) return PIVector2D<T>(); if (isEmpty()) return PIVector2D<T>();
PIVector<size_t> goodCols; PIVector<size_t> goodCols;
@@ -934,23 +1364,13 @@ public:
goodCols << c; goodCols << c;
} }
} }
PIVector2D<T> result(rows_, goodCols.size()); PIVector2D<T> result;
for (size_t r = 0; r < rows_; ++r) { for (size_t gc = 0; gc < goodCols.size(); ++gc) {
for (size_t gc = 0; gc < goodCols.size(); ++gc) { result.addColumn(col(goodCols[gc]));
result.element(r, gc) = element(r, goodCols[gc]);
}
} }
return result; return result;
} }
//! \~english Returns a new 2D array (as a single row) containing only the elements that pass the test.
//! \~russian Возвращает новый двумерный массив (в виде одной строки), содержащий только элементы, прошедшие проверку.
inline PIVector2D<T> filterElements(std::function<bool(const T &)> test) const {
PIVector<T> filtered = mat.filter(test);
if (filtered.isEmpty()) return PIVector2D<T>();
return PIVector2D<T>(1, filtered.size(), filtered);
}
protected: protected:
size_t rows_, cols_; size_t rows_, cols_;
PIVector<T> mat; PIVector<T> mat;

View File

@@ -245,9 +245,6 @@ inline constexpr T piAbs(const T & v) {
} }
//! \~\brief
//! \~english Templated function return minimum of two values
//! \~russian Шаблонный метод, возвращающий минимум из двух значений
template<typename T> template<typename T>
constexpr T piMin(const T & f, const T & s) { constexpr T piMin(const T & f, const T & s) {
return ((f > s) ? s : f); return ((f > s) ? s : f);
@@ -285,9 +282,6 @@ constexpr T piMin(const T & f, const T & s, const Args &... args) {
} }
//! \~\brief
//! \~english Templated function return maximum of two values
//! \~russian Шаблонный метод, возвращающий максимум из двух значений
template<typename T> template<typename T>
constexpr T piMax(const T & f, const T & s) { constexpr T piMax(const T & f, const T & s) {
return ((f < s) ? s : f); return ((f < s) ? s : f);

View File

@@ -64,16 +64,7 @@ PIP_EXPORT PIString errorString();
//! \~russian Сброс последней ошибки //! \~russian Сброс последней ошибки
PIP_EXPORT void errorClear(); PIP_EXPORT void errorClear();
//! \ingroup Core
//! \brief
//! \~english Initialize random number generator
//! \~russian Инициализация генератора случайных чисел
PIP_EXPORT void randomize(); PIP_EXPORT void randomize();
//! \ingroup Core
//! \brief
//! \~english Returns random integer value
//! \~russian Возвращает случайное целое число
PIP_EXPORT int randomi(); PIP_EXPORT int randomi();
//! \ingroup Core //! \ingroup Core

View File

@@ -45,15 +45,11 @@ public:
s = size_; s = size_;
} }
//! \~english Copy constructor
//! \~russian Конструктор копирования
PIMemoryBlock(const PIMemoryBlock & o) { PIMemoryBlock(const PIMemoryBlock & o) {
d = o.d; d = o.d;
s = o.s; s = o.s;
} }
//! \~english Assignment operator
//! \~russian Оператор присваивания
PIMemoryBlock & operator=(const PIMemoryBlock & o) { PIMemoryBlock & operator=(const PIMemoryBlock & o) {
d = o.d; d = o.d;
s = o.s; s = o.s;

View File

@@ -29,53 +29,21 @@
#include "pimathbase.h" #include "pimathbase.h"
//! \~english Geographical ellipsoid Earth model
//! \~russian Географическая эллипсоидная модель Земли
class PIP_EXPORT PIEllipsoidModel { class PIP_EXPORT PIEllipsoidModel {
public: public:
//! \~english Default constructor
//! \~russian Конструктор по умолчанию
PIEllipsoidModel(); PIEllipsoidModel();
double eccSquared() const { return eccentricity * eccentricity; } // eccentricity squared
//! \~english Get eccentricity squared
//! \~russian Получить квадрат эксцентриситета
double eccSquared() const { return eccentricity * eccentricity; }
//! \~english Get semi-minor axis (b)
//! \~russian Получить малую полуось (b)
double b() const { return a * sqrt(1 - eccSquared()); } double b() const { return a * sqrt(1 - eccSquared()); }
//! \~english WGS84 ellipsoid model
//! \~russian Эллипсоид WGS84
static PIEllipsoidModel WGS84Ellipsoid(); static PIEllipsoidModel WGS84Ellipsoid();
//! \~english PZ90 ellipsoid model
//! \~russian Эллипсоид ПЗ-90
static PIEllipsoidModel PZ90Ellipsoid(); static PIEllipsoidModel PZ90Ellipsoid();
//! \~english GPS ellipsoid (same as WGS84)
//! \~russian Эллипсоид GPS (то же что WGS84)
static PIEllipsoidModel GPSEllipsoid(); static PIEllipsoidModel GPSEllipsoid();
//! \~english Krasovskiy ellipsoid model
//! \~russian Эллипсоид Красовского
static PIEllipsoidModel KrasovskiyEllipsoid(); static PIEllipsoidModel KrasovskiyEllipsoid();
//! \~english Major semi-axis (meters) double a; /// Major axis of Earth in meters
//! \~russian Большая полуось (метры) double flattening; /// Flattening (ellipsoid parameter)
double a; double eccentricity; /// Eccentricity (ellipsoid parameter)
double angVelocity; /// Angular velocity of Earth in radians/sec
//! \~english Flattening (f = (a-b)/a)
//! \~russian Сплюснутость (f = (a-b)/a)
double flattening;
//! \~english First eccentricity
//! \~russian Первый эксцентриситет
double eccentricity;
//! \~english Angular velocity (rad/sec)
//! \~russian Угловая скорость (рад/сек)
double angVelocity;
}; };

View File

@@ -29,338 +29,147 @@
#include "piellipsoidmodel.h" #include "piellipsoidmodel.h"
#include "pimathvector.h" #include "pimathvector.h"
//! \~english Geographical position class
//! \~russian Класс географической позиции
class PIP_EXPORT PIGeoPosition: public PIMathVectorT3d { class PIP_EXPORT PIGeoPosition: public PIMathVectorT3d {
public: public:
//! \~english Coordinate system types
//! \~russian Типы систем координат
enum CoordinateSystem { enum CoordinateSystem {
Unknown = 0, //!< Unknown coordinate system Unknown = 0, /// Unknown coordinate system
Geodetic, //!< Geodetic latitude, longitude, and height above ellipsoid Geodetic, /// Geodetic latitude, longitude, and height above ellipsoid
Geocentric, //!< Geocentric (regular spherical coordinates) Geocentric, /// Geocentric (regular spherical coordinates)
Cartesian, //!< Cartesian (Earth-centered, Earth-fixed) Cartesian, /// Cartesian (Earth-centered, Earth-fixed)
Spherical //!< Spherical coordinates (theta,phi,radius) Spherical /// Spherical coordinates (theta,phi,radius)
}; };
//! \~english One centimeter tolerance static const double one_cm_tolerance; /// One centimeter tolerance.
//! \~russian Допуск один сантиметр static const double one_mm_tolerance; /// One millimeter tolerance.
static const double one_cm_tolerance; static const double one_um_tolerance; /// One micron tolerance.
static double position_tolerance; /// Default tolerance (default 1mm)
//! \~english One millimeter tolerance
//! \~russian Допуск один миллиметр
static const double one_mm_tolerance;
//! \~english One micron tolerance
//! \~russian Допуск один микрон
static const double one_um_tolerance;
//! \~english Default position tolerance (default 1mm)
//! \~russian Допуск позиции по умолчанию (по умолчанию 1мм)
static double position_tolerance;
//! \~english Set position tolerance
//! \~russian Установить допуск позиции
//! \param tol New tolerance value
//! \return Previous tolerance value
static double setPositionTolerance(const double tol) { static double setPositionTolerance(const double tol) {
position_tolerance = tol; position_tolerance = tol;
return position_tolerance; return position_tolerance;
} }
//! \~english Get position tolerance
//! \~russian Получить допуск позиции
static double getPositionTolerance() { return position_tolerance; } static double getPositionTolerance() { return position_tolerance; }
//! \~english Default constructor
//! \~russian Конструктор по умолчанию
PIGeoPosition(); PIGeoPosition();
//! \~english Constructor with coordinates
//! \~russian Конструктор с координатами
//! \param a First coordinate
//! \param b Second coordinate
//! \param c Third coordinate
//! \param s Coordinate system
//! \param ell Ellipsoid model
PIGeoPosition(double a, double b, double c, CoordinateSystem s = Cartesian, PIEllipsoidModel ell = PIEllipsoidModel::WGS84Ellipsoid()); PIGeoPosition(double a, double b, double c, CoordinateSystem s = Cartesian, PIEllipsoidModel ell = PIEllipsoidModel::WGS84Ellipsoid());
//! \~english Constructor from vector
//! \~russian Конструктор из вектора
//! \param v Vector with coordinates
//! \param s Coordinate system
//! \param ell Ellipsoid model
PIGeoPosition(PIMathVectorT3d v, CoordinateSystem s = Cartesian, PIEllipsoidModel ell = PIEllipsoidModel::WGS84Ellipsoid()); PIGeoPosition(PIMathVectorT3d v, CoordinateSystem s = Cartesian, PIEllipsoidModel ell = PIEllipsoidModel::WGS84Ellipsoid());
//! \~english Transform to specified coordinate system
//! \~russian Преобразовать в указанную систему координат
//! \param sys Target coordinate system
//! \return Reference to this position
PIGeoPosition & transformTo(CoordinateSystem sys); PIGeoPosition & transformTo(CoordinateSystem sys);
//! \~english Convert to geodetic coordinates
//! \~russian Преобразовать в геодезические координаты
PIGeoPosition & asGeodetic() { PIGeoPosition & asGeodetic() {
transformTo(Geodetic); transformTo(Geodetic);
return *this; return *this;
} } /// Convert to geodetic coordinate
//! \~english Convert to geodetic coordinates using specified ellipsoid
//! \~russian Преобразовать в геодезические координаты с указанным эллипсоидом
//! \param ell Ellipsoid model to use
//! \return Reference to this position
PIGeoPosition & asGeodetic(const PIEllipsoidModel & ell) { PIGeoPosition & asGeodetic(const PIEllipsoidModel & ell) {
setEllipsoidModel(ell); setEllipsoidModel(ell);
transformTo(Geodetic); transformTo(Geodetic);
return *this; return *this;
} } /// Convert to another ell, then to geodetic coordinates
//! \~english Convert to ECEF (cartesian) coordinates
//! \~russian Преобразовать в координаты ECEF (декартовы)
PIGeoPosition & asECEF() { PIGeoPosition & asECEF() {
transformTo(Cartesian); transformTo(Cartesian);
return *this; return *this;
} } /// Convert to cartesian coordinates
//! \~english Get X coordinate (or first coordinate in Cartesian)
//! \~russian Получить координату X (или первую координату в Декартовой)
double x() const; double x() const;
//! \~english Get Y coordinate (or second coordinate in Cartesian)
//! \~russian Получить координату Y (или вторую координату в Декартовой)
double y() const; double y() const;
//! \~english Get Z coordinate (or third coordinate in Cartesian)
//! \~russian Получить координату Z (или третью координату в Декартовой)
double z() const; double z() const;
//! \~english Get geodetic latitude in degrees
//! \~russian Получить геодезическую широту в градусах
double latitudeGeodetic() const; double latitudeGeodetic() const;
//! \~english Get geocentric latitude in degrees
//! \~russian Получить геоцентрическую широту в градусах
double latitudeGeocentric() const; double latitudeGeocentric() const;
//! \~english Get longitude in degrees
//! \~russian Получить долготу в градусах
double longitude() const; double longitude() const;
//! \~english Get theta (angle from Z axis) in degrees
//! \~russian Получить тета (угол от оси Z) в градусах
double theta() const; double theta() const;
//! \~english Get phi (angle in XY plane from X axis) in degrees
//! \~russian Получить фи (угол в плоскости XY от оси X) в градусах
double phi() const; double phi() const;
//! \~english Get radius (distance from Earth center)
//! \~russian Получить радиус (расстояние от центра Земли)
double radius() const; double radius() const;
//! \~english Get height above ellipsoid
//! \~russian Получить высоту над эллипсоидом
double height() const; double height() const;
//! \~english Set ellipsoid model for this position /// Set the ellipsoid values for this PIGeoPosition given a ellipsoid.
//! \~russian Установить модель эллипсоида для этой позиции
//! \param ell Ellipsoid model
void setEllipsoidModel(const PIEllipsoidModel & ell) { el = ell; } void setEllipsoidModel(const PIEllipsoidModel & ell) { el = ell; }
//! \~english Set position from geodetic coordinates /// Set the \a PIGeoPosition given geodetic coordinates in degrees. \a CoordinateSystem is set to \a Geodetic.
//! \~russian Установить позицию из геодезических координат
//! \param lat Latitude in degrees
//! \param lon Longitude in degrees
//! \param ht Height above ellipsoid
//! \param ell Ellipsoid model (default WGS84)
//! \return Reference to this position
PIGeoPosition & setGeodetic(double lat, double lon, double ht, PIEllipsoidModel ell = PIEllipsoidModel::WGS84Ellipsoid()); PIGeoPosition & setGeodetic(double lat, double lon, double ht, PIEllipsoidModel ell = PIEllipsoidModel::WGS84Ellipsoid());
//! \~english Set position from geocentric coordinates /// Set the \a PIGeoPosition given geocentric coordinates in degrees. \a CoordinateSystem is set to \a Geocentric
//! \~russian Установить позицию из геоцентрических координат
//! \param lat Latitude in degrees
//! \param lon Longitude in degrees
//! \param rad Radius
//! \return Reference to this position
PIGeoPosition & setGeocentric(double lat, double lon, double rad); PIGeoPosition & setGeocentric(double lat, double lon, double rad);
//! \~english Set position from spherical coordinates /// Set the \a PIGeoPosition given spherical coordinates in degrees. \a CoordinateSystem is set to \a Spherical
//! \~russian Установить позицию из сферических координат
//! \param theta Angle from Z axis in degrees
//! \param phi Angle in XY plane from X axis in degrees
//! \param rad Radius
//! \return Reference to this position
PIGeoPosition & setSpherical(double theta, double phi, double rad); PIGeoPosition & setSpherical(double theta, double phi, double rad);
//! \~english Set position from ECEF coordinates /// Set the \a PIGeoPosition given ECEF coordinates in meeters. \a CoordinateSystem is set to \a Cartesian.
//! \~russian Установить позицию из координат ECEF
//! \param x X coordinate in meters
//! \param y Y coordinate in meters
//! \param z Z coordinate in meters
//! \return Reference to this position
PIGeoPosition & setECEF(double x, double y, double z); PIGeoPosition & setECEF(double x, double y, double z);
//! \~english Convert spherical to Cartesian coordinates /// Fundamental conversion from spherical to cartesian coordinates.
//! \~russian Преобразовать сферические в декартовы координаты
//! \param tpr Input spherical (theta, phi, radius)
//! \param xyz Output Cartesian (x, y, z)
static void convertSphericalToCartesian(const PIMathVectorT3d & tpr, PIMathVectorT3d & xyz); static void convertSphericalToCartesian(const PIMathVectorT3d & tpr, PIMathVectorT3d & xyz);
//! \~english Convert Cartesian to spherical coordinates /// Fundamental routine to convert cartesian to spherical coordinates.
//! \~russian Преобразовать декартовы в сферические координаты
//! \param xyz Input Cartesian (x, y, z)
//! \param tpr Output spherical (theta, phi, radius)
static void convertCartesianToSpherical(const PIMathVectorT3d & xyz, PIMathVectorT3d & tpr); static void convertCartesianToSpherical(const PIMathVectorT3d & xyz, PIMathVectorT3d & tpr);
//! \~english Convert Cartesian (ECEF) to geodetic coordinates /// Fundamental routine to convert ECEF (cartesian) to geodetic coordinates,
//! \~russian Преобразовать декартовы (ECEF) в геодезические координаты
//! \param xyz Input Cartesian (x, y, z)
//! \param llh Output geodetic (latitude, longitude, height)
//! \param ell Ellipsoid model (default WGS84)
static void convertCartesianToGeodetic(const PIMathVectorT3d & xyz, static void convertCartesianToGeodetic(const PIMathVectorT3d & xyz,
PIMathVectorT3d & llh, PIMathVectorT3d & llh,
PIEllipsoidModel ell = PIEllipsoidModel::WGS84Ellipsoid()); PIEllipsoidModel ell = PIEllipsoidModel::WGS84Ellipsoid());
//! \~english Convert geodetic to Cartesian (ECEF) coordinates /// Fundamental routine to convert geodetic to ECEF (cartesian) coordinates,
//! \~russian Преобразовать геодезические в декартовы (ECEF) координаты
//! \param llh Input geodetic (latitude, longitude, height)
//! \param xyz Output Cartesian (x, y, z)
//! \param ell Ellipsoid model (default WGS84)
static void convertGeodeticToCartesian(const PIMathVectorT3d & llh, static void convertGeodeticToCartesian(const PIMathVectorT3d & llh,
PIMathVectorT3d & xyz, PIMathVectorT3d & xyz,
PIEllipsoidModel ell = PIEllipsoidModel::WGS84Ellipsoid()); PIEllipsoidModel ell = PIEllipsoidModel::WGS84Ellipsoid());
//! \~english Convert Cartesian (ECEF) to geocentric coordinates /// Fundamental routine to convert cartesian (ECEF) to geocentric
//! \~russian Преобразовать декартовы (ECEF) в геоцентрические координаты
//! \param xyz Input Cartesian (x, y, z)
//! \param llr Output geocentric (latitude, longitude, radius)
static void convertCartesianToGeocentric(const PIMathVectorT3d & xyz, PIMathVectorT3d & llr); static void convertCartesianToGeocentric(const PIMathVectorT3d & xyz, PIMathVectorT3d & llr);
//! \~english Convert geocentric to Cartesian (ECEF) /// Fundamental routine to convert geocentric to cartesian (ECEF)
//! \~russian Преобразовать геоцентрические в декартовы (ECEF)
//! \param llr Input geocentric (latitude, longitude, radius)
//! \param xyz Output Cartesian (x, y, z)
static void convertGeocentricToCartesian(const PIMathVectorT3d & llr, PIMathVectorT3d & xyz); static void convertGeocentricToCartesian(const PIMathVectorT3d & llr, PIMathVectorT3d & xyz);
//! \~english Convert geocentric to geodetic /// Fundamental routine to convert geocentric to geodetic
//! \~russian Преобразовать геоцентрические в геодезические
//! \param llr Input geocentric (latitude, longitude, radius)
//! \param llh Output geodetic (latitude, longitude, height)
//! \param ell Ellipsoid model (default WGS84)
static void convertGeocentricToGeodetic(const PIMathVectorT3d & llr, static void convertGeocentricToGeodetic(const PIMathVectorT3d & llr,
PIMathVectorT3d & llh, PIMathVectorT3d & llh,
PIEllipsoidModel ell = PIEllipsoidModel::WGS84Ellipsoid()); PIEllipsoidModel ell = PIEllipsoidModel::WGS84Ellipsoid());
//! \~english Convert geodetic to geocentric /// Fundamental routine to convert geodetic to geocentric
//! \~russian Преобразовать геодезические в геоцентрические
//! \param llh Input geodetic (latitude, longitude, height)
//! \param llr Output geocentric (latitude, longitude, radius)
//! \param ell Ellipsoid model (default WGS84)
static void convertGeodeticToGeocentric(const PIMathVectorT3d & llh, static void convertGeodeticToGeocentric(const PIMathVectorT3d & llh,
PIMathVectorT3d & llr, PIMathVectorT3d & llr,
PIEllipsoidModel ell = PIEllipsoidModel::WGS84Ellipsoid()); PIEllipsoidModel ell = PIEllipsoidModel::WGS84Ellipsoid());
//! \~english Compute radius of ellipsoid at given latitude /// Compute the radius of the ellipsoidal Earth, given the geodetic latitude.
//! \~russian Вычислить радиус эллипсоида на заданной широте
//! \param geolat Geodetic latitude in degrees
//! \param ell Ellipsoid model (default WGS84)
//! \return Radius in meters
static double radiusEarth(double geolat, PIEllipsoidModel ell = PIEllipsoidModel::WGS84Ellipsoid()); static double radiusEarth(double geolat, PIEllipsoidModel ell = PIEllipsoidModel::WGS84Ellipsoid());
//! \~english Compute radius of ellipsoid at current position
//! \~russian Вычислить радиус эллипсоида в текущей позиции
double radiusEarth() const { double radiusEarth() const {
PIGeoPosition p(*this); PIGeoPosition p(*this);
p.transformTo(PIGeoPosition::Geodetic); p.transformTo(PIGeoPosition::Geodetic);
return PIGeoPosition::radiusEarth((*this)[0], p.el); return PIGeoPosition::radiusEarth((*this)[0], p.el);
} }
//! \~english Compute range between two positions /// Compute the range in meters between two PIGeoPositions.
//! \~russian Вычислить расстояние между двумя позициями
//! \param a First position
//! \param b Second position
//! \return Range in meters
static double range(const PIGeoPosition & a, const PIGeoPosition & b); static double range(const PIGeoPosition & a, const PIGeoPosition & b);
//! \~english Compute range from this position to another
//! \~russian Вычислить расстояние от этой позиции до другой
//! \param p Target position
//! \return Range in meters
double range(const PIGeoPosition & p) const { return range((*this), p); } double range(const PIGeoPosition & p) const { return range((*this), p); }
//! \~english Compute elevation angle to target position /// Computes the elevation of the input (p) position as seen from this PIGeoPosition.
//! \~russian Вычислить угол возвышения до целевой позиции
//! \param p Target position
//! \return Elevation angle in degrees
double elevation(const PIGeoPosition & p) const; double elevation(const PIGeoPosition & p) const;
//! \~english Compute geodetic elevation angle to target position /// Computes the elevation of the input (p) position as seen from this PIGeoPosition, using a Geodetic (ellipsoidal) system.
//! \~russian Вычислить геодезический угол возвышения до целевой позиции
//! \param p Target position
//! \return Elevation angle in degrees
double elevationGeodetic(const PIGeoPosition & p) const; double elevationGeodetic(const PIGeoPosition & p) const;
//! \~english Compute azimuth angle to target position /// Computes the azimuth of the input (p) position as seen from this PIGeoPosition.
//! \~russian Вычислить азимут до целевой позиции
//! \param p Target position
//! \return Azimuth angle in degrees
double azimuth(const PIGeoPosition & p) const; double azimuth(const PIGeoPosition & p) const;
//! \~english Compute geodetic azimuth angle to target position /// Computes the azimuth of the input (p) position as seen from this PIGeoPosition, using a Geodetic (ellipsoidal) system.
//! \~russian Вычислить геодезический азимут до целевой позиции
//! \param p Target position
//! \return Azimuth angle in degrees
double azimuthGeodetic(const PIGeoPosition & p) const; double azimuthGeodetic(const PIGeoPosition & p) const;
//! \~english Get radius of curvature of the meridian /// Computes the radius of curvature of the meridian (Rm) corresponding to this PIGeoPosition.
//! \~russian Получить радиус кривизны меридиана
//! \return Radius in meters
double getCurvMeridian() const; double getCurvMeridian() const;
//! \~english Get radius of curvature in the prime vertical /// Computes the radius of curvature in the prime vertical (Rn) corresponding to this PIGeoPosition.
//! \~russian Получить радиус кривизны в вертикале
//! \return Radius in meters
double getCurvPrimeVertical() const; double getCurvPrimeVertical() const;
//! \~english Get as PIMathVectorT3d /// Returns as PIMathVectorT3d
//! \~russian Получить как PIMathVectorT3d
//! \return Reference to underlying vector
const PIMathVectorT3d & vector() const { return *this; } const PIMathVectorT3d & vector() const { return *this; }
//! \~english Assignment from vector
//! \~russian Присваивание из вектора
PIGeoPosition & operator=(const PIMathVectorT3d & v); PIGeoPosition & operator=(const PIMathVectorT3d & v);
//! \~english Subtraction
//! \~russian Вычитание
PIGeoPosition & operator-=(const PIGeoPosition & right); PIGeoPosition & operator-=(const PIGeoPosition & right);
//! \~english Addition
//! \~russian Сложение
PIGeoPosition & operator+=(const PIGeoPosition & right); PIGeoPosition & operator+=(const PIGeoPosition & right);
//! \~english Subtraction
//! \~russian Вычитание
friend PIGeoPosition operator-(const PIGeoPosition & left, const PIGeoPosition & right); friend PIGeoPosition operator-(const PIGeoPosition & left, const PIGeoPosition & right);
//! \~english Addition
//! \~russian Сложение
friend PIGeoPosition operator+(const PIGeoPosition & left, const PIGeoPosition & right); friend PIGeoPosition operator+(const PIGeoPosition & left, const PIGeoPosition & right);
//! \~english Scalar multiplication
//! \~russian Умножение на скаляр
friend PIGeoPosition operator*(const double & scale, const PIGeoPosition & right); friend PIGeoPosition operator*(const double & scale, const PIGeoPosition & right);
friend PIGeoPosition operator*(const PIGeoPosition & left, const double & scale); friend PIGeoPosition operator*(const PIGeoPosition & left, const double & scale);
friend PIGeoPosition operator*(const int & scale, const PIGeoPosition & right); friend PIGeoPosition operator*(const int & scale, const PIGeoPosition & right);
friend PIGeoPosition operator*(const PIGeoPosition & left, const int & scale); friend PIGeoPosition operator*(const PIGeoPosition & left, const int & scale);
//! \~english Equality comparison
//! \~russian Сравнение на равенство
bool operator==(const PIGeoPosition & right) const; bool operator==(const PIGeoPosition & right) const;
//! \~english Inequality comparison
//! \~russian Сравнение на неравенство
bool operator!=(const PIGeoPosition & right) const { return !(operator==(right)); } bool operator!=(const PIGeoPosition & right) const { return !(operator==(right)); }

View File

@@ -29,36 +29,16 @@
#include "piiodevice.h" #include "piiodevice.h"
//! \ingroup IO
//! \~\brief
//! \~english CAN device.
//! \~russian Устройство CAN.
class PIP_EXPORT PICAN: public PIIODevice { class PIP_EXPORT PICAN: public PIIODevice {
PIIODEVICE(PICAN, "can"); PIIODEVICE(PICAN, "can");
public: public:
//! \~english Constructs %PICAN with empty path and ReadWrite mode
//! \~russian Создаёт %PICAN с пустым путём и режимом ReadWrite
explicit PICAN(const PIString & path = PIString(), PIIODevice::DeviceMode mode = PIIODevice::ReadWrite); explicit PICAN(const PIString & path = PIString(), PIIODevice::DeviceMode mode = PIIODevice::ReadWrite);
//! \~english Destructor
//! \~russian Деструктор
virtual ~PICAN(); virtual ~PICAN();
//! \~english Set CAN ID for filtering received messages
//! \~russian Устанавливает CAN ID для фильтрации принимаемых сообщений
void setCANID(int id); void setCANID(int id);
//! \~english Returns current CAN ID
//! \~russian Возвращает текущий CAN ID
int CANID() const; int CANID() const;
//! \~english Returns CAN ID of last readed message
//! \~russian Возвращает CAN ID последнего прочитанного сообщения
int readedCANID() const; int readedCANID() const;
//! \~english Interrupt blocking operation
//! \~russian Прерывает блокирующую операцию
void interrupt() override; void interrupt() override;
protected: protected:

View File

@@ -29,10 +29,6 @@
#include "pidiagnostics.h" #include "pidiagnostics.h"
#include "piethernet.h" #include "piethernet.h"
//! \ingroup IO
//! \~\brief
//! \~english Peering net node.
//! \~russian Элемент пиринговой сети.
class PIP_EXPORT PIPeer: public PIIODevice { class PIP_EXPORT PIPeer: public PIIODevice {
PIIODEVICE(PIPeer, "peer"); PIIODEVICE(PIPeer, "peer");
@@ -40,16 +36,9 @@ private:
class PeerData; class PeerData;
public: public:
//! \~english Constructs %PIPeer with name "name"
//! \~russian Создаёт %PIPeer с именем "name"
explicit PIPeer(const PIString & name = PIString()); explicit PIPeer(const PIString & name = PIString());
//! \~english Destructor
//! \~russian Деструктор
virtual ~PIPeer(); virtual ~PIPeer();
//! \~english Peer information structure
//! \~russian Структура информации о пире
class PIP_EXPORT PeerInfo { class PIP_EXPORT PeerInfo {
friend class PIPeer; friend class PIPeer;
BINARY_STREAM_FRIEND(PIPeer::PeerInfo); BINARY_STREAM_FRIEND(PIPeer::PeerInfo);
@@ -98,89 +87,38 @@ public:
BINARY_STREAM_FRIEND(PIPeer::PeerInfo); BINARY_STREAM_FRIEND(PIPeer::PeerInfo);
//! \~english Send data to peer with name "to"
//! \~russian Отправляет данные пиру с именем "to"
bool send(const PIString & to, const PIByteArray & data) { return send(to, data.data(), data.size_s()); } bool send(const PIString & to, const PIByteArray & data) { return send(to, data.data(), data.size_s()); }
//! \~english Send string to peer with name "to"
//! \~russian Отправляет строку пиру с именем "to"
bool send(const PIString & to, const PIString & data) { return send(to, data.data(), data.size_s()); } bool send(const PIString & to, const PIString & data) { return send(to, data.data(), data.size_s()); }
bool send(const PIString & to, const void * data, int size); bool send(const PIString & to, const void * data, int size);
//! \~english Send data to peer "to"
//! \~russian Отправляет данные пиру "to"
bool send(const PeerInfo & to, const PIByteArray & data) { return send(to.name, data.data(), data.size_s()); } bool send(const PeerInfo & to, const PIByteArray & data) { return send(to.name, data.data(), data.size_s()); }
bool send(const PeerInfo & to, const PIString & data) { return send(to.name, data.data(), data.size_s()); } bool send(const PeerInfo & to, const PIString & data) { return send(to.name, data.data(), data.size_s()); }
bool send(const PeerInfo & to, const void * data, int size) { return send(to.name, data, size); } bool send(const PeerInfo & to, const void * data, int size) { return send(to.name, data, size); }
bool send(const PeerInfo * to, const PIByteArray & data); bool send(const PeerInfo * to, const PIByteArray & data);
bool send(const PeerInfo * to, const PIString & data); bool send(const PeerInfo * to, const PIString & data);
bool send(const PeerInfo * to, const void * data, int size); bool send(const PeerInfo * to, const void * data, int size);
//! \~english Send data to all peers
//! \~russian Отправляет данные всем пирам
void sendToAll(const PIByteArray & data); void sendToAll(const PIByteArray & data);
void sendToAll(const PIString & data); void sendToAll(const PIString & data);
void sendToAll(const void * data, int size); void sendToAll(const void * data, int size);
//! \~english Returns if receiving multicast packets is enabled
//! \~russian Возвращает включён ли приём мультикаст пакетов
bool isMulticastReceive() const { return !eths_mcast.isEmpty(); } bool isMulticastReceive() const { return !eths_mcast.isEmpty(); }
//! \~english Returns if receiving broadcast packets is enabled
//! \~russian Возвращает включён ли приём широковещательных пакетов
bool isBroadcastReceive() const { return !eths_bcast.isEmpty(); } bool isBroadcastReceive() const { return !eths_bcast.isEmpty(); }
//! \~english Returns diagnostic service
//! \~russian Возвращает диагностический сервис
PIDiagnostics & diagnosticService() { return diag_s; } PIDiagnostics & diagnosticService() { return diag_s; }
//! \~english Returns diagnostic data
//! \~russian Возвращает диагностические данные
PIDiagnostics & diagnosticData() { return diag_d; } PIDiagnostics & diagnosticData() { return diag_d; }
//! \~english Returns all known peers
//! \~russian Возвращает всех известных пиров
const PIVector<PIPeer::PeerInfo> & allPeers() const { return peers; } const PIVector<PIPeer::PeerInfo> & allPeers() const { return peers; }
//! \~english Returns if peer with name "name" exists
//! \~russian Возвращает существует ли пир с именем "name"
bool isPeerExists(const PIString & name) const { return getPeerByName(name) != 0; } bool isPeerExists(const PIString & name) const { return getPeerByName(name) != 0; }
//! \~english Returns peer info by name, or nullptr if not found
//! \~russian Возвращает информацию о пире по имени, или nullptr если не найден
const PeerInfo * getPeerByName(const PIString & name) const { return peers_map.value(name, 0); } const PeerInfo * getPeerByName(const PIString & name) const { return peers_map.value(name, 0); }
//! \~english Returns self info
//! \~russian Возвращает информацию о себе
const PeerInfo & selfInfo() const { return self_info; } const PeerInfo & selfInfo() const { return self_info; }
const PIMap<PIString, PIVector<PeerInfo *>> & _peerMap() const { return addresses_map; } const PIMap<PIString, PIVector<PeerInfo *>> & _peerMap() const { return addresses_map; }
//! \~english Reinitialize peer network
//! \~russian Переинициализирует пиринговую сеть
void reinit(); void reinit();
//! \~english Lock peers list
//! \~russian Блокирует список пиров
void lock() { peers_mutex.lock(); } void lock() { peers_mutex.lock(); }
//! \~english Unlock peers list
//! \~russian Разблокирует список пиров
void unlock() { peers_mutex.unlock(); } void unlock() { peers_mutex.unlock(); }
//! \~english Change peer name to "new_name"
//! \~russian Изменяет имя пира на "new_name"
void changeName(const PIString & new_name); void changeName(const PIString & new_name);
//! \~english Returns trusted peer name
//! \~russian Возвращает имя доверенного пира
const PIString & trustPeerName() const { return trust_peer; } const PIString & trustPeerName() const { return trust_peer; }
//! \~english Set trusted peer name
//! \~russian Устанавливает имя доверенного пира
void setTrustPeerName(const PIString & peer_name) { trust_peer = peer_name; } void setTrustPeerName(const PIString & peer_name) { trust_peer = peer_name; }
//! \~english Set TCP server IP address
//! \~russian Устанавливает IP адрес TCP сервера
void setTcpServerIP(const PIString & ip); void setTcpServerIP(const PIString & ip);
ssize_t bytesAvailable() const override; ssize_t bytesAvailable() const override;

View File

@@ -29,59 +29,35 @@
#include "piiodevice.h" #include "piiodevice.h"
//! \ingroup IO
//! \~\brief
//! \~english SPI device.
//! \~russian Устройство SPI.
class PIP_EXPORT PISPI: public PIIODevice { class PIP_EXPORT PISPI: public PIIODevice {
PIIODEVICE(PISPI, "spi"); PIIODEVICE(PISPI, "spi");
public: public:
//! \~english Constructs %PISPI with path "path", speed "speed_hz" and mode "mode"
//! \~russian Создаёт %PISPI с путём "path", скоростью "speed_hz" и режимом "mode"
explicit PISPI(const PIString & path = PIString(), uint speed_hz = 1000000, PIIODevice::DeviceMode mode = PIIODevice::ReadWrite); explicit PISPI(const PIString & path = PIString(), uint speed_hz = 1000000, PIIODevice::DeviceMode mode = PIIODevice::ReadWrite);
//! \~english Destructor
//! \~russian Деструктор
virtual ~PISPI(); virtual ~PISPI();
//! \~english Parameters of PISPI //! \brief Parameters of PISPI
//! \~russian Параметры PISPI
enum Parameters { enum Parameters {
ClockInverse /*! \~english SPI clk polarity control \~russian Управление полярностью SPI clk */ = 0x1, ClockInverse /*! SPI clk polarity control*/ = 0x1,
ClockPhaseShift /*! \~english SPI clk phase control \~russian Управление фазой SPI clk */ = 0x2, ClockPhaseShift /*! SPI clk phase control */ = 0x2,
}; };
//! \~english Set SPI speed in Hz
//! \~russian Устанавливает скорость SPI в Гц
void setSpeed(uint speed_hz); void setSpeed(uint speed_hz);
//! \~english Returns current SPI speed in Hz
//! \~russian Возвращает текущую скорость SPI в Гц
uint speed() const { return spi_speed; } uint speed() const { return spi_speed; }
//! \~english Set number of bits per word, default is 8
//! \~russian Устанавливает количество бит на слово, по умолчанию 8
void setBits(uchar bits = 8); void setBits(uchar bits = 8);
//! \~english Returns number of bits per word
//! \~russian Возвращает количество бит на слово
uchar bits() const { return spi_bits; } uchar bits() const { return spi_bits; }
//! \~english Set parameters to "parameters_" //! Set parameters to "parameters_"
//! \~russian Устанавливает параметры в "parameters_"
void setParameters(PIFlags<PISPI::Parameters> parameters_) { spi_mode = (int)parameters_; } void setParameters(PIFlags<PISPI::Parameters> parameters_) { spi_mode = (int)parameters_; }
//! \~english Set parameter "parameter" to "on" state //! Set parameter "parameter" to "on" state
//! \~russian Устанавливает параметр "parameter" в состояние "on"
void setParameter(PISPI::Parameters parameter, bool on = true); void setParameter(PISPI::Parameters parameter, bool on = true);
//! \~english Returns if parameter "parameter" is set //! Returns if parameter "parameter" is set
//! \~russian Возвращает установлен ли параметр "parameter"
bool isParameterSet(PISPI::Parameters parameter) const; bool isParameterSet(PISPI::Parameters parameter) const;
//! \~english Returns parameters //! Returns parameters
//! \~russian Возвращает параметры
PIFlags<PISPI::Parameters> parameters() const { return spi_mode; } PIFlags<PISPI::Parameters> parameters() const { return spi_mode; }
ssize_t bytesAvailable() const override; ssize_t bytesAvailable() const override;

View File

@@ -62,24 +62,13 @@
struct usb_dev_handle; struct usb_dev_handle;
//! \ingroup IO
//! \~\brief
//! \~english USB device.
//! \~russian Устройство USB.
class PIP_USB_EXPORT PIUSB: public PIIODevice { class PIP_USB_EXPORT PIUSB: public PIIODevice {
PIIODEVICE(PIUSB, "usb"); PIIODEVICE(PIUSB, "usb");
public: public:
//! \~english Constructs %PIUSB with vendor ID "vid" and product ID "pid"
//! \~russian Создаёт %PIUSB с идентификатором поставщика "vid" и идентификатором продукта "pid"
explicit PIUSB(ushort vid = 0, ushort pid = 0); explicit PIUSB(ushort vid = 0, ushort pid = 0);
//! \~english Destructor
//! \~russian Деструктор
virtual ~PIUSB(); virtual ~PIUSB();
//! \~english USB endpoint structure
//! \~russian Структура USB endpoint
struct PIP_USB_EXPORT Endpoint { struct PIP_USB_EXPORT Endpoint {
Endpoint(uchar a = 0, uchar at = 0, ushort mps = 0) { Endpoint(uchar a = 0, uchar at = 0, ushort mps = 0) {
address = a; address = a;
@@ -122,8 +111,6 @@ public:
UsageType usage_type = DataEndpoint; UsageType usage_type = DataEndpoint;
}; };
//! \~english USB interface structure
//! \~russian Структура USB интерфейса
struct PIP_USB_EXPORT Interface { struct PIP_USB_EXPORT Interface {
uchar index = 0; uchar index = 0;
uchar value_to_select = 0; uchar value_to_select = 0;
@@ -133,8 +120,6 @@ public:
PIVector<PIUSB::Endpoint> endpoints; PIVector<PIUSB::Endpoint> endpoints;
}; };
//! \~english USB configuration structure
//! \~russian Структура USB конфигурации
struct PIP_USB_EXPORT Configuration { struct PIP_USB_EXPORT Configuration {
uchar index = 0; uchar index = 0;
uchar value_to_select = 0; uchar value_to_select = 0;
@@ -145,8 +130,6 @@ public:
PIVector<PIUSB::Interface> interfaces; PIVector<PIUSB::Interface> interfaces;
}; };
//! \~english USB device descriptor structure
//! \~russian Структура дескриптора USB устройства
struct PIP_USB_EXPORT Descriptor { struct PIP_USB_EXPORT Descriptor {
ushort usb_spec_number = 0; ushort usb_spec_number = 0;
uchar device_class = 0; uchar device_class = 0;
@@ -162,100 +145,36 @@ public:
PIVector<PIUSB::Configuration> configurations; PIVector<PIUSB::Configuration> configurations;
}; };
//! \~english Returns current device descriptor
//! \~russian Возвращает текущий дескриптор устройства
const PIUSB::Descriptor & currentDescriptor() const { return desc_; } const PIUSB::Descriptor & currentDescriptor() const { return desc_; }
//! \~english Returns current configuration
//! \~russian Возвращает текущую конфигурацию
const PIUSB::Configuration & currentConfiguration() const { return conf_; } const PIUSB::Configuration & currentConfiguration() const { return conf_; }
//! \~english Returns current interface
//! \~russian Возвращает текущий интерфейс
const PIUSB::Interface & currentInterface() const { return iface_; } const PIUSB::Interface & currentInterface() const { return iface_; }
//! \~english Returns vendor ID
//! \~russian Возвращает ID поставщика
ushort vendorID() const { return vid_; } ushort vendorID() const { return vid_; }
//! \~english Returns product ID
//! \~russian Возвращает ID продукта
ushort productID() const { return pid_; } ushort productID() const { return pid_; }
//! \~english Returns device number
//! \~russian Возвращает номер устройства
int deviceNumber() const { return property("deviceNumber").toInt(); } int deviceNumber() const { return property("deviceNumber").toInt(); }
//! \~english Returns read timeout in milliseconds
//! \~russian Возвращает таймаут чтения в миллисекундах
int timeoutRead() const { return property("timeoutRead").toInt(); } int timeoutRead() const { return property("timeoutRead").toInt(); }
//! \~english Returns write timeout in milliseconds
//! \~russian Возвращает таймаут записи в миллисекундах
int timeoutWrite() const { return property("timeoutWrite").toInt(); } int timeoutWrite() const { return property("timeoutWrite").toInt(); }
//! \~english Returns read endpoint
//! \~russian Возвращает endpoint для чтения
const PIUSB::Endpoint & endpointRead() const { return ep_read; } const PIUSB::Endpoint & endpointRead() const { return ep_read; }
//! \~english Returns write endpoint
//! \~russian Возвращает endpoint для записи
const PIUSB::Endpoint & endpointWrite() const { return ep_write; } const PIUSB::Endpoint & endpointWrite() const { return ep_write; }
//! \~english Returns all endpoints
//! \~russian Возвращает все endpoints
const PIVector<PIUSB::Endpoint> & endpoints() const { return eps; } const PIVector<PIUSB::Endpoint> & endpoints() const { return eps; }
//! \~english Returns read endpoints
//! \~russian Возвращает endpoints для чтения
PIVector<PIUSB::Endpoint> endpointsRead(); PIVector<PIUSB::Endpoint> endpointsRead();
//! \~english Returns write endpoints
//! \~russian Возвращает endpoints для записи
PIVector<PIUSB::Endpoint> endpointsWrite(); PIVector<PIUSB::Endpoint> endpointsWrite();
//! \~english Returns endpoint by address
//! \~russian Возвращает endpoint по адресу
PIUSB::Endpoint getEndpointByAddress(uchar address); PIUSB::Endpoint getEndpointByAddress(uchar address);
//! \~english Set vendor ID to "vid"
//! \~russian Устанавливает ID поставщика в "vid"
void setVendorID(ushort vid); void setVendorID(ushort vid);
//! \~english Set product ID to "pid"
//! \~russian Устанавливает ID продукта в "pid"
void setProductID(ushort pid); void setProductID(ushort pid);
//! \~english Set configuration by value
//! \~russian Устанавливает конфигурацию по значению
bool setConfiguration(uchar value); bool setConfiguration(uchar value);
//! \~english Set interface by value
//! \~russian Устанавливает интерфейс по значению
bool setInterface(uchar value); bool setInterface(uchar value);
//! \~english Set read endpoint
//! \~russian Устанавливает endpoint для чтения
void setEndpointRead(const PIUSB::Endpoint & ep) { ep_read = ep; } void setEndpointRead(const PIUSB::Endpoint & ep) { ep_read = ep; }
//! \~english Set write endpoint
//! \~russian Устанавливает endpoint для записи
void setEndpointWrite(const PIUSB::Endpoint & ep) { ep_write = ep; } void setEndpointWrite(const PIUSB::Endpoint & ep) { ep_write = ep; }
//! \~english Set device number
//! \~russian Устанавливает номер устройства
void setDeviceNumber(int dn) { setProperty("deviceNumber", dn); } void setDeviceNumber(int dn) { setProperty("deviceNumber", dn); }
//! \~english Set read timeout in milliseconds
//! \~russian Устанавливает таймаут чтения в миллисекундах
void setTimeoutRead(int t) { setProperty("timeoutRead", t); } void setTimeoutRead(int t) { setProperty("timeoutRead", t); }
//! \~english Set write timeout in milliseconds
//! \~russian Устанавливает таймаут записи в миллисекундах
void setTimeoutWrite(int t) { setProperty("timeoutWrite", t); } void setTimeoutWrite(int t) { setProperty("timeoutWrite", t); }
//! \~english Control write to device
//! \~russian Управляющая запись в устройство
int controlWrite(const void * data, int max_size); int controlWrite(const void * data, int max_size);
virtual void flush() override; virtual void flush() override;

View File

@@ -1,10 +1,10 @@
//! \file picrc.h /*! \file picrc.h
//! \ingroup Math * \ingroup Math
//! \~\brief * \~\brief
//! \~english CRC checksum calculation * \~english CRC checksum calculation
//! \~russian Вычисление CRC контрольной суммы * \~russian Вычисление CRC контрольной суммы
*/
/*! /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
CRC checksum calculator CRC checksum calculator
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
@@ -28,113 +28,67 @@
#include "pistring.h" #include "pistring.h"
//! \addtogroup Math
//! \{
//! \class uint_cl
//! \brief
//! \~english Fixed-size unsigned integer class for CRC calculations
//! \~russian Класс целого числа фиксированного размера для вычисления CRC
//! \details
//! \~english Provides arbitrary length unsigned integer support for CRC computation
//! \~russian Обеспечивает поддержку целых чисел произвольной длины для вычисления CRC
//! \}
template<int L> template<int L>
class PIP_EXPORT uint_cl { class PIP_EXPORT uint_cl {
public: public:
//! \~english Default constructor, initializes to zero
//! \~russian Конструктор по умолчанию, инициализирует нулём
uint_cl() { uint_cl() {
for (int i = 0; i < L / 8; ++i) for (int i = 0; i < L / 8; ++i)
data_[i] = 0; data_[i] = 0;
} }
//! \~english Copy constructor
//! \~russian Конструктор копирования
uint_cl(const uint_cl<L> & v) { uint_cl(const uint_cl<L> & v) {
for (int i = 0; i < L / 8; ++i) for (int i = 0; i < L / 8; ++i)
data_[i] = v.data_[i]; data_[i] = v.data_[i];
} }
//! \~english Construct from unsigned char
//! \~russian Конструктор из unsigned char
uint_cl(uchar v) { uint_cl(uchar v) {
for (int i = 0; i < L / 8; ++i) for (int i = 0; i < L / 8; ++i)
data_[i] = (i == 0 ? v : 0); data_[i] = (i == 0 ? v : 0);
} }
//! \~english Construct from char
//! \~russian Конструктор из char
uint_cl(char v) { uint_cl(char v) {
for (int i = 0; i < L / 8; ++i) for (int i = 0; i < L / 8; ++i)
data_[i] = (i == 0 ? v : 0); data_[i] = (i == 0 ? v : 0);
} }
//! \~english Construct from unsigned short
//! \~russian Конструктор из unsigned short
uint_cl(ushort v) { uint_cl(ushort v) {
int l = piMin<uint>(L / 8, sizeof(v)); int l = piMin<uint>(L / 8, sizeof(v));
memcpy(data_, &v, l); memcpy(data_, &v, l);
for (int i = l; i < L / 8; ++i) for (int i = l; i < L / 8; ++i)
data_[i] = 0; data_[i] = 0;
} }
//! \~english Construct from short
//! \~russian Конструктор из short
uint_cl(short v) { uint_cl(short v) {
int l = piMin<uint>(L / 8, sizeof(v)); int l = piMin<uint>(L / 8, sizeof(v));
memcpy(data_, &v, l); memcpy(data_, &v, l);
for (int i = l; i < L / 8; ++i) for (int i = l; i < L / 8; ++i)
data_[i] = 0; data_[i] = 0;
} }
//! \~english Construct from unsigned int
//! \~russian Конструктор из unsigned int
uint_cl(uint v) { uint_cl(uint v) {
int l = piMin<uint>(L / 8, sizeof(v)); int l = piMin<uint>(L / 8, sizeof(v));
memcpy(data_, &v, l); memcpy(data_, &v, l);
for (int i = l; i < L / 8; ++i) for (int i = l; i < L / 8; ++i)
data_[i] = 0; data_[i] = 0;
} }
//! \~english Construct from int
//! \~russian Конструктор из int
uint_cl(int v) { uint_cl(int v) {
int l = piMin<uint>(L / 8, sizeof(v)); int l = piMin<uint>(L / 8, sizeof(v));
memcpy(data_, &v, l); memcpy(data_, &v, l);
for (int i = l; i < L / 8; ++i) for (int i = l; i < L / 8; ++i)
data_[i] = 0; data_[i] = 0;
} }
//! \~english Construct from unsigned long
//! \~russian Конструктор из unsigned long
uint_cl(ulong v) { uint_cl(ulong v) {
int l = piMin<uint>(L / 8, sizeof(v)); int l = piMin<uint>(L / 8, sizeof(v));
memcpy(data_, &v, l); memcpy(data_, &v, l);
for (int i = l; i < L / 8; ++i) for (int i = l; i < L / 8; ++i)
data_[i] = 0; data_[i] = 0;
} }
//! \~english Construct from long
//! \~russian Конструктор из long
uint_cl(long v) { uint_cl(long v) {
int l = piMin<uint>(L / 8, sizeof(v)); int l = piMin<uint>(L / 8, sizeof(v));
memcpy(data_, &v, l); memcpy(data_, &v, l);
for (int i = l; i < L / 8; ++i) for (int i = l; i < L / 8; ++i)
data_[i] = 0; data_[i] = 0;
} }
//! \~english Construct from unsigned long long
//! \~russian Конструктор из unsigned long long
uint_cl(ullong v) { uint_cl(ullong v) {
int l = piMin<uint>(L / 8, sizeof(v)); int l = piMin<uint>(L / 8, sizeof(v));
memcpy(data_, &v, l); memcpy(data_, &v, l);
for (int i = l; i < L / 8; ++i) for (int i = l; i < L / 8; ++i)
data_[i] = 0; data_[i] = 0;
} }
//! \~english Construct from long long
//! \~russian Конструктор из long long
uint_cl(llong v) { uint_cl(llong v) {
int l = piMin<uint>(L / 8, sizeof(v)); int l = piMin<uint>(L / 8, sizeof(v));
memcpy(data_, &v, l); memcpy(data_, &v, l);
@@ -142,87 +96,55 @@ public:
data_[i] = 0; data_[i] = 0;
} }
//! \~english Convert to bool
//! \~russian Преобразование в bool
operator bool() { operator bool() {
for (int i = 0; i < L / 8; ++i) for (int i = 0; i < L / 8; ++i)
if (data_[i] > 0) return true; if (data_[i] > 0) return true;
return false; return false;
} }
//! \~english Convert to char
//! \~russian Преобразование в char
operator char() { return (char)data_[0]; } operator char() { return (char)data_[0]; }
//! \~english Convert to short
//! \~russian Преобразование в short
operator short() { operator short() {
short t(0); short t(0);
int l = piMin<uint>(L / 8, sizeof(t)); int l = piMin<uint>(L / 8, sizeof(t));
memcpy(&t, data_, l); memcpy(&t, data_, l);
return t; return t;
} }
//! \~english Convert to int
//! \~russian Преобразование в int
operator int() { operator int() {
int t(0); int t(0);
int l = piMin<uint>(L / 8, sizeof(t)); int l = piMin<uint>(L / 8, sizeof(t));
memcpy(&t, data_, l); memcpy(&t, data_, l);
return t; return t;
} }
//! \~english Convert to long
//! \~russian Преобразование в long
operator long() { operator long() {
long t(0); long t(0);
int l = piMin<uint>(L / 8, sizeof(t)); int l = piMin<uint>(L / 8, sizeof(t));
memcpy(&t, data_, l); memcpy(&t, data_, l);
return t; return t;
} }
//! \~english Convert to long long
//! \~russian Преобразование в long long
operator llong() { operator llong() {
llong t(0); llong t(0);
int l = piMin<uint>(L / 8, sizeof(t)); int l = piMin<uint>(L / 8, sizeof(t));
memcpy(&t, data_, l); memcpy(&t, data_, l);
return t; return t;
} }
//! \~english Convert to unsigned char
//! \~russian Преобразование в unsigned char
operator uchar() { return data_[0]; } operator uchar() { return data_[0]; }
//! \~english Convert to unsigned short
//! \~russian Преобразование в unsigned short
operator ushort() { operator ushort() {
ushort t(0); ushort t(0);
int l = piMin<uint>(L / 8, sizeof(t)); int l = piMin<uint>(L / 8, sizeof(t));
memcpy(&t, data_, l); memcpy(&t, data_, l);
return t; return t;
} }
//! \~english Convert to unsigned int
//! \~russian Преобразование в unsigned int
operator uint() { operator uint() {
uint t(0); uint t(0);
int l = piMin<uint>(L / 8, sizeof(t)); int l = piMin<uint>(L / 8, sizeof(t));
memcpy(&t, data_, l); memcpy(&t, data_, l);
return t; return t;
} }
//! \~english Convert to unsigned long
//! \~russian Преобразование в unsigned long
operator ulong() { operator ulong() {
ulong t(0); ulong t(0);
int l = piMin<uint>(L / 8, sizeof(t)); int l = piMin<uint>(L / 8, sizeof(t));
memcpy(&t, data_, l); memcpy(&t, data_, l);
return t; return t;
} }
//! \~english Convert to unsigned long long
//! \~russian Преобразование в unsigned long long
operator ullong() { operator ullong() {
ullong t(0); ullong t(0);
int l = piMin<uint>(L / 8, sizeof(t)); int l = piMin<uint>(L / 8, sizeof(t));
@@ -230,8 +152,6 @@ public:
return t; return t;
} }
//! \~english Addition operator
//! \~russian Оператор сложения
uint_cl<L> operator+(const uint_cl<L> & v) { uint_cl<L> operator+(const uint_cl<L> & v) {
uint_cl<L> t; uint_cl<L> t;
uint cv; uint cv;
@@ -245,15 +165,12 @@ public:
return t; return t;
} }
//! \~english Bitwise AND operator
//! \~russian Побитовый оператор И
uint_cl<L> operator&(const uint_cl<L> & v) const { uint_cl<L> operator&(const uint_cl<L> & v) const {
uint_cl<L> t; uint_cl<L> t;
for (int i = 0; i < L / 8; ++i) for (int i = 0; i < L / 8; ++i)
t.data_[i] = v.data_[i] & data_[i]; t.data_[i] = v.data_[i] & data_[i];
return t; return t;
} }
uint_cl<L> operator&(const uchar & v) const { return *this & uint_cl<L>(v); } uint_cl<L> operator&(const uchar & v) const { return *this & uint_cl<L>(v); }
uint_cl<L> operator&(const ushort & v) const { return *this & uint_cl<L>(v); } uint_cl<L> operator&(const ushort & v) const { return *this & uint_cl<L>(v); }
uint_cl<L> operator&(const uint & v) const { return *this & uint_cl<L>(v); } uint_cl<L> operator&(const uint & v) const { return *this & uint_cl<L>(v); }
@@ -265,15 +182,12 @@ public:
uint_cl<L> operator&(const long & v) const { return *this & uint_cl<L>(v); } uint_cl<L> operator&(const long & v) const { return *this & uint_cl<L>(v); }
uint_cl<L> operator&(const llong & v) const { return *this & uint_cl<L>(v); } uint_cl<L> operator&(const llong & v) const { return *this & uint_cl<L>(v); }
//! \~english Bitwise OR operator
//! \~russian Побитовый оператор ИЛИ
uint_cl<L> operator|(const uint_cl<L> & v) const { uint_cl<L> operator|(const uint_cl<L> & v) const {
uint_cl<L> t; uint_cl<L> t;
for (int i = 0; i < L / 8; ++i) for (int i = 0; i < L / 8; ++i)
t.data_[i] = v.data_[i] | data_[i]; t.data_[i] = v.data_[i] | data_[i];
return t; return t;
} }
uint_cl<L> operator|(const uchar & v) const { return *this | uint_cl<L>(v); } uint_cl<L> operator|(const uchar & v) const { return *this | uint_cl<L>(v); }
uint_cl<L> operator|(const ushort & v) const { return *this | uint_cl<L>(v); } uint_cl<L> operator|(const ushort & v) const { return *this | uint_cl<L>(v); }
uint_cl<L> operator|(const uint & v) const { return *this | uint_cl<L>(v); } uint_cl<L> operator|(const uint & v) const { return *this | uint_cl<L>(v); }
@@ -285,15 +199,12 @@ public:
uint_cl<L> operator|(const long & v) const { return *this | uint_cl<L>(v); } uint_cl<L> operator|(const long & v) const { return *this | uint_cl<L>(v); }
uint_cl<L> operator|(const llong & v) const { return *this | uint_cl<L>(v); } uint_cl<L> operator|(const llong & v) const { return *this | uint_cl<L>(v); }
//! \~english Bitwise XOR operator
//! \~russian Побитовый оператор исключающее ИЛИ
uint_cl<L> operator^(const uint_cl<L> & v) const { uint_cl<L> operator^(const uint_cl<L> & v) const {
uint_cl<L> t; uint_cl<L> t;
for (int i = 0; i < L / 8; ++i) for (int i = 0; i < L / 8; ++i)
t.data_[i] = v.data_[i] ^ data_[i]; t.data_[i] = v.data_[i] ^ data_[i];
return t; return t;
} }
uint_cl<L> operator^(const uchar & v) const { return *this ^ uint_cl<L>(v); } uint_cl<L> operator^(const uchar & v) const { return *this ^ uint_cl<L>(v); }
uint_cl<L> operator^(const ushort & v) const { return *this ^ uint_cl<L>(v); } uint_cl<L> operator^(const ushort & v) const { return *this ^ uint_cl<L>(v); }
uint_cl<L> operator^(const uint & v) const { return *this ^ uint_cl<L>(v); } uint_cl<L> operator^(const uint & v) const { return *this ^ uint_cl<L>(v); }
@@ -305,8 +216,6 @@ public:
uint_cl<L> operator^(const long & v) const { return *this ^ uint_cl<L>(v); } uint_cl<L> operator^(const long & v) const { return *this ^ uint_cl<L>(v); }
uint_cl<L> operator^(const llong & v) const { return *this ^ uint_cl<L>(v); } uint_cl<L> operator^(const llong & v) const { return *this ^ uint_cl<L>(v); }
//! \~english Less than operator
//! \~russian Оператор меньше
bool operator<(const uint_cl<L> & v) const { bool operator<(const uint_cl<L> & v) const {
for (int i = 0; i < L / 8; ++i) { for (int i = 0; i < L / 8; ++i) {
if (v.data_[i] > data_[i]) return true; if (v.data_[i] > data_[i]) return true;
@@ -314,9 +223,6 @@ public:
} }
return false; return false;
} }
//! \~english Less than or equal operator
//! \~russian Оператор меньше или равно
bool operator<=(const uint_cl<L> & v) const { bool operator<=(const uint_cl<L> & v) const {
for (int i = 0; i < L / 8; ++i) { for (int i = 0; i < L / 8; ++i) {
if (v.data_[i] > data_[i]) return true; if (v.data_[i] > data_[i]) return true;
@@ -324,9 +230,6 @@ public:
} }
return true; return true;
} }
//! \~english Greater than operator
//! \~russian Оператор больше
bool operator>(const uint_cl<L> & v) const { bool operator>(const uint_cl<L> & v) const {
for (int i = 0; i < L / 8; ++i) { for (int i = 0; i < L / 8; ++i) {
if (v.data_[i] < data_[i]) return true; if (v.data_[i] < data_[i]) return true;
@@ -334,9 +237,6 @@ public:
} }
return false; return false;
} }
//! \~english Greater than or equal operator
//! \~russian Оператор больше или равно
bool operator>=(const uint_cl<L> & v) const { bool operator>=(const uint_cl<L> & v) const {
for (int i = 0; i < L / 8; ++i) { for (int i = 0; i < L / 8; ++i) {
if (v.data_[i] < data_[i]) return true; if (v.data_[i] < data_[i]) return true;
@@ -344,27 +244,18 @@ public:
} }
return true; return true;
} }
//! \~english Equality operator
//! \~russian Оператор равенства
bool operator==(const uint_cl<L> & v) const { bool operator==(const uint_cl<L> & v) const {
for (int i = 0; i < L / 8; ++i) for (int i = 0; i < L / 8; ++i)
if (v.data_[i] != data_[i]) return false; if (v.data_[i] != data_[i]) return false;
return true; return true;
} }
//! \~english Inequality operator
//! \~russian Оператор неравенства
bool operator!=(const uint_cl<L> & v) const { bool operator!=(const uint_cl<L> & v) const {
for (int i = 0; i < L / 8; ++i) for (int i = 0; i < L / 8; ++i)
if (v.data_[i] != data_[i]) return true; if (v.data_[i] != data_[i]) return true;
return false; return false;
} }
bool operator<=(const uint_cl<8> & v1) { return (*(uchar *)data()) <= (*(uchar *)v1.data()); } bool operator<=(const uint_cl<8> & v1) { return (*(uchar *)data()) <= (*(uchar *)v1.data()); }
//! \~english Right shift operator
//! \~russian Оператор побитового сдвига вправо
uint_cl<L> operator>>(const int & c) const { uint_cl<L> operator>>(const int & c) const {
uint_cl<L> t; uint_cl<L> t;
int l = L - c; int l = L - c;
@@ -379,11 +270,7 @@ public:
} }
return t; return t;
} }
uint_cl<L> operator>>(const uint & c) const { return (*this << (int)c); } uint_cl<L> operator>>(const uint & c) const { return (*this << (int)c); }
//! \~english Left shift operator
//! \~russian Оператор побитового сдвига влево
uint_cl<L> operator<<(const int & c) const { uint_cl<L> operator<<(const int & c) const {
uint_cl<L> t; uint_cl<L> t;
int l = L - c; int l = L - c;
@@ -398,28 +285,19 @@ public:
} }
return t; return t;
} }
uint_cl<L> operator<<(const uint & c) const { return (*this >> (int)c); } uint_cl<L> operator<<(const uint & c) const { return (*this >> (int)c); }
//! \~english In-place bitwise inversion
//! \~russian Побитовая инверсия на месте
uint_cl<L> & inverse() const { uint_cl<L> & inverse() const {
for (int i = 0; i < L / 8; ++i) for (int i = 0; i < L / 8; ++i)
data_[i] = ~data_[i]; data_[i] = ~data_[i];
return *this; return *this;
} }
//! \~english Returns bitwise inverted copy
//! \~russian Возвращает копию с побитовой инверсией
uint_cl<L> inversed() const { uint_cl<L> inversed() const {
uint_cl<L> t(*this); uint_cl<L> t(*this);
for (int i = 0; i < L / 8; ++i) for (int i = 0; i < L / 8; ++i)
t.data_[i] = ~t.data_[i]; t.data_[i] = ~t.data_[i];
return t; return t;
} }
//! \~english Returns bit-reversed copy
//! \~russian Возвращает копию с переставленными битами
uint_cl<L> reversed() const { uint_cl<L> reversed() const {
uint_cl<L> t; uint_cl<L> t;
bool bit; bool bit;
@@ -433,16 +311,8 @@ public:
return t; return t;
} }
//! \~english Get const pointer to data
//! \~russian Получить константный указатель на данные
const uchar * data() const { return data_; } const uchar * data() const { return data_; }
//! \~english Get pointer to data
//! \~russian Получить указатель на данные
uchar * data() { return data_; } uchar * data() { return data_; }
//! \~english Get data length in bytes
//! \~russian Получить длину данных в байтах
uint length() const { return L / 8; } uint length() const { return L / 8; }
private: private:
@@ -450,11 +320,6 @@ private:
}; };
//! \~english Reverse byte order
//! \~russian Реверс порядка байтов
//! \details
//! \~english Reverses the bit order within a byte
//! \~russian Инвертирует порядок битов в байте
inline uchar reverseByte(uchar b) { inline uchar reverseByte(uchar b) {
uchar ret = 0; uchar ret = 0;
bool bit; bool bit;
@@ -465,26 +330,9 @@ inline uchar reverseByte(uchar b) {
return ret; return ret;
} }
//! \addtogroup Math
//! \{
//! \class PICRC
//! \brief
//! \~english CRC calculator class
//! \~russian Класс калькулятора CRC
//! \details
//! \~english Calculates CRC checksum using configurable polynomial and parameters
//! \~russian Вычисляет контрольную сумму CRC с использованием настраиваемого полинома и параметров
//! \sa CRC_32, CRC_16, CRC_8
//! \}
template<uint L, typename N = uint_cl<L>> template<uint L, typename N = uint_cl<L>>
class PIP_EXPORT PICRC { class PIP_EXPORT PICRC {
public: public:
//! \~english Default constructor
//! \~russian Конструктор по умолчанию
//! \note
//! \~english Polynomial value defaults to zero
//! \~russian Значение полинома по умолчанию ноль
PICRC(const N & poly = N()) { PICRC(const N & poly = N()) {
poly_ = poly; poly_ = poly;
reverse_poly = true; reverse_poly = true;
@@ -493,13 +341,6 @@ public:
reverse_before_xor = reverse_data = false; reverse_before_xor = reverse_data = false;
initTable(); initTable();
} }
//! \~english Constructor with full parameters
//! \~russian Конструктор с полными параметрами
//! \param poly polynomial value
//! \param reverse_poly_ whether to reverse polynomial bits
//! \param initial initial CRC value
//! \param out_xor XOR value for output
PICRC(const N & poly, bool reverse_poly_, const N & initial, const N & out_xor) { PICRC(const N & poly, bool reverse_poly_, const N & initial, const N & out_xor) {
poly_ = poly; poly_ = poly;
reverse_poly = reverse_poly_; reverse_poly = reverse_poly_;
@@ -509,33 +350,18 @@ public:
initTable(); initTable();
} }
//! \~english Set initial CRC value
//! \~russian Установить начальное значение CRC
void setInitial(const N & v) { init_ = v; } void setInitial(const N & v) { init_ = v; }
//! \~english Set output XOR value
//! \~russian Установить значение XOR для вывода
void setOutXor(const N & v) { out_ = v; } void setOutXor(const N & v) { out_ = v; }
//! \~english Set polynomial bit reversal
//! \~russian Установить реверс битов полинома
void setReversePolynome(bool yes) { void setReversePolynome(bool yes) {
reverse_poly = yes; reverse_poly = yes;
initTable(); initTable();
} }
//! \~english Set output bit reversal before XOR
//! \~russian Установить реверс битов вывода перед XOR
void setReverseOutBeforeXOR(bool yes) { reverse_before_xor = yes; } void setReverseOutBeforeXOR(bool yes) { reverse_before_xor = yes; }
//! \~english Set data byte reversal
//! \~russian Установить реверс байтов данных
void setReverseDataBytes(bool yes) { reverse_data = yes; } void setReverseDataBytes(bool yes) { reverse_data = yes; }
//! \~english Initialize lookup table
//! \~russian Инициализировать таблицу поиска
void initTable() { void initTable() {
N tmp, pol = reverse_poly ? reversed(poly_) : poly_; N tmp, pol = reverse_poly ? reversed(poly_) : poly_;
// cout << std::hex << "poly " << (uint)N(poly_) << " -> " << (uint)N(pol) << endl;
for (int i = 0; i < 256; ++i) { for (int i = 0; i < 256; ++i) {
tmp = uchar(i); tmp = uchar(i);
for (int j = 0; j < 8; ++j) for (int j = 0; j < 8; ++j)
@@ -544,11 +370,10 @@ public:
} }
} }
//! \~english Calculate CRC from raw data
//! \~russian Вычислить CRC из сырых данных
N calculate(const void * data, int size) { N calculate(const void * data, int size) {
N crc = init_; N crc = init_;
uchar *data_ = (uchar *)data, cb; uchar *data_ = (uchar *)data, cb;
// cout << "process " << size << endl;
uchar nTemp; uchar nTemp;
for (int i = 0; i < size; ++i) { for (int i = 0; i < size; ++i) {
cb = data_[i]; cb = data_[i];
@@ -560,13 +385,7 @@ public:
if (reverse_before_xor) crc = reversed(crc); if (reverse_before_xor) crc = reversed(crc);
return crc ^ out_; return crc ^ out_;
} }
//! \~english Calculate CRC from PIByteArray
//! \~russian Вычислить CRC из PIByteArray
N calculate(const PIByteArray & d) { return calculate(d.data(), d.size()); } N calculate(const PIByteArray & d) { return calculate(d.data(), d.size()); }
//! \~english Calculate CRC from null-terminated string
//! \~russian Вычислить CRC из нуль-терминированной строки
N calculate(const char * str) { N calculate(const char * str) {
PIByteArray s(PIString(str).toByteArray()); PIByteArray s(PIString(str).toByteArray());
return calculate(s.data(), s.size_s()); return calculate(s.data(), s.size_s());
@@ -606,46 +425,22 @@ inline uint PICRC<32, uint>::inversed(const uint & v) {
return ~v; return ~v;
} }
//! \~english Standard CRC-32 (Ethernet, ZIP, etc.)
//! \~russian Стандартный CRC-32 (Ethernet, ZIP и т.д.)
typedef PICRC<32, uint> CRC_32; typedef PICRC<32, uint> CRC_32;
//! \~english Standard CRC-24
//! \~russian Стандартный CRC-24
typedef PICRC<24> CRC_24; typedef PICRC<24> CRC_24;
//! \~english Standard CRC-16
//! \~russian Стандартный CRC-16
typedef PICRC<16, ushort> CRC_16; typedef PICRC<16, ushort> CRC_16;
//! \~english Standard CRC-8
//! \~russian Стандартный CRC-8
typedef PICRC<8, uchar> CRC_8; typedef PICRC<8, uchar> CRC_8;
//! \~english Create standard CRC-32 calculator
//! \~russian Создать стандартный калькулятор CRC-32
inline CRC_32 standardCRC_32() { inline CRC_32 standardCRC_32() {
return CRC_32(0x04C11DB7, true, 0xFFFFFFFF, 0xFFFFFFFF); return CRC_32(0x04C11DB7, true, 0xFFFFFFFF, 0xFFFFFFFF);
} }
//! \~english Create standard CRC-16 calculator
//! \~russian Создать стандартный калькулятор CRC-16
inline CRC_16 standardCRC_16() { inline CRC_16 standardCRC_16() {
return CRC_16(0x8005, true, 0x0, 0x0); return CRC_16(0x8005, true, 0x0, 0x0);
} }
//! \~english Create standard CRC-16 Modbus calculator
//! \~russian Создать стандартный калькулятор CRC-16 Modbus
inline CRC_16 standardCRC_16_Modbus() { inline CRC_16 standardCRC_16_Modbus() {
return CRC_16(0x8005, 0xFFFF, 0xFFFF, false); return CRC_16(0x8005, 0xFFFF, 0xFFFF, false);
} }
//! \~english Create standard CRC-8 calculator
//! \~russian Создать стандартный калькулятор CRC-8
inline CRC_8 standardCRC_8() { inline CRC_8 standardCRC_8() {
return CRC_8(0xD5, true, 0x0, 0x0); return CRC_8(0xD5, true, 0x0, 0x0);
} }
//! \}
#endif // CRC_H #endif // CRC_H

View File

@@ -1,13 +1,10 @@
//! \addtogroup Math /*! \file pifft.h
//! \{ * \ingroup Math
//! \file pifft.h * \ingroup FFTW
//! \brief * \~\brief
//! \~english Declares \a PIFFT classes * \~english FFT, IFFT and Hilbert transformations
//! \~russian Объявление классов \a PIFFT * \~russian БПФ, ОБПФ и преобразования Гильберта
//! \~\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 PIP - Platform Independent Primitives
Class for FFT, IFFT and Hilbert transformations Class for FFT, IFFT and Hilbert transformations
@@ -67,40 +64,16 @@
# include "pip_fftw_export.h" # include "pip_fftw_export.h"
//! \addtogroup Math
//! \{
//! \class PIFFT_double
//! \brief
//! \~english Fast Fourier Transform implementation for double precision.
//! \~russian Реализация быстрого преобразования Фурье для двойной точности.
//! \~\}
//! \sa \a PIFFT_float, \a PIFFTW
class PIP_EXPORT PIFFT_double { class PIP_EXPORT PIFFT_double {
public: public:
//! \~english Default constructor.
//! \~russian Конструктор по умолчанию.
PIFFT_double(); PIFFT_double();
//! \~english Calculate FFT from complex vector.
//! \~russian Вычисление БПФ из комплексного вектора.
PIVector<complexd> * calcFFT(const PIVector<complexd> & val); PIVector<complexd> * calcFFT(const PIVector<complexd> & val);
//! \~english Calculate FFT from real vector.
//! \~russian Вычисление БПФ из вещественного вектора.
PIVector<complexd> * calcFFT(const PIVector<double> & val); PIVector<complexd> * calcFFT(const PIVector<double> & val);
//! \~english Calculate inverse FFT.
//! \~russian Вычисление обратного БПФ.
PIVector<complexd> * calcFFTinverse(const PIVector<complexd> & val); PIVector<complexd> * calcFFTinverse(const PIVector<complexd> & val);
//! \~english Calculate Hilbert transform.
//! \~russian Вычисление преобразования Гильберта.
PIVector<complexd> * calcHilbert(const PIVector<double> & val); PIVector<complexd> * calcHilbert(const PIVector<double> & val);
//! \~english Get amplitude spectrum.
//! \~russian Получить амплитудный спектр.
PIVector<double> getAmplitude() const; PIVector<double> getAmplitude() const;
//! \~english Get real part.
//! \~russian Получить действительную часть.
PIVector<double> getReal() const; PIVector<double> getReal() const;
//! \~english Get imaginary part.
//! \~russian Получить мнимую часть.
PIVector<double> getImag() const; PIVector<double> getImag() const;
private: private:
@@ -145,40 +118,16 @@ private:
void ftbase_ffttwcalc(PIVector<double> * a, int aoffset, int n1, int n2); void ftbase_ffttwcalc(PIVector<double> * a, int aoffset, int n1, int n2);
}; };
//! \addtogroup Math
//! \{
//! \class PIFFT_float
//! \brief
//! \~english Fast Fourier Transform implementation for single precision.
//! \~russian Реализация быстрого преобразования Фурье для одинарной точности.
//! \~\}
//! \sa \a PIFFT_double, \a PIFFTW
class PIP_EXPORT PIFFT_float { class PIP_EXPORT PIFFT_float {
public: public:
//! \~english Default constructor.
//! \~russian Конструктор по умолчанию.
PIFFT_float(); PIFFT_float();
//! \~english Calculate FFT from complex vector.
//! \~russian Вычисление БПФ из комплексного вектора.
PIVector<complexf> * calcFFT(const PIVector<complexf> & val); PIVector<complexf> * calcFFT(const PIVector<complexf> & val);
//! \~english Calculate FFT from real vector.
//! \~russian Вычисление БПФ из вещественного вектора.
PIVector<complexf> * calcFFT(const PIVector<float> & val); PIVector<complexf> * calcFFT(const PIVector<float> & val);
//! \~english Calculate inverse FFT.
//! \~russian Вычисление обратного БПФ.
PIVector<complexf> * calcFFTinverse(const PIVector<complexf> & val); PIVector<complexf> * calcFFTinverse(const PIVector<complexf> & val);
//! \~english Calculate Hilbert transform.
//! \~russian Вычисление преобразования Гильберта.
PIVector<complexf> * calcHilbert(const PIVector<float> & val); PIVector<complexf> * calcHilbert(const PIVector<float> & val);
//! \~english Get amplitude spectrum.
//! \~russian Получить амплитудный спектр.
PIVector<float> getAmplitude() const; PIVector<float> getAmplitude() const;
//! \~english Get real part.
//! \~russian Получить действительную часть.
PIVector<float> getReal() const; PIVector<float> getReal() const;
//! \~english Get imaginary part.
//! \~russian Получить мнимую часть.
PIVector<float> getImag() const; PIVector<float> getImag() const;
private: private:
@@ -222,7 +171,6 @@ private:
void ftbase_fftirltrec(PIVector<float> * a, int astart, int astride, PIVector<float> * b, int bstart, int bstride, int m, int n); void ftbase_fftirltrec(PIVector<float> * a, int astart, int astride, PIVector<float> * b, int bstart, int bstride, int m, int n);
void ftbase_ffttwcalc(PIVector<float> * a, int aoffset, int n1, int n2); void ftbase_ffttwcalc(PIVector<float> * a, int aoffset, int n1, int n2);
}; };
//! \~\}
typedef PIFFT_double PIFFT; typedef PIFFT_double PIFFT;
typedef PIFFT_double PIFFTd; typedef PIFFT_double PIFFTd;
@@ -230,63 +178,40 @@ typedef PIFFT_float PIFFTf;
# ifndef CC_VC # ifndef CC_VC
# define _PIFFTW_H(type) \ # define _PIFFTW_H(type) \
class PIP_FFTW_EXPORT _PIFFTW_P_##type##_ { \ class PIP_FFTW_EXPORT _PIFFTW_P_##type##_ { \
public: \ public: \
_PIFFTW_P_##type##_(); \ _PIFFTW_P_##type##_(); \
~_PIFFTW_P_##type##_(); \ ~_PIFFTW_P_##type##_(); \
const PIVector<complex<type>> & calcFFT(const PIVector<complex<type>> & in); \ const PIVector<complex<type>> & calcFFT(const PIVector<complex<type>> & in); \
const PIVector<complex<type>> & calcFFTR(const PIVector<type> & in); \ const PIVector<complex<type>> & calcFFTR(const PIVector<type> & in); \
const PIVector<complex<type>> & calcFFTI(const PIVector<complex<type>> & in); \ const PIVector<complex<type>> & calcFFTI(const PIVector<complex<type>> & in); \
void preparePlan(int size, int op); \ void preparePlan(int size, int op); \
void * impl; \ void * impl; \
}; };
_PIFFTW_H(float) _PIFFTW_H(float)
_PIFFTW_H(double) _PIFFTW_H(double)
_PIFFTW_H(ldouble) _PIFFTW_H(ldouble)
//! \addtogroup FFTW
//! \{
//! \class PIFFTW
//! \brief
//! \~english FFTW wrapper for arbitrary precision types.
//! \~russian Обёртка FFTW для типов произвольной точности.
//! \~\}
//! \note Requires linking against libfftw3
//! \sa \a PIFFT_double, \a PIFFT_float
template<typename T> template<typename T>
class PIFFTW { class PIFFTW {
public: public:
//! \~english Default constructor.
//! \~russian Конструктор по умолчанию.
explicit PIFFTW() { explicit PIFFTW() {
p = 0; p = 0;
newP(p); newP(p);
} }
//! \~english Destructor.
//! \~russian Деструктор.
~PIFFTW() { deleteP(p); } ~PIFFTW() { deleteP(p); }
//! \~english Calculate FFT from complex vector.
//! \~russian Вычисление БПФ из комплексного вектора.
inline const PIVector<complex<T>> & calcFFT(const PIVector<complex<T>> & in) { return PIVector<complex<T>>().resize(in.size()); } inline const PIVector<complex<T>> & calcFFT(const PIVector<complex<T>> & in) { return PIVector<complex<T>>().resize(in.size()); }
//! \~english Calculate FFT from real vector.
//! \~russian Вычисление БПФ из вещественного вектора.
inline const PIVector<complex<T>> & calcFFT(const PIVector<T> & in) { return PIVector<complex<T>>().resize(in.size()); } inline const PIVector<complex<T>> & calcFFT(const PIVector<T> & in) { return PIVector<complex<T>>().resize(in.size()); }
//! \~english Calculate inverse FFT.
//! \~russian Вычисление обратного БПФ.
inline const PIVector<complex<T>> & calcFFTinverse(const PIVector<complex<T>> & in) { return PIVector<complex<T>>().resize(in.size()); } inline const PIVector<complex<T>> & calcFFTinverse(const PIVector<complex<T>> & in) { return PIVector<complex<T>>().resize(in.size()); }
//! \~english FFT operation type.
//! \~russian Тип операции БПФ.
enum FFT_Operation { enum FFT_Operation {
foReal, foReal,
foComplex, foComplex,
foInverse foInverse
}; };
//! \~english Prepare computation plan.
//! \~russian Подготовить план вычислений.
inline void preparePlan(int size, FFT_Operation op) {} inline void preparePlan(int size, FFT_Operation op) {}
private: private:
@@ -297,7 +222,6 @@ private:
void * p; void * p;
}; };
//! \~\}
template<> template<>

View File

@@ -1,13 +1,21 @@
//! \addtogroup Math /*! \file pigeometry.h
//! \{ * \ingroup Math
//! \file pigeometry.h * \brief
//! \brief * \~english Geometry base classes
//! \~english Geometry utilities * \~russian Базовые геометрические классы
//! \~russian Геометрические утилиты * \~\details
//! \~\authors * \~english
//! \~english Ivan Pelipenko peri4ko@yandex.ru; Andrey Bychkov work.a.b@yandex.ru * Add \a PIPoint, \a PILine and \a PIRect classes.
//! \~russian Иван Пелипенко peri4ko@yandex.ru; Андрей Бычков work.a.b@yandex.ru * \~russian
//! \~\} * Содержит классы: \a PIPoint, \a PILine и \a PIRect.
* * \~\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 PIP - Platform Independent Primitives
Geometry base classes Geometry base classes

View File

@@ -21,10 +21,7 @@
You should have received a copy of the GNU Lesser General Public License 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/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
//! \~english OpenCL module
//! \~russian Модуль OpenCL
//! \defgroup OpenCL OpenCL //! \defgroup OpenCL OpenCL
//! \~\brief //! \~\brief
//! \~english OpenCL support //! \~english OpenCL support
@@ -66,41 +63,17 @@
class PIP_OPENCL_EXPORT PIOpenCL { class PIP_OPENCL_EXPORT PIOpenCL {
public: public:
//! \~english Kernel argument structure
//! \~russian Структура аргумента ядра
struct KernelArg; struct KernelArg;
//! \~english Device structure
//! \~russian Структура устройства
struct Device; struct Device;
//! \~english Platform structure
//! \~russian Структура платформы
struct Platform; struct Platform;
//! \~english OpenCL context class
//! \~russian Класс контекста OpenCL
class Context; class Context;
//! \~english OpenCL buffer class
//! \~russian Класс буфера OpenCL
class Buffer; class Buffer;
//! \~english OpenCL program class
//! \~russian Класс программы OpenCL
class Program; class Program;
//! \~english OpenCL kernel class
//! \~russian Класс ядра OpenCL
class Kernel; class Kernel;
//! \~english List of devices
//! \~russian Список устройств
typedef PIVector<Device> DeviceList; typedef PIVector<Device> DeviceList;
//! \~english Address space qualifiers
//! \~russian Квалификаторы адресного пространства
enum AddressQualifier { enum AddressQualifier {
AddressGlobal, AddressGlobal,
AddressLocal, AddressLocal,
@@ -108,8 +81,6 @@ public:
AddressPrivate, AddressPrivate,
}; };
//! \~english Access qualifiers
//! \~russian Квалификаторы доступа
enum AccessQualifier { enum AccessQualifier {
AccessReadOnly, AccessReadOnly,
AccessWriteOnly, AccessWriteOnly,
@@ -117,16 +88,12 @@ public:
AccessNone, AccessNone,
}; };
//! \~english Buffer direction
//! \~russian Направление буфера
enum Direction { enum Direction {
Input = 0x01, Input = 0x01,
Output = 0x02, Output = 0x02,
InputOutput = Input | Output, InputOutput = Input | Output,
}; };
//! \~english Type qualifiers
//! \~russian Квалификаторы типа
enum TypeQualifier { enum TypeQualifier {
TypeConst, TypeConst,
TypeRestrict, TypeRestrict,
@@ -134,8 +101,6 @@ public:
TypeNone, TypeNone,
}; };
//! \~english Argument types
//! \~russian Типы аргументов
enum ArgType { enum ArgType {
Char = 1, Char = 1,
UChar, UChar,
@@ -150,51 +115,17 @@ public:
}; };
//! \~english Kernel argument information
//! \~russian Информация об аргументе ядра
struct PIP_OPENCL_EXPORT KernelArg { struct PIP_OPENCL_EXPORT KernelArg {
//! \~english Default constructor
//! \~russian Конструктор по умолчанию
KernelArg(); KernelArg();
//! \~english Address qualifier
//! \~russian Квалификатор адреса
AddressQualifier address_qualifier; AddressQualifier address_qualifier;
//! \~english Access qualifier
//! \~russian Квалификатор доступа
AccessQualifier access_qualifier; AccessQualifier access_qualifier;
//! \~english Buffer direction
//! \~russian Направление буфера
Direction direction; Direction direction;
//! \~english Type qualifier
//! \~russian Квалификатор типа
TypeQualifier type_qualifier; TypeQualifier type_qualifier;
//! \~english Argument name
//! \~russian Имя аргумента
PIString arg_name; PIString arg_name;
//! \~english Type name
//! \~russian Имя типа
PIString type_name; PIString type_name;
//! \~english Base type name
//! \~russian Имя базового типа
PIString base_type_name; PIString base_type_name;
//! \~english Is pointer
//! \~russian Является указателем
bool is_pointer; bool is_pointer;
//! \~english Argument type
//! \~russian Тип аргумента
ArgType arg_type; ArgType arg_type;
//! \~english Dimensions
//! \~russian Размерности
int dims; int dims;
private: private:
@@ -203,180 +134,68 @@ public:
}; };
//! \~english OpenCL device information
//! \~russian Информация об устройстве OpenCL
struct PIP_OPENCL_EXPORT Device { struct PIP_OPENCL_EXPORT Device {
//! \~english Default constructor
//! \~russian Конструктор по умолчанию
Device() { Device() {
id = platform_id = 0; id = platform_id = 0;
max_compute_units = max_clock_frequency = 0; max_compute_units = max_clock_frequency = 0;
max_memory_size = 0; max_memory_size = 0;
} }
//! \~english Check if device is valid
//! \~russian Проверить устройство на корректность
bool isValid() const { return id != 0; } bool isValid() const { return id != 0; }
//! \~english Get display text
//! \~russian Получить текст для отображения
PIString displayText() const { return name.trimmed() + " (" + device_version.trimmed() + ")"; } PIString displayText() const { return name.trimmed() + " (" + device_version.trimmed() + ")"; }
//! \~english Device handle
//! \~russian Дескриптор устройства
void * id; void * id;
//! \~english Platform ID
//! \~russian ID платформы
void * platform_id; void * platform_id;
//! \~english Device name
//! \~russian Имя устройства
PIString name; PIString name;
//! \~english Vendor name
//! \~russian Имя производителя
PIString vendor; PIString vendor;
//! \~english Device version
//! \~russian Версия устройства
PIString device_version; PIString device_version;
//! \~english Driver version
//! \~russian Версия драйвера
PIString driver_version; PIString driver_version;
//! \~english Maximum compute units
//! \~russian Максимум вычислительных блоков
int max_compute_units; int max_compute_units;
//! \~english Maximum clock frequency
//! \~russian Максимальная тактовая частота
int max_clock_frequency; int max_clock_frequency;
//! \~english Maximum memory size
//! \~russian Максимальный размер памяти
ullong max_memory_size; ullong max_memory_size;
}; };
//! \~english OpenCL platform information
//! \~russian Информация о платформе OpenCL
struct PIP_OPENCL_EXPORT Platform { struct PIP_OPENCL_EXPORT Platform {
//! \~english Default constructor
//! \~russian Конструктор по умолчанию
Platform() { id = 0; } Platform() { id = 0; }
//! \~english Check if platform is valid
//! \~russian Проверить платформу на корректность
bool isValid() const { return id != 0; } bool isValid() const { return id != 0; }
//! \~english Get display text
//! \~russian Получить текст для отображения
PIString displayText() const { return name.trimmed() + " (" + version.trimmed() + ", " + profile.trimmed() + ")"; } PIString displayText() const { return name.trimmed() + " (" + version.trimmed() + ", " + profile.trimmed() + ")"; }
//! \~english Platform handle
//! \~russian Дескриптор платформы
void * id; void * id;
//! \~english Platform name
//! \~russian Имя платформы
PIString name; PIString name;
//! \~english Vendor name
//! \~russian Имя производителя
PIString vendor; PIString vendor;
//! \~english Profile
//! \~russian Профиль
PIString profile; PIString profile;
//! \~english Version
//! \~russian Версия
PIString version; PIString version;
//! \~english Extensions
//! \~russian Расширения
PIStringList extensions; PIStringList extensions;
//! \~english Available devices
//! \~russian Доступные устройства
PIVector<Device> devices; PIVector<Device> devices;
}; };
//! \~english OpenCL context for managing devices and resources
//! \~russian Контекст OpenCL для управления устройствами и ресурсами
class PIP_OPENCL_EXPORT Context { class PIP_OPENCL_EXPORT Context {
friend class Buffer; friend class Buffer;
friend class Program; friend class Program;
friend class Kernel; friend class Kernel;
public: public:
//! \~english Destructor
//! \~russian Деструктор
~Context(); ~Context();
//! \~english Get context handle
//! \~russian Получить дескриптор контекста
void * handle(); void * handle();
//! \~english Get command queue
//! \~russian Получить очередь команд
void * queue(); void * queue();
//! \~english Create context for device list
//! \~russian Создать контекст для списка устройств
//! \param dl List of devices
//! \return New context or nullptr
static Context * create(const DeviceList & dl); static Context * create(const DeviceList & dl);
//! \~english Create context for single device
//! \~russian Создать контекст для одного устройства
//! \param d Device
//! \return New context or nullptr
static Context * create(const Device & d) { return create(DeviceList() << d); } static Context * create(const Device & d) { return create(DeviceList() << d); }
//! \~english Create context by platform name
//! \~russian Создать контекст по имени платформы
//! \param part_name Platform name pattern
//! \return New context or nullptr
static Context * create(const PIString & part_name); static Context * create(const PIString & part_name);
//! \~english Create program from source
//! \~russian Создать программу из исходного кода
//! \param source OpenCL source code
//! \param args Build arguments
//! \param error Error message output
//! \return New program or nullptr
Program * createProgram(const PIString & source, const PIStringList & args = PIStringList(), PIString * error = 0); Program * createProgram(const PIString & source, const PIStringList & args = PIStringList(), PIString * error = 0);
//! \~english Create buffer from vector
//! \~russian Создать буфер из вектора
template<typename T> template<typename T>
Buffer * createBuffer(PIOpenCL::Direction dir, PIVector<T> & container) { Buffer * createBuffer(PIOpenCL::Direction dir, PIVector<T> & container) {
T def = T(); T def = T();
return createBuffer(dir, &container, Buffer::cVector, PIByteArray(&def, sizeof(T)), container.size()); return createBuffer(dir, &container, Buffer::cVector, PIByteArray(&def, sizeof(T)), container.size());
} }
//! \~english Create buffer from deque
//! \~russian Создать буфер из deque
template<typename T> template<typename T>
Buffer * createBuffer(PIOpenCL::Direction dir, PIDeque<T> & container) { Buffer * createBuffer(PIOpenCL::Direction dir, PIDeque<T> & container) {
T def = T(); T def = T();
return createBuffer(dir, &container, Buffer::cDeque, PIByteArray(&def, sizeof(T)), container.size()); return createBuffer(dir, &container, Buffer::cDeque, PIByteArray(&def, sizeof(T)), container.size());
} }
//! \~english Create buffer from 2D vector
//! \~russian Создать буфер из 2D вектора
template<typename T> template<typename T>
Buffer * createBuffer(PIOpenCL::Direction dir, PIVector2D<T> & container) { Buffer * createBuffer(PIOpenCL::Direction dir, PIVector2D<T> & container) {
T def = T(); T def = T();
return createBuffer(dir, &container, Buffer::cVector2D, PIByteArray(&def, sizeof(T)), container.size()); return createBuffer(dir, &container, Buffer::cVector2D, PIByteArray(&def, sizeof(T)), container.size());
} }
//! \~english Create buffer for elements
//! \~russian Создать буфер для элементов
template<typename T> template<typename T>
Buffer * createBuffer(PIOpenCL::Direction dir, uint elements) { Buffer * createBuffer(PIOpenCL::Direction dir, uint elements) {
T def = T(); T def = T();
@@ -397,70 +216,26 @@ public:
}; };
//! \~english OpenCL buffer for data storage
//! \~russian Буфер OpenCL для хранения данных
class PIP_OPENCL_EXPORT Buffer { class PIP_OPENCL_EXPORT Buffer {
friend class Context; friend class Context;
friend class Kernel; friend class Kernel;
public: public:
//! \~english Destructor
//! \~russian Деструктор
~Buffer(); ~Buffer();
//! \~english Get buffer handle
//! \~russian Получить дескриптор буфера
void * handle(); void * handle();
//! \~english Resize buffer
//! \~russian Изменить размер буфера
//! \param new_elements New number of elements
//! \return true if successful
bool resize(uint new_elements); bool resize(uint new_elements);
//! \~english Clear buffer
//! \~russian Очистить буфер
void clear(); void clear();
//! \~english Copy to container
//! \~russian Копировать в контейнер
void copyToContainer(); void copyToContainer();
//! \~english Copy to memory
//! \~russian Копировать в память
void copyTo(void * data); void copyTo(void * data);
//! \~english Copy to memory with offset
//! \~russian Копировать в память со смещением
void copyTo(void * data, int elements_count, int elements_offset = 0); void copyTo(void * data, int elements_count, int elements_offset = 0);
//! \~english Copy to another buffer
//! \~russian Копировать в другой буфер
void copyTo(Buffer * buffer, int elements_count = -1, int elements_from_offset = 0, int elements_to_offset = 0); void copyTo(Buffer * buffer, int elements_count = -1, int elements_from_offset = 0, int elements_to_offset = 0);
//! \~english Copy from container
//! \~russian Копировать из контейнера
void copyFromContainer(); void copyFromContainer();
//! \~english Copy from memory
//! \~russian Копировать из памяти
void copyFrom(void * data); void copyFrom(void * data);
//! \~english Copy from memory with offset
//! \~russian Копировать из памяти со смещением
void copyFrom(void * data, int elements_count, int elements_offset = 0); void copyFrom(void * data, int elements_count, int elements_offset = 0);
//! \~english Copy from another buffer
//! \~russian Копировать из другого буфера
void copyFrom(Buffer * buffer, int elements_count = -1, int elements_from_offset = 0, int elements_to_offset = 0); void copyFrom(Buffer * buffer, int elements_count = -1, int elements_from_offset = 0, int elements_to_offset = 0);
//! \~english Get elements count
//! \~russian Получить количество элементов
uint elementsCount() const { return elements; } uint elementsCount() const { return elements; }
private: private:
//! \~english Container types
//! \~russian Типы контейнеров
enum Container { enum Container {
cNone, cNone,
cVector, cVector,
@@ -482,32 +257,16 @@ public:
}; };
//! \~english OpenCL program containing kernels
//! \~russian Программа OpenCL содержащая ядра
class PIP_OPENCL_EXPORT Program { class PIP_OPENCL_EXPORT Program {
friend class Context; friend class Context;
friend class Kernel; friend class Kernel;
friend class Buffer; friend class Buffer;
public: public:
//! \~english Destructor
//! \~russian Деструктор
~Program(); ~Program();
//! \~english Get context
//! \~russian Получить контекст
Context * context() const { return context_; } Context * context() const { return context_; }
//! \~english Get source code
//! \~russian Получить исходный код
const PIString & sourceCode() const { return source_; } const PIString & sourceCode() const { return source_; }
//! \~english Get kernel by index
//! \~russian Получить ядро по индексу
Kernel * kernel(int index = 0) const { return kernels_[index]; } Kernel * kernel(int index = 0) const { return kernels_[index]; }
//! \~english Get all kernels
//! \~russian Получить все ядра
const PIVector<Kernel *> & kernels() const { return kernels_; } const PIVector<Kernel *> & kernels() const { return kernels_; }
private: private:
@@ -521,68 +280,28 @@ public:
}; };
//! \~english OpenCL kernel for execution
//! \~russian Ядро OpenCL для выполнения
class PIP_OPENCL_EXPORT Kernel { class PIP_OPENCL_EXPORT Kernel {
friend class Program; friend class Program;
friend class Buffer; friend class Buffer;
public: public:
//! \~english Get parent program
//! \~russian Получить родительскую программу
Program * program() const { return program_; } Program * program() const { return program_; }
//! \~english Execute kernel
//! \~russian Выполнить ядро
//! \return true if successful
bool execute(); bool execute();
//! \~english Wait for execution to finish
//! \~russian Ждать завершения выполнения
void waitForFinish(); void waitForFinish();
//! \~english Set execution range (1D)
//! \~russian Установить диапазон выполнения (1D)
//! \param size Number of work items
void setExecuteRange(int size) { setExecuteRanges(PIVector<int>() << size); } void setExecuteRange(int size) { setExecuteRanges(PIVector<int>() << size); }
//! \~english Set execution ranges (ND)
//! \~russian Установить диапазоны выполнения (ND)
//! \param ranges Array of sizes per dimension
void setExecuteRanges(const PIVector<int> & ranges); void setExecuteRanges(const PIVector<int> & ranges);
//! \~english Get kernel name
//! \~russian Получить имя ядра
const PIString & name() const { return name_; } const PIString & name() const { return name_; }
//! \~english Get kernel arguments
//! \~russian Получить аргументы ядра
const PIVector<KernelArg> & args() const { return args_; } const PIVector<KernelArg> & args() const { return args_; }
//! \~english Set argument value by index
//! \~russian Установить значение аргумента по индексу
template<typename T> template<typename T>
bool setArgValue(int index, const T & value) { bool setArgValue(int index, const T & value) {
return setArgValueS(index, PIVariant::fromValue(value)); return setArgValueS(index, PIVariant::fromValue(value));
} }
//! \~english Set argument value by name
//! \~russian Установить значение аргумента по имени
template<typename T> template<typename T>
bool setArgValue(const PIString & arg, const T & value) { bool setArgValue(const PIString & arg, const T & value) {
return setArgValue(argIndex(arg), value); return setArgValue(argIndex(arg), value);
} }
//! \~english Set variant argument value
//! \~russian Установить значение аргумента variant
bool setArgValue(const PIString & arg, const PIVariant & value) { return setArgValueS(argIndex(arg), value); } bool setArgValue(const PIString & arg, const PIVariant & value) { return setArgValueS(argIndex(arg), value); }
//! \~english Bind buffer to argument
//! \~russian Привязать буфер к аргументу
bool bindArgValue(int index, Buffer * buffer); bool bindArgValue(int index, Buffer * buffer);
//! \~english Bind buffer to argument by name
//! \~russian Привязать буфер к аргументу по имени
bool bindArgValue(const PIString & arg, Buffer * buffer) { return bindArgValue(argIndex(arg), buffer); } bool bindArgValue(const PIString & arg, Buffer * buffer) { return bindArgValue(argIndex(arg), buffer); }
private: private:
@@ -602,37 +321,15 @@ public:
}; };
//! \~english Initialize OpenCL
//! \~russian Инициализировать OpenCL
static void init(); static void init();
//! \~english Get available platforms
//! \~russian Получить доступные платформы
//! \return Vector of platforms
static const PIVector<Platform> & platforms(); static const PIVector<Platform> & platforms();
//! \~english Get all available devices
//! \~russian Получить все доступные устройства
//! \return Vector of devices
static const PIVector<Device> devices(); static const PIVector<Device> devices();
//! \~english Get device by ID
//! \~russian Получить устройство по ID
//! \param id Device handle
//! \return Device info
static Device deviceByID(void * id); static Device deviceByID(void * id);
//! \~english Prepare program source
//! \~russian Подготовить исходный код программы
//! \param prog Program source
//! \return Prepared source
static PIString prepareProgram(const PIString & prog); static PIString prepareProgram(const PIString & prog);
private: private:
static PIString prog_header; static PIString prog_header;
PIOpenCL() { ; } PIOpenCL() { ; }
//! \~english Initialization helper
//! \~russian Помощник инициализации
class PIP_OPENCL_EXPORT Initializer { class PIP_OPENCL_EXPORT Initializer {
public: public:
Initializer(); Initializer();
@@ -644,8 +341,6 @@ private:
}; };
//! \~english Output stream operator for KernelArg
//! \~russian Оператор вывода в поток для KernelArg
PIP_OPENCL_EXPORT PICout operator<<(PICout s, const PIOpenCL::KernelArg & v); PIP_OPENCL_EXPORT PICout operator<<(PICout s, const PIOpenCL::KernelArg & v);

View File

@@ -17,40 +17,6 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
//! \~english PIP - Platform Independent Primitives
//! \~russian PIP - Кроссплатформенные примитивы
//! \mainpage
//!
//! \~\brief
//! \~english Main include file for PIP library
//! \~russian Главный включаемый файл библиотеки PIP
//!
//! \~\details
//! \~english \section overview Overview
//! \~russian \section overview Обзор
//!
//! \~english
//! PIP is a C++ cross-platform library providing platform-independent abstractions for:
//! * Core/Types: Strings, variants, containers, datetime, networks
//! * Threading: Mutexes, semaphores, thread pools, timers
//! * I/O: Files, serial, CAN, GPIO, SPI, Ethernet
//! * Math: Vectors, matrices, FFT, quaternions
//! * Crypto: MD5, SHA, BLAKE2, SipHash
//! * Compression: zlib support
//! * HTTP: Client and server support
//! * Serialization: JSON, binary, XML
//!
//! \~russian
//! PIP - это кроссплатформенная C++ библиотека, предоставляющая платформонезависимые абстракции для:
//! * Ядро/Типы: Строки, варианты, контейнеры, дата/время, сети
//! * Потоки: Мьютексы, семафоры, пулы потоков, таймеры
//! * Ввод/Вывод: Файлы, последовательные порты, CAN, GPIO, SPI, Ethernet
//! * Математика: Векторы, матрицы, FFT, кватернионы
//! * Криптография: MD5, SHA, BLAKE2, SipHash
//! * Сжатие: Поддержка zlib
//! * HTTP: Клиент и сервер
//! * Сериализация: JSON, бинарная, XML
#ifndef PIP_H #ifndef PIP_H
#define PIP_H #define PIP_H

View File

@@ -22,15 +22,12 @@
You should have received a copy of the GNU Lesser General Public License 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/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
//! \~english Resources subsystem
//! \~russian Подсистема ресурсов
//! \defgroup Resources Resources //! \defgroup Resources Resources
//! \~\brief //! \~\brief
//! \~english Resources subsystem //! \~english Resources subsystem
//! \~russian Подсистема ресурсов //! \~russian Подсистема ресурсов
//! //!
//! \~\details //! \~\details
//! \~
//! \~english \section cmake_module_Resources Building with CMake //! \~english \section cmake_module_Resources Building with CMake
//! \~russian \section cmake_module_Resources Сборка с использованием CMake //! \~russian \section cmake_module_Resources Сборка с использованием CMake
//! //!
@@ -62,31 +59,18 @@
#include "pistring.h" #include "pistring.h"
//! \~english Macro for initializing compiled-in resources #define INIT_RESOURCE(name) \
//! \~russian Макрос для инициализации вкомпиленных ресурсов { \
#define INIT_RESOURCE(name) \ extern void _pirc_##name##_init_(); \
{ \ _pirc_##name##_init_(); \
extern void _pirc_##name##_init_(); \ }
_pirc_##name##_init_(); \
}
//! \~english Class for accessing compiled-in resources
//! \~russian Класс для доступа к вкомпиленным ресурсам
class PIP_EXPORT PIResources { class PIP_EXPORT PIResources {
public: public:
//! \~english Get resource by section and name //!
//! \~russian Получить ресурс по секции и имени
//! \details
//! \~english Searches for resource in specified section
//! \~russian Ищет ресурс в указанной секции
static PIByteArray get(const PIString & section, const PIString & name); static PIByteArray get(const PIString & section, const PIString & name);
//! \~english Get resource by name (searches all sections)
//! \~russian Получить ресурс по имени (ищет во всех секциях)
static PIByteArray get(const PIString & name); static PIByteArray get(const PIString & name);
//! \~english Dump all resources to console
//! \~russian Вывести все ресурсы в консоль
static void dump(); static void dump();
private: private:

View File

@@ -17,13 +17,6 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
//! \~english Resources storage subsystem
//! \~russian Подсистема хранения ресурсов
//! \defgroup Resources Resources
//! \~\brief
//! \~english Resources storage subsystem
//! \~russian Подсистема хранения ресурсов
#ifndef PIRESOURCES_P_H #ifndef PIRESOURCES_P_H
#define PIRESOURCES_P_H #define PIRESOURCES_P_H
@@ -33,36 +26,17 @@
class PIResources; class PIResources;
//! \~english Storage for compiled-in resources
//! \~russian Хранилище вкомпиленных ресурсов
class PIP_EXPORT PIResourcesStorage { class PIP_EXPORT PIResourcesStorage {
friend class PIResources; friend class PIResources;
public: public:
//! \~english Get singleton instance
//! \~russian Получить синглтон
static PIResourcesStorage * instance(); static PIResourcesStorage * instance();
//! \~english Section containing resource entries
//! \~russian Секция, содержащая записи ресурсов
struct PIP_EXPORT Section { struct PIP_EXPORT Section {
//! \~english Constructor
//! \~russian Конструктор
Section(); Section();
//! \~english Destructor
//! \~russian Деструктор
~Section(); ~Section();
//! \~english Add another section to this one
//! \~russian Добавить другую секцию к этой
void add(const Section & s); void add(const Section & s);
//! \~english Clear all entries
//! \~russian Очистить все записи
void purge(); void purge();
//! \~english Map of resource names to data
//! \~russian Карта имен ресурсов к данным
PIMap<PIString, PIByteArray *> entries; PIMap<PIString, PIByteArray *> entries;
}; };
@@ -82,65 +56,21 @@ public:
size = si; size = si;
flags = fl; flags = fl;
} }
//! \~english Section name
//! \~russian Имя секции
PIString section; PIString section;
//! \~english Resource name
//! \~russian Имя ресурса
PIString name; PIString name;
//! \~english Alias
//! \~russian Псевдоним
PIString alias; PIString alias;
//! \~english Source file
//! \~russian Исходный файл
PIString file; PIString file;
//! \~english Offset in file
//! \~russian Смещение в файле
llong offset; llong offset;
//! \~english Size
//! \~russian Размер
llong size; llong size;
//! \~english Flags
//! \~russian Флаги
int flags; int flags;
}; };
//! \~english Register a section with data
//! \~russian Зарегистрировать секцию с данными
//! \param section_name Name of the section
//! \param data Section data
void registerSection(const PIString & section_name, const Section & data); void registerSection(const PIString & section_name, const Section & data);
//! \~english Register from raw data
//! \~russian Зарегистрировать из сырых данных
//! \param rc_data Resource data
//! \param rc_desc Resource description
//! \param rc_desc_size Description size
void registerSection(const uchar * rc_data, const uchar * rc_desc, int rc_desc_size); void registerSection(const uchar * rc_data, const uchar * rc_desc, int rc_desc_size);
//! \~english Get section by name
//! \~russian Получить секцию по имени
//! \param section_name Name of section
//! \return Pointer to section or nullptr
Section * section(const PIString & section_name) const; Section * section(const PIString & section_name) const;
//! \~english Get resource by section and name
//! \~russian Получить ресурс по секции и имени
PIByteArray get(const PIString & section_name, const PIString & entry_name) const; PIByteArray get(const PIString & section_name, const PIString & entry_name) const;
//! \~english Get resource by name (searches all sections)
//! \~russian Получить ресурс по имени (ищет во всех секциях)
PIByteArray get(const PIString & entry_name) const; PIByteArray get(const PIString & entry_name) const;
//! \~english Clear all sections
//! \~russian Очистить все секции
void clear(); void clear();
private: private:

View File

@@ -31,16 +31,12 @@
namespace PIStateMachineHelpers { namespace PIStateMachineHelpers {
//! \~english Base class for function wrappers
//! \~russian Базовый класс для обёрток функций
class FunctionBase { class FunctionBase {
public: public:
virtual ~FunctionBase() {} virtual ~FunctionBase() {}
virtual uint formatHash() = 0; virtual uint formatHash() = 0;
}; };
//! \~english Template class for function wrappers
//! \~russian Шаблонный класс для обёрток функций
template<typename... Args> template<typename... Args>
class Function: public FunctionBase { class Function: public FunctionBase {
public: public:
@@ -51,8 +47,6 @@ public:
std::function<bool(Args...)> func; std::function<bool(Args...)> func;
}; };
//! \~english Creates function wrapper from std::function
//! \~russian Создает обёртку функции из std::function
template<typename Ret, typename... Args> template<typename Ret, typename... Args>
FunctionBase * makeFunction(std::function<Ret(Args...)> func) { FunctionBase * makeFunction(std::function<Ret(Args...)> func) {
auto * ret = new Function<Args...>(); auto * ret = new Function<Args...>();

View File

@@ -31,117 +31,50 @@
#include "pisystemtime.h" #include "pisystemtime.h"
//! \~english Base class for state machine states //! \ingroup StateMachine
//! \~russian Базовый класс для состояний машины состояний //! \~\brief
//! \~english
//! \~russian
class PIP_EXPORT PIStateBase { class PIP_EXPORT PIStateBase {
friend class PIStateMachine; friend class PIStateMachine;
friend class PITransitionBase; friend class PITransitionBase;
friend class PIStateFinal; friend class PIStateFinal;
public: public:
//! \~english Creates state with name
//! \~russian Создает состояние с именем
PIStateBase(const PIString & n = {}): name_(n) { ; } PIStateBase(const PIString & n = {}): name_(n) { ; }
virtual ~PIStateBase(); virtual ~PIStateBase();
//! \~english Called when state is \~russian Вы entered
//! зывается при входе в состояние
virtual void onEnter() {} virtual void onEnter() {}
//! \~english Called when state is exited
//! \~russian Вызывается при выходе из состояния
virtual void onExit() {} virtual void onExit() {}
//! \~english Called when state machine finishes (for final states)
//! \~russian Вызывается при завершении машины состояний (для финальных состояний)
virtual void onFinish() {} virtual void onFinish() {}
//! \~english Returns state machine this state belongs to
//! \~russian Возвращает машину состояний, которой принадлежит это состояние
PIStateMachine * machine() const { return root; } PIStateMachine * machine() const { return root; }
//! \~english Returns parent state
//! \~russian Возвращает родительское состояние
PIStateBase * parent() const { return parent_state; } PIStateBase * parent() const { return parent_state; }
//! \~english Returns active child state
//! \~russian Возвращает активное дочернее состояние
PIStateBase * activeChild() const { return active_state; } PIStateBase * activeChild() const { return active_state; }
//! \~english Returns all active child states
//! \~russian Возвращает все активные дочерние состояния
PIVector<PIStateBase *> activeChildren() const; PIVector<PIStateBase *> activeChildren() const;
//! \~english Returns all active atomic states
//! \~russian Возвращает все активные атомарные состояния
PIVector<PIStateBase *> activeAtomics() const; PIVector<PIStateBase *> activeAtomics() const;
//! \~english Adds child state
//! \~russian Добавляет дочернее состояние
void addState(PIStateBase * s); void addState(PIStateBase * s);
//! \~english Adds multiple child states
//! \~russian Добавляет несколько дочерних состояний
void addStates(PIVector<PIStateBase *> s); void addStates(PIVector<PIStateBase *> s);
//! \~english Sets initial state for compound state
//! \~russian Устанавливает начальное состояние для составного состояния
void setInitialState(PIStateBase * s); void setInitialState(PIStateBase * s);
//! \~english Adds transition to target state on event
//! \~russian Добавляет переход к целевому состоянию по событию
PITransitionBase * addTransition(PIStateBase * target, int event_id); PITransitionBase * addTransition(PIStateBase * target, int event_id);
//! \~english Adds timeout transition to target state
//! \~russian Добавляет переход по таймауту к целевому состоянию
PITransitionTimeout * addTimeoutTransition(PIStateBase * target, PISystemTime timeout); PITransitionTimeout * addTimeoutTransition(PIStateBase * target, PISystemTime timeout);
//! \~english Sets parallel mode for state
//! \~russian Устанавливает параллельный режим для состояния
void setParallel(bool yes) { is_parallel = yes; } void setParallel(bool yes) { is_parallel = yes; }
//! \~english Returns state name
//! \~russian Возвращает имя состояния
const PIString & getName() const { return name_; } const PIString & getName() const { return name_; }
//! \~english Checks if this is root state machine
//! \~russian Проверяет является ли это корневой машиной состояний
bool isStateMachine() const { return is_root; } bool isStateMachine() const { return is_root; }
//! \~english Checks if state is active
//! \~russian Проверяет активно ли состояние
bool isActive() const { return is_active; } bool isActive() const { return is_active; }
//! \~english Checks if state is in parallel mode
//! \~russian Проверяет находится ли состояние в параллельном режиме
bool isParallel() const { return is_parallel; } bool isParallel() const { return is_parallel; }
//! \~english Checks if state is final
//! \~russian Проверяет является ли состояние финальным
bool isFinal() const { return is_final; } bool isFinal() const { return is_final; }
//! \~english Checks if state is atomic (no children)
//! \~russian Проверяет является ли состояние атомарным (нет потомков)
bool isAtomic() const { return children.isEmpty(); } bool isAtomic() const { return children.isEmpty(); }
//! \~english Checks if state is compound (has children)
//! \~russian Проверяет является ли состояние составным (есть потомки)
bool isCompound() const { return children.isNotEmpty(); } bool isCompound() const { return children.isNotEmpty(); }
//! \~english Returns child states
//! \~russian Возвращает дочерние состояния
const PIVector<PIStateBase *> & getChildren() const { return children; } const PIVector<PIStateBase *> & getChildren() const { return children; }
//! \~english Returns transitions from this state
//! \~russian Возвращает переходы из этого состояния
const PIVector<PITransitionBase *> & getTransitions() const { return transitions; } const PIVector<PITransitionBase *> & getTransitions() const { return transitions; }
//! \~english Prints state tree to string
//! \~russian Выводит дерево состояний в строку
void print(PIString prefix = {}); void print(PIString prefix = {});
//! \~english Returns all states in machine
//! \~russian Возвращает все состояния в машине
PIVector<PIStateBase *> gatherStates(); PIVector<PIStateBase *> gatherStates();
private: private:
@@ -167,12 +100,8 @@ private:
}; };
//! \~english State with lambda callbacks
//! \~russian Состояние с lambda коллбэками
class PIP_EXPORT PIStateLambda: public PIStateBase { class PIP_EXPORT PIStateLambda: public PIStateBase {
public: public:
//! \~english Creates lambda state with callbacks
//! \~russian Создает lambda состояние с коллбэками
PIStateLambda(std::function<void()> on_enter, std::function<void()> on_exit = nullptr, const PIString & n = {}): PIStateBase(n) { PIStateLambda(std::function<void()> on_enter, std::function<void()> on_exit = nullptr, const PIString & n = {}): PIStateBase(n) {
enter = on_enter; enter = on_enter;
exit = on_exit; exit = on_exit;
@@ -189,12 +118,8 @@ private:
}; };
//! \~english Final state of state machine
//! \~russian Финальное состояние машины состояний
class PIP_EXPORT PIStateFinal: public PIStateBase { class PIP_EXPORT PIStateFinal: public PIStateBase {
public: public:
//! \~english Creates final state with finish callback
//! \~russian Создает финальное состояние с коллбэком завершения
PIStateFinal(std::function<void()> on_finish = nullptr, const PIString & n = {}): PIStateBase(n) { PIStateFinal(std::function<void()> on_finish = nullptr, const PIString & n = {}): PIStateBase(n) {
is_final = true; is_final = true;
enter = on_finish; enter = on_finish;

View File

@@ -30,32 +30,22 @@
#include "pitimer.h" #include "pitimer.h"
//! \~english Base class for state machine transitions //! \ingroup StateMachine
//! \~russian Базовый класс для переходов машины состояний //! \~\brief
//! \~english
//! \~russian
class PIP_EXPORT PITransitionBase { class PIP_EXPORT PITransitionBase {
friend class PIStateMachine; friend class PIStateMachine;
friend class PIStateBase; friend class PIStateBase;
public: public:
//! \~english Creates transition from source to target on event
//! \~russian Создает переход от source к target по событию
PITransitionBase(PIStateBase * source, PIStateBase * target, int event_id); PITransitionBase(PIStateBase * source, PIStateBase * target, int event_id);
virtual ~PITransitionBase(); virtual ~PITransitionBase();
//! \~english Returns state machine this transition belongs to
//! \~russian Возвращает машину состояний, которой принадлежит этот переход
PIStateMachine * machine() const { return root; } PIStateMachine * machine() const { return root; }
//! \~english Returns source state
//! \~russian Возвращает исходное состояние
PIStateBase * source() const { return source_state; } PIStateBase * source() const { return source_state; }
//! \~english Returns target state
//! \~russian Возвращает целевое состояние
PIStateBase * target() const { return target_state; } PIStateBase * target() const { return target_state; }
//! \~english Adds guard function to transition
//! \~russian Добавляет сторожевую функцию к переходу
template<typename R, typename... Args> template<typename R, typename... Args>
PITransitionBase * addGuard(std::function<R(Args...)> f) { PITransitionBase * addGuard(std::function<R(Args...)> f) {
static_assert(std::is_same<R, bool>::value, "guard function should return bool!"); static_assert(std::is_same<R, bool>::value, "guard function should return bool!");
@@ -64,15 +54,11 @@ public:
return this; return this;
} }
//! \~english Adds guard function to transition (callable)
//! \~russian Добавляет сторожевую функцию к переходу (callable)
template<typename L> template<typename L>
PITransitionBase * addGuard(L f) { PITransitionBase * addGuard(L f) {
return addGuard(toStdFunction(f)); return addGuard(toStdFunction(f));
} }
//! \~english Tests guard function with arguments
//! \~russian Тестирует сторожевую функцию с аргументами
template<typename... Args> template<typename... Args>
bool testGuard(Args... args) { bool testGuard(Args... args) {
if (!guard) return true; if (!guard) return true;
@@ -83,25 +69,13 @@ public:
return reinterpret_cast<PIStateMachineHelpers::Function<Args...> *>(guard)->func(args...); return reinterpret_cast<PIStateMachineHelpers::Function<Args...> *>(guard)->func(args...);
} }
//! \~english Adds action to transition
//! \~russian Добавляет действие к переходу
PITransitionBase * addAction(std::function<void()> a); PITransitionBase * addAction(std::function<void()> a);
//! \~english Executes transition action
//! \~russian Выполняет действие перехода
void makeAction(); void makeAction();
//! \~english Triggers transition
//! \~russian Запускает переход
void trigger(); void trigger();
protected: protected:
//! \~english Called when transition becomes enabled
//! \~russian Вызывается когда переход становится доступным
virtual void enabled() {} virtual void enabled() {}
//! \~english Called when transition becomes disabled
//! \~russian Вызывается когда переход становится недоступным
virtual void disabled() {} virtual void disabled() {}
int eventID = 0; int eventID = 0;
@@ -112,12 +86,8 @@ protected:
}; };
//! \~english Timeout transition
//! \~russian Переход по таймауту
class PIP_EXPORT PITransitionTimeout: public PITransitionBase { class PIP_EXPORT PITransitionTimeout: public PITransitionBase {
public: public:
//! \~english Creates timeout transition
//! \~russian Создает переход по таймауту
PITransitionTimeout(PIStateBase * source, PIStateBase * target, PISystemTime timeout); PITransitionTimeout(PIStateBase * source, PIStateBase * target, PISystemTime timeout);
~PITransitionTimeout(); ~PITransitionTimeout();

View File

@@ -342,12 +342,12 @@ PIVector<PIHIDeviceInfo> PIHIDevice::allDevices(bool try_open) {
PIDir hid_dir("/sys/bus/hid/devices"_a); PIDir hid_dir("/sys/bus/hid/devices"_a);
auto hid_devs = hid_dir.entries(); auto hid_devs = hid_dir.entries();
for (auto hd: hid_devs) { for (const auto & hd: hid_devs) {
// piCout << d.path; // piCout << d.path;
if (!isDir(hd)) continue; if (!isDir(hd)) continue;
PIDir dir_input(hd.path + "/input"_a); PIDir dir_input(hd.path + "/input"_a);
auto hid_inputs = dir_input.entries(); auto hid_inputs = dir_input.entries();
for (auto hd_i: hid_inputs) { for (const auto & hd_i: hid_inputs) {
if (!isDir(hd_i)) continue; if (!isDir(hd_i)) continue;
// now in /sys/bus/hid/devices/<dev>/input/input<N> // now in /sys/bus/hid/devices/<dev>/input/input<N>
// piCout << hd_i.path; // piCout << hd_i.path;
@@ -364,7 +364,7 @@ PIVector<PIHIDeviceInfo> PIHIDevice::allDevices(bool try_open) {
PIDir dir_e(hd_i.path); PIDir dir_e(hd_i.path);
PIStringList devs; PIStringList devs;
auto dl_e = dir_e.entries(); auto dl_e = dir_e.entries();
for (auto d_e: dl_e) { for (const auto & d_e: dl_e) {
if (!d_e.isDir() || d_e.flags[PIFile::FileInfo::Dot] || d_e.flags[PIFile::FileInfo::DotDot]) continue; if (!d_e.isDir() || d_e.flags[PIFile::FileInfo::Dot] || d_e.flags[PIFile::FileInfo::DotDot]) continue;
devs << d_e.name(); devs << d_e.name();
} }
@@ -392,7 +392,7 @@ PIVector<PIHIDeviceInfo> PIHIDevice::allDevices(bool try_open) {
if (test_f.isClosed()) continue; if (test_f.isClosed()) continue;
} }
ullong ev = readFile(hd_i.path + "/capabilities/ev"_a).toULLong(16); // ullong ev = readFile(hd_i.path + "/capabilities/ev"_a).toULLong(16);
auto readAxes = [readFile, checkBit, &hd_i, &dev](const PIString & file, bool is_relative) { auto readAxes = [readFile, checkBit, &hd_i, &dev](const PIString & file, bool is_relative) {
PIVector<PIHIDeviceInfo::AxisInfo> ret; PIVector<PIHIDeviceInfo::AxisInfo> ret;

View File

@@ -29,98 +29,37 @@
#include "pithread.h" #include "pithread.h"
//! \~english HID device information
//! \~russian Информация об HID устройстве
struct PIP_EXPORT PIHIDeviceInfo { struct PIP_EXPORT PIHIDeviceInfo {
friend class PIHIDevice; friend class PIHIDevice;
//! \~english Base class for value info
//! \~russian Базовый класс для информации о значении
struct PIP_EXPORT ValueInfoBase { struct PIP_EXPORT ValueInfoBase {
//! \~english Checks if info is valid
//! \~russian Проверяет валидна ли информация
bool isValid() const { return index >= 0; } bool isValid() const { return index >= 0; }
int index = -1; int index = -1;
int data_index = -1; int data_index = -1;
}; };
//! \~english Axis information
//! \~russian Информация об оси
struct PIP_EXPORT AxisInfo: public ValueInfoBase { struct PIP_EXPORT AxisInfo: public ValueInfoBase {
int bits = 0; int bits = 0;
int min = 0; int min = 0;
int max = 1; int max = 1;
bool is_relative = false; bool is_relative = false;
}; };
//! \~english Button information
//! \~russian Информация о кнопке
struct PIP_EXPORT ButtonInfo: public ValueInfoBase { struct PIP_EXPORT ButtonInfo: public ValueInfoBase {
int code = 0; int code = 0;
}; };
//! \~english Device path
//! \~russian Путь к устройству
PIString path; PIString path;
//! \~english Manufacturer name
//! \~russian Имя производителя
PIString manufacturer; PIString manufacturer;
//! \~english Product name
//! \~russian Название продукта
PIString product; PIString product;
//! \~english Serial number
//! \~russian Серийный номер
PIString serial; PIString serial;
//! \~english Version
//! \~russian Версия
PIString version; PIString version;
//! \~english Vendor ID
//! \~russian Идентификатор производителя
PIString VID; PIString VID;
//! \~english Product ID
//! \~russian Идентификатор продукта
PIString PID; PIString PID;
//! \~english List of axes
//! \~russian Список осей
PIVector<AxisInfo> axes; PIVector<AxisInfo> axes;
//! \~english List of buttons
//! \~russian Список кнопок
PIVector<ButtonInfo> buttons; PIVector<ButtonInfo> buttons;
//! \~english Checks if info is null
//! \~russian Проверяет является ли информация пустой
bool isNull() const { return path.isEmpty(); } bool isNull() const { return path.isEmpty(); }
//! \~english Checks if info is not null
//! \~russian Проверяет является ли информация не пустой
bool isNotNull() const { return !isNull(); } bool isNotNull() const { return !isNull(); }
//! \~english Matches device by string
//! \~russian Сопоставляет устройство по строке
bool match(const PIString & str) const; bool match(const PIString & str) const;
//! \~english Returns axes count
//! \~russian Возвращает количество осей
int axesCount() const { return axes.size_s(); } int axesCount() const { return axes.size_s(); }
//! \~english Returns absolute axes count
//! \~russian Возвращает количество абсолютных осей
int axesAbsoluteCount() const; int axesAbsoluteCount() const;
//! \~english Returns relative axes count
//! \~russian Возвращает количество относительных осей
int axesRelativeCount() const; int axesRelativeCount() const;
//! \~english Returns buttons count
//! \~russian Возвращает количество кнопок
int buttonsCount() const { return buttons.size_s(); } int buttonsCount() const { return buttons.size_s(); }
private: private:
@@ -135,19 +74,13 @@ private:
PIP_EXPORT PICout operator<<(PICout s, const PIHIDeviceInfo & v); PIP_EXPORT PICout operator<<(PICout s, const PIHIDeviceInfo & v);
//! \~english HID device
//! \~russian HID устройство
class PIP_EXPORT PIHIDevice: public PIThread { class PIP_EXPORT PIHIDevice: public PIThread {
PIOBJECT_SUBCLASS(PIHIDevice, PIThread) PIOBJECT_SUBCLASS(PIHIDevice, PIThread)
public: public:
~PIHIDevice(); ~PIHIDevice();
//! \~english HID event
//! \~russian Событие HID
struct PIP_EXPORT Event { struct PIP_EXPORT Event {
//! \~english Event type
//! \~russian Тип события
enum Type { enum Type {
tNone, tNone,
tButton, tButton,
@@ -159,48 +92,19 @@ public:
float value = 0.; float value = 0.;
}; };
//! \~english Checks if device is opened
//! \~russian Проверяет открыто ли устройство
bool isOpened() const; bool isOpened() const;
//! \~english Opens device by info
//! \~russian Открывает устройство по информации
bool open(const PIHIDeviceInfo & device); bool open(const PIHIDeviceInfo & device);
//! \~english Opens device
//! \~russian Открывает устройство
bool open(); bool open();
//! \~english Closes device
//! \~russian Закрывает устройство
void close(); void close();
//! \~english Starts reading device
//! \~russian Начинает чтение устройства
void start(); void start();
//! \~english Stops reading device
//! \~russian Останавливает чтение устройства
void stop(); void stop();
//! \~english Sets dead zone for axes
//! \~russian Устанавливает мёртвую зону для осей
void setDeadZone(float v) { dead_zone = v; } void setDeadZone(float v) { dead_zone = v; }
//! \~english Returns dead zone
//! \~russian Возвращает мёртвую зону
float deadZone() const { return dead_zone; } float deadZone() const { return dead_zone; }
//! \~english Event fired on device event
//! \~russian Событие при событии устройства
EVENT1(event, PIHIDevice::Event, e); EVENT1(event, PIHIDevice::Event, e);
//! \~english Returns all available HID devices
//! \~russian Возвращает все доступные HID устройства
static PIVector<PIHIDeviceInfo> allDevices(bool try_open = true); static PIVector<PIHIDeviceInfo> allDevices(bool try_open = true);
//! \~english Finds device by name
//! \~russian Находит устройство по имени
static PIHIDeviceInfo findDevice(const PIString & name); static PIHIDeviceInfo findDevice(const PIString & name);
private: private:

View File

@@ -30,54 +30,36 @@
#include <functional> #include <functional>
//! \~english System signals handler
//! \~russian Обработчик системных сигналов
class PIP_EXPORT PISignals { class PIP_EXPORT PISignals {
public: public:
//! \~english Signal types
//! \~russian Типы сигналов
enum Signal { enum Signal {
Interrupt = 0x01, //!< Interrupt from keyboard Interrupt /** Interrupt from keyboard */ = 0x01, // Term Interrupt from keyboard
Illegal = 0x02, //!< Illegal Instruction Illegal /** Illegal Instruction */ = 0x02, // Core Illegal Instruction
Abort = 0x04, //!< Abort signal Abort /** Abort signal */ = 0x04, // Core Abort signal from abort
FPE = 0x08, //!< Floating point exception FPE /** Floating point exception */ = 0x08, // Core Floating point exception
SegFault = 0x10, //!< Invalid memory reference SegFault /** Invalid memory reference */ = 0x10, // Core Invalid memory reference
Termination = 0x20, //!< Termination signal Termination /** Termination signal */ = 0x20, // Term Termination signal
Hangup = 0x40, //!< Hangup detected Hangup = 0x40, // Term Hangup detected on controlling terminal or death of controlling process
Quit = 0x80, //!< Quit from keyboard Quit = 0x80, // Core Quit from keyboard
Kill = 0x100, //!< Kill signal Kill = 0x100, // Term Kill signal
BrokenPipe = 0x200, //!< Broken pipe BrokenPipe = 0x200, // Term Broken pipe: write to pipe with no readers
Timer = 0x400, //!< Timer signal Timer = 0x400, // Term Timer signal from alarm
UserDefined1 = 0x800, //!< User-defined signal 1 UserDefined1 = 0x800, // Term User-defined signal 1
UserDefined2 = 0x1000, //!< User-defined signal 2 UserDefined2 = 0x1000, // Term User-defined signal 2
ChildStopped = 0x2000, //!< Child stopped or terminated ChildStopped = 0x2000, // Ign Child stopped or terminated
Continue = 0x4000, //!< Continue if stopped Continue = 0x4000, // Cont Continue if stopped
StopProcess = 0x8000, //!< Stop process StopProcess = 0x8000, // Stop Stop process
StopTTY = 0x10000, //!< Stop typed at tty StopTTY = 0x10000, // Stop Stop typed at tty
StopTTYInput = 0x20000, //!< Stop tty input StopTTYInput = 0x20000, // Stop tty input for background process
StopTTYOutput = 0x40000, //!< Stop tty output StopTTYOutput = 0x40000, // Stop tty output for background process
All = 0xFFFFF //!< All signals All = 0xFFFFF
}; };
//! \~english Signal handler callback type
//! \~russian Тип коллбэка обработчика сигналов
//! \note slot is any function with format "void(PISignals::Signal)"
typedef std::function<void(PISignals::Signal)> SignalEvent; typedef std::function<void(PISignals::Signal)> SignalEvent;
// slot is any function format "void(PISignals::Signal)"
//! \~english Sets signal handler callback
//! \~russian Устанавливает коллбэк обработчика сигналов
static void setSlot(SignalEvent slot) { ret_func = slot; } static void setSlot(SignalEvent slot) { ret_func = slot; }
//! \~english Grabs specified signals
//! \~russian Перехватывает указанные сигналы
static void grabSignals(PIFlags<PISignals::Signal> signals_); static void grabSignals(PIFlags<PISignals::Signal> signals_);
//! \~english Releases specified signals
//! \~russian Освобождает указанные сигналы
static void releaseSignals(PIFlags<PISignals::Signal> signals_); static void releaseSignals(PIFlags<PISignals::Signal> signals_);
//! \~english Raises signal
//! \~russian Генерирует сигнал
static void raiseSignal(PISignals::Signal signal); static void raiseSignal(PISignals::Signal signal);
private: private:

View File

@@ -35,25 +35,25 @@
//! \~russian Класс C-строки. //! \~russian Класс C-строки.
class PIP_EXPORT PIConstChars { class PIP_EXPORT PIConstChars {
public: public:
//! \~english Constructs an null string. //! \~english Contructs an null string.
//! \~russian Создает нулевую строку. //! \~russian Создает нулевую строку.
PIConstChars() {} PIConstChars() {}
//! \~english Constructs string from C-string "string". //! \~english Contructs string from C-string "string".
//! \~russian Создает строку из C-строки "string". //! \~russian Создает строку из C-строки "string".
PIConstChars(const char * string) { PIConstChars(const char * string) {
str = string; str = string;
len = strlen(string); len = strlen(string);
} }
//! \~english Constructs string from "size" characters of buffer "data". //! \~english Contructs string from "size" characters of buffer "data".
//! \~russian Создает строку из "size" символов массива "data". //! \~russian Создает строку из "size" символов массива "data".
PIConstChars(const char * data, size_t size) { PIConstChars(const char * data, size_t size) {
str = data; str = data;
len = size; len = size;
} }
//! \~english Constructs a copy of string. //! \~english Contructs a copy of string.
//! \~russian Создает копию строки. //! \~russian Создает копию строки.
PIConstChars(const PIConstChars & o) { PIConstChars(const PIConstChars & o) {
str = o.str; str = o.str;

View File

@@ -54,7 +54,7 @@ public:
typedef const PIChar & const_reference; typedef const PIChar & const_reference;
typedef size_t size_type; typedef size_t size_type;
//! \~english Constructs an empty string. //! \~english Contructs an empty string.
//! \~russian Создает пустую строку. //! \~russian Создает пустую строку.
PIString() {} PIString() {}
@@ -106,7 +106,7 @@ public:
PIString & operator+=(llong) = delete; PIString & operator+=(llong) = delete;
PIString & operator+=(ullong) = delete; PIString & operator+=(ullong) = delete;
//! \~english Constructs a copy of string. //! \~english Contructs a copy of string.
//! \~russian Создает копию строки. //! \~russian Создает копию строки.
PIString(const PIString & o) { PIString(const PIString & o) {
d = o.d; d = o.d;

View File

@@ -1,12 +1,9 @@
//! \file piblockingqueue.h /*! \file piblockingqueue.h
//! \ingroup Thread * \ingroup Thread
//! \brief * \~\brief
//! \~english Queue with blocking * \~english Queue with blocking
//! \~russian Блокирующая очередь * \~russian Блокирующая очередь
//! */
//! \details
//! \~english Thread-safe queue that supports blocking operations - waits for space when storing and waits for element when retrieving.
//! \~russian Потокобезопасная очередь с поддержкой блокирующих операций - ожидает место при добавлении и ожидает элемент при получении.
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
@@ -36,13 +33,12 @@
* \brief A Queue that supports operations that wait for the queue to become non-empty when retrieving an element, and * \brief A Queue that supports operations that wait for the queue to become non-empty when retrieving an element, and
* wait for space to become available in the queue when storing an element. * wait for space to become available in the queue when storing an element.
*/ */
//! \~english Thread-safe blocking queue template class
//! \~russian Шаблонный класс потокобезопасной блокирующей очереди
template<typename T> template<typename T>
class PIBlockingQueue: private PIQueue<T> { class PIBlockingQueue: private PIQueue<T> {
public: public:
//! \~english Constructs queue with specified capacity /**
//! \~russian Создает очередь с указанной емкостью * \brief Constructor
*/
explicit inline PIBlockingQueue(size_t capacity = SIZE_MAX, explicit inline PIBlockingQueue(size_t capacity = SIZE_MAX,
PIConditionVariable * cond_var_add = new PIConditionVariable(), PIConditionVariable * cond_var_add = new PIConditionVariable(),
PIConditionVariable * cond_var_rem = new PIConditionVariable()) PIConditionVariable * cond_var_rem = new PIConditionVariable())
@@ -50,8 +46,9 @@ public:
, cond_var_rem(cond_var_rem) , cond_var_rem(cond_var_rem)
, max_size(capacity) {} , max_size(capacity) {}
//! \~english Copy constructor from PIDeque /**
//! \~russian Конструктор копирования из PIDeque * \brief Copy constructor. Initialize queue with copy of other queue elements. Not thread-safe for other queue.
*/
explicit inline PIBlockingQueue(const PIDeque<T> & other) explicit inline PIBlockingQueue(const PIDeque<T> & other)
: cond_var_add(new PIConditionVariable()) : cond_var_add(new PIConditionVariable())
, cond_var_rem(new PIConditionVariable()) { , cond_var_rem(new PIConditionVariable()) {
@@ -61,8 +58,9 @@ public:
mutex.unlock(); mutex.unlock();
} }
//! \~english Thread-safe copy constructor from another PIBlockingQueue /**
//! \~russian Потокобезопасный конструктор копирования из другой PIBlockingQueue * \brief Thread-safe copy constructor. Initialize queue with copy of other queue elements.
*/
inline PIBlockingQueue(PIBlockingQueue<T> & other): cond_var_add(new PIConditionVariable()), cond_var_rem(new PIConditionVariable()) { inline PIBlockingQueue(PIBlockingQueue<T> & other): cond_var_add(new PIConditionVariable()), cond_var_rem(new PIConditionVariable()) {
other.mutex.lock(); other.mutex.lock();
mutex.lock(); mutex.lock();
@@ -77,8 +75,11 @@ public:
delete cond_var_rem; delete cond_var_rem;
} }
//! \~english Inserts element waiting for space to become available /**
//! \~russian Вставляет элемент, ожидая освобождения места * \brief Inserts the specified element into this queue, waiting if necessary for space to become available.
*
* @param v the element to add
*/
PIBlockingQueue<T> & put(const T & v) { PIBlockingQueue<T> & put(const T & v) {
mutex.lock(); mutex.lock();
cond_var_rem->wait(mutex, [&]() { return PIDeque<T>::size() < max_size; }); cond_var_rem->wait(mutex, [&]() { return PIDeque<T>::size() < max_size; });
@@ -90,8 +91,14 @@ public:
PIBlockingQueue<T> & enqueue(const T & v) { return put(v); } PIBlockingQueue<T> & enqueue(const T & v) { return put(v); }
//! \~english Inserts element if possible without exceeding capacity /**
//! \~russian Вставляет элемент если возможно без превышения емкости * \brief Inserts the specified element at the end of this queue if it is possible to do so immediately without
* exceeding the queue's capacity, returning true upon success and false if this queue is full.
*
* @param v the element to add
* @param timeout the timeout waiting for inserting if que is full, if timeout is null, then returns immediately
* @return true if the element was added to this queue, else false
*/
bool offer(const T & v, PISystemTime timeout = {}) { bool offer(const T & v, PISystemTime timeout = {}) {
bool isOk; bool isOk;
mutex.lock(); mutex.lock();
@@ -122,8 +129,16 @@ public:
T dequeue() { return take(); } T dequeue() { return take(); }
//! \~english Retrieves and removes head, waiting until element becomes available /**
//! \~russian Извлекает и удаляет голову очереди, ожидая появления элемента * \brief Retrieves and removes the head of this queue, waiting up to the specified wait time if necessary for an
* element to become available.
*
* @param timeout how long to wait before giving up
* @param defaultVal value, which returns if the specified waiting time elapses before an element is available
* @param isOk flag, which indicates result of method execution. It will be set to false if timeout, or true if
* return value is retrieved value
* @return the head of this queue, or defaultVal if the specified waiting time elapses before an element is available
*/
T poll(PISystemTime timeout = {}, const T & defaultVal = T(), bool * isOk = nullptr) { T poll(PISystemTime timeout = {}, const T & defaultVal = T(), bool * isOk = nullptr) {
T t = defaultVal; T t = defaultVal;
bool isNotEmpty; bool isNotEmpty;
@@ -139,8 +154,12 @@ public:
return t; return t;
} }
//! \~english Returns queue capacity /**
//! \~russian Возвращает емкость очереди * \brief Returns the number of elements that this queue can ideally (in the absence of memory or resource
* constraints) contains. This is always equal to the initial capacity of this queue less the current size of this queue.
*
* @return the capacity
*/
size_t capacity() { size_t capacity() {
size_t c; size_t c;
mutex.lock(); mutex.lock();
@@ -149,8 +168,12 @@ public:
return c; return c;
} }
//! \~english Returns remaining capacity /**
//! \~russian Возвращает оставшуюся емкость * \brief Returns the number of additional elements that this queue can ideally (in the absence of memory or resource
* constraints) accept. This is always equal to the initial capacity of this queue less the current size of this queue.
*
* @return the remaining capacity
*/
size_t remainingCapacity() { size_t remainingCapacity() {
mutex.lock(); mutex.lock();
size_t c = max_size - PIDeque<T>::size(); size_t c = max_size - PIDeque<T>::size();
@@ -158,8 +181,9 @@ public:
return c; return c;
} }
//! \~english Returns number of elements in queue /**
//! \~russian Возвращает количество элементов в очереди * \brief Returns the number of elements in this collection.
*/
size_t size() { size_t size() {
mutex.lock(); mutex.lock();
size_t s = PIDeque<T>::size(); size_t s = PIDeque<T>::size();
@@ -167,8 +191,9 @@ public:
return s; return s;
} }
//! \~english Removes all available elements and adds them to another queue /**
//! \~russian Удаляет все доступные элементы и добавляет их в другую очередь * \brief Removes all available elements from this queue and adds them to other given queue.
*/
size_t drainTo(PIDeque<T> & other, size_t maxCount = SIZE_MAX) { size_t drainTo(PIDeque<T> & other, size_t maxCount = SIZE_MAX) {
mutex.lock(); mutex.lock();
size_t count = ((maxCount > PIDeque<T>::size()) ? PIDeque<T>::size() : maxCount); size_t count = ((maxCount > PIDeque<T>::size()) ? PIDeque<T>::size() : maxCount);
@@ -178,8 +203,9 @@ public:
return count; return count;
} }
//! \~english Removes all available elements and adds them to another blocking queue /**
//! \~russian Удаляет все доступные элементы и добавляет их в другую блокирующую очередь * \brief Removes all available elements from this queue and adds them to other given queue.
*/
size_t drainTo(PIBlockingQueue<T> & other, size_t maxCount = SIZE_MAX) { size_t drainTo(PIBlockingQueue<T> & other, size_t maxCount = SIZE_MAX) {
mutex.lock(); mutex.lock();
other.mutex.lock(); other.mutex.lock();

View File

@@ -1,12 +1,9 @@
//! \file piconditionvar.h /*! \file piconditionvar.h
//! \ingroup Thread * \ingroup Thread
//! \brief * \~\brief
//! \~english Conditional variable * \~english Conditional variable
//! \~russian Условная переменная * \~russian Conditional variable
//! */
//! \details
//! \~english Object able to block the calling thread until notified to resume.
//! \~russian Объект, способный заблокировать вызывающий поток до уведомления о продолжении.
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
@@ -39,39 +36,27 @@
* It uses a PIMutex to lock the thread when one of its wait functions is called. The thread remains * It uses a PIMutex to lock the thread when one of its wait functions is called. The thread remains
* blocked until woken up by another thread that calls a notification function on the same PIConditionVariable object. * blocked until woken up by another thread that calls a notification function on the same PIConditionVariable object.
*/ */
//! \~english Condition variable for thread synchronization
//! \~russian Условная переменная для синхронизации потоков
class PIP_EXPORT PIConditionVariable { class PIP_EXPORT PIConditionVariable {
public: public:
NO_COPY_CLASS(PIConditionVariable); NO_COPY_CLASS(PIConditionVariable);
//! \~english Constructs condition variable
//! \~russian Создает условную переменную
explicit PIConditionVariable(); explicit PIConditionVariable();
//! \~english Destroys condition variable
//! \~russian Уничтожает условную переменную
virtual ~PIConditionVariable(); virtual ~PIConditionVariable();
/** /**
* \brief Unblocks one of the threads currently waiting for this condition. If no threads are waiting, the function * \brief Unblocks one of the threads currently waiting for this condition. If no threads are waiting, the function
* does nothing. If more than one, it is unspecified which of the threads is selected. * does nothing. If more than one, it is unspecified which of the threads is selected.
*/ */
//! \~english Wakes one waiting thread
//! \~russian Будит один ожидающий поток
void notifyOne(); void notifyOne();
/** /**
* \brief Unblocks all threads currently waiting for this condition. If no threads are waiting, the function does * \brief Unblocks all threads currently waiting for this condition. If no threads are waiting, the function does
* nothing. * nothing.
*/ */
//! \~english Wakes all waiting threads
//! \~russian Будит все ожидающие потоки
void notifyAll(); void notifyAll();
/** /**
* \brief see wait(PIMutex &, const std::function<bool()>&) * \brief see wait(PIMutex &, const std::function<bool()>&)
*/ */
//! \~english Wait until notified
//! \~russian Ожидает уведомления
virtual void wait(PIMutex & lk); virtual void wait(PIMutex & lk);
/** /**
@@ -98,15 +83,11 @@ public:
* @param condition A callable object or function that takes no arguments and returns a value that can be evaluated * @param condition A callable object or function that takes no arguments and returns a value that can be evaluated
* as a bool. This is called repeatedly until it evaluates to true. * as a bool. This is called repeatedly until it evaluates to true.
*/ */
//! \~english Wait until notified with condition predicate
//! \~russian Ожидает уведомления с условием
virtual void wait(PIMutex & lk, const std::function<bool()> & condition); virtual void wait(PIMutex & lk, const std::function<bool()> & condition);
/** /**
* \brief see waitFor(PIMutex &, int, const std::function<bool()>&) * \brief see waitFor(PIMutex &, int, const std::function<bool()>&)
*/ */
//! \~english Wait for timeout
//! \~russian Ожидает таймаут
virtual bool waitFor(PIMutex & lk, PISystemTime timeout); virtual bool waitFor(PIMutex & lk, PISystemTime timeout);
/** /**
@@ -134,8 +115,6 @@ public:
* as a bool. This is called repeatedly until it evaluates to true. * as a bool. This is called repeatedly until it evaluates to true.
* @return false if timeout reached or true if wakeup condition is true * @return false if timeout reached or true if wakeup condition is true
*/ */
//! \~english Wait for timeout or until notified with condition predicate
//! \~russian Ожидает таймаут или уведомление с условием
virtual bool waitFor(PIMutex & lk, PISystemTime timeout, const std::function<bool()> & condition); virtual bool waitFor(PIMutex & lk, PISystemTime timeout, const std::function<bool()> & condition);
private: private:

View File

@@ -1,12 +1,9 @@
//! \file pigrabberbase.h /*! \file pigrabberbase.h
//! \ingroup Thread * \ingroup Thread
//! \brief * \~\brief
//! \~english Abstract class for creating grabbers * \~english Abstract class for create grabbers
//! \~russian Базовый класс для создания грабберов * \~russian Базовый класс для создания грабберов
//! */
//! \details
//! \~english Base class for thread-based data acquisition with queue support.
//! \~russian Базовый класс для получения данных в потоке с поддержкой очереди.
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Abstract class for create grabbers Abstract class for create grabbers
@@ -34,33 +31,18 @@
#include "pitime.h" #include "pitime.h"
//! \~english Base class for data grabber threads
//! \~russian Базовый класс для потоков получения данных
template<typename T = PIByteArray> template<typename T = PIByteArray>
class PIGrabberBase: public PIThread { class PIGrabberBase: public PIThread {
PIOBJECT_SUBCLASS(PIGrabberBase, PIThread); PIOBJECT_SUBCLASS(PIGrabberBase, PIThread);
public: public:
//! \~english Constructs grabber
//! \~russian Создает граббер
PIGrabberBase() { PIGrabberBase() {
is_opened = false; is_opened = false;
is_recording = false; is_recording = false;
} }
//! \~english Destroys grabber
//! \~russian Уничтожает граббер
virtual ~PIGrabberBase() { stopGrabber(false); } virtual ~PIGrabberBase() { stopGrabber(false); }
//! \~english Returns if grabber is opened
//! \~russian Возвращает открыт ли граббер
virtual bool isOpened() const { return is_opened; } virtual bool isOpened() const { return is_opened; }
//! \~english Returns if grabber is recording
//! \~russian Возвращает записывает ли граббер
virtual bool isRecording() const { return is_recording; } virtual bool isRecording() const { return is_recording; }
//! \~english Start recording to file
//! \~russian Начинает запись в файл
virtual void startRecord(const PIString & filename) { virtual void startRecord(const PIString & filename) {
if (!isOpened()) return; if (!isOpened()) return;
if (isRecording()) return; if (isRecording()) return;
@@ -69,8 +51,6 @@ public:
is_recording = true; is_recording = true;
rec_mutex.unlock(); rec_mutex.unlock();
} }
//! \~english Stop recording
//! \~russian Останавливает запись
virtual void stopRecord() { virtual void stopRecord() {
if (!isOpened()) return; if (!isOpened()) return;
if (!isRecording()) return; if (!isRecording()) return;
@@ -79,9 +59,6 @@ public:
stopRecordInternal(); stopRecordInternal();
rec_mutex.unlock(); rec_mutex.unlock();
} }
//! \~english Returns last grabbed data
//! \~russian Возвращает последние полученные данные
T last() const { T last() const {
T ret; T ret;
last_mutex.lock(); last_mutex.lock();
@@ -89,9 +66,6 @@ public:
last_mutex.unlock(); last_mutex.unlock();
return ret; return ret;
} }
//! \~english Returns if queue is empty
//! \~russian Возвращает пустая ли очередь
bool isEmpty() { bool isEmpty() {
bool ret; bool ret;
que_mutex.lock(); que_mutex.lock();
@@ -99,9 +73,6 @@ public:
que_mutex.unlock(); que_mutex.unlock();
return ret; return ret;
} }
//! \~english Returns queue size
//! \~russian Возвращает размер очереди
int queSize() { int queSize() {
int ret; int ret;
que_mutex.lock(); que_mutex.lock();
@@ -109,9 +80,6 @@ public:
que_mutex.unlock(); que_mutex.unlock();
return ret; return ret;
} }
//! \~english Dequeues data from queue
//! \~russian Извлекает данные из очереди
T dequeue() { T dequeue() {
T ret; T ret;
// piCoutObj << "start"; // piCoutObj << "start";
@@ -124,9 +92,6 @@ public:
que_mutex.unlock(); que_mutex.unlock();
return ret; return ret;
} }
//! \~english Stop grabber thread
//! \~russian Останавливает поток граббера
void stopGrabber(bool wait_forever = true) { void stopGrabber(bool wait_forever = true) {
if (isRunning()) { if (isRunning()) {
stop(); stop();
@@ -139,18 +104,12 @@ public:
} }
} }
} }
//! \~english Open grabber
//! \~russian Открывает граббер
bool open() { bool open() {
bool ret = openInternal(); bool ret = openInternal();
if (!is_opened && ret) opened(); if (!is_opened && ret) opened();
is_opened = ret; is_opened = ret;
return ret; return ret;
} }
//! \~english Close grabber
//! \~russian Закрывает граббер
void close() { void close() {
bool em = is_opened; bool em = is_opened;
closeInternal(); closeInternal();
@@ -158,21 +117,12 @@ public:
if (em) closed(); if (em) closed();
is_opened = false; is_opened = false;
} }
//! \~english Returns diagnostics
//! \~russian Возвращает диагностику
const PIDiagnostics & diag() const { return diag_; } const PIDiagnostics & diag() const { return diag_; }
//! \~english Clear queue
//! \~russian Очищает очередь
void clear() { void clear() {
que_mutex.lock(); que_mutex.lock();
que.clear(); que.clear();
que_mutex.unlock(); que_mutex.unlock();
} }
//! \~english Restart grabber
//! \~russian Перезапускает граббер
void restart() { void restart() {
clear(); clear();
close(); close();

View File

@@ -1,12 +1,9 @@
//! \file pipipelinethread.h /*! \file pipipelinethread.h
//! \ingroup Thread * \ingroup Thread
//! \brief * \~\brief
//! \~english Class for creating multithread pipeline * \~english Class for create multihread pipeline
//! \~russian Класс для создания многопоточного конвейера * \~russian Класс для создания многопоточного конвейера
//! */
//! \details
//! \~english Pipeline thread for processing data through stages in separate threads.
//! \~russian Конвейерный поток для обработки данных через этапы в отдельных потоках.
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Class for create multihread pipeline Class for create multihread pipeline
@@ -34,22 +31,16 @@
#include "pithread.h" #include "pithread.h"
//! \~english Pipeline thread template class
//! \~russian Шаблонный класс конвейерного потока
template<typename Tin, typename Tout> template<typename Tin, typename Tout>
class PIPipelineThread: public PIThread { class PIPipelineThread: public PIThread {
PIOBJECT_SUBCLASS(PIPipelineThread, PIThread); PIOBJECT_SUBCLASS(PIPipelineThread, PIThread);
public: public:
//! \~english Constructs pipeline thread
//! \~russian Создает конвейерный поток
PIPipelineThread() { PIPipelineThread() {
cnt = 0; cnt = 0;
max_size = 0; max_size = 0;
wait_next_pipe = false; wait_next_pipe = false;
} }
//! \~english Destroys pipeline thread
//! \~russian Уничтожает конвейерный поток
~PIPipelineThread() { ~PIPipelineThread() {
stop(); stop();
cv.notifyAll(); cv.notifyAll();
@@ -58,8 +49,6 @@ public:
terminate(); terminate();
} }
} }
//! \~english Connect to next pipeline stage
//! \~russian Подключает к следующему этапу конвейера
template<typename T> template<typename T>
void connectTo(PIPipelineThread<Tout, T> * next) { void connectTo(PIPipelineThread<Tout, T> * next) {
CONNECT3(void, Tout, bool, bool *, this, calculated, next, enqueue); CONNECT3(void, Tout, bool, bool *, this, calculated, next, enqueue);
@@ -83,21 +72,9 @@ public:
} }
mutex.unlock(); mutex.unlock();
} }
//! \~english Enqueue data for processing
//! \~russian Добавляет данные в очередь на обработку
void enqueue(const Tin & v, bool wait = false) { enqueue(v, wait, nullptr); } void enqueue(const Tin & v, bool wait = false) { enqueue(v, wait, nullptr); }
//! \~english Returns pointer to counter
//! \~russian Возвращает указатель на счетчик
const ullong * counterPtr() const { return &cnt; } const ullong * counterPtr() const { return &cnt; }
//! \~english Returns items processed counter
//! \~russian Возвращает количество обработанных элементов
ullong counter() const { return cnt; } ullong counter() const { return cnt; }
//! \~english Returns if input queue is empty
//! \~russian Возвращает пустая ли входная очередь
bool isEmpty() { bool isEmpty() {
bool ret; bool ret;
mutex.lock(); mutex.lock();
@@ -105,9 +82,6 @@ public:
mutex.unlock(); mutex.unlock();
return ret; return ret;
} }
//! \~english Returns input queue size
//! \~russian Возвращает размер входной очереди
int queSize() { int queSize() {
int ret; int ret;
mutex.lock(); mutex.lock();
@@ -115,9 +89,6 @@ public:
mutex.unlock(); mutex.unlock();
return ret; return ret;
} }
//! \~english Clear input queue
//! \~russian Очищает входную очередь
void clear() { void clear() {
mutex.lock(); mutex.lock();
mutex_wait.lock(); mutex_wait.lock();
@@ -126,9 +97,6 @@ public:
mutex_wait.unlock(); mutex_wait.unlock();
mutex.unlock(); mutex.unlock();
} }
//! \~english Stop calculation
//! \~russian Останавливает вычисления
void stopCalc(int wait_delay = 100) { void stopCalc(int wait_delay = 100) {
if (isRunning()) { if (isRunning()) {
stop(); stop();
@@ -140,9 +108,6 @@ public:
} }
} }
} }
//! \~english Returns last processed result
//! \~russian Возвращает последний обработанный результат
Tout getLast() { Tout getLast() {
Tout ret; Tout ret;
mutex_last.lock(); mutex_last.lock();
@@ -151,12 +116,8 @@ public:
return ret; return ret;
} }
//! \~english Returns max queue size
//! \~russian Возвращает максимальный размер очереди
uint maxQueSize() { return max_size; } uint maxQueSize() { return max_size; }
//! \~english Set max queue size
//! \~russian Устанавливает максимальный размер очереди
void setMaxQueSize(uint count) { void setMaxQueSize(uint count) {
mutex.lock(); mutex.lock();
max_size = count; max_size = count;
@@ -164,17 +125,10 @@ public:
mutex.unlock(); mutex.unlock();
} }
//! \~english Returns if waiting for next pipeline
//! \~russian Возвращает ожидает ли следующий конвейер
bool isWaitNextPipe() { return wait_next_pipe; } bool isWaitNextPipe() { return wait_next_pipe; }
//! \~english Set waiting for next pipeline
//! \~russian Устанавливает ожидание следующего конвейера
void setWaitNextPipe(bool wait) { wait_next_pipe = wait; } void setWaitNextPipe(bool wait) { wait_next_pipe = wait; }
protected: protected:
//! \~english Processing function - must be implemented
//! \~russian Функция обработки - должна быть реализована
virtual Tout calc(Tin & v, bool & ok) = 0; virtual Tout calc(Tin & v, bool & ok) = 0;
uint max_size; uint max_size;

View File

@@ -1,29 +1,26 @@
//! \file piprotectedvariable.h /*! \file piprotectedvariable.h
//! \ingroup Thread * \ingroup Thread
//! \brief * \~\brief
//! \~english Thread-safe variable * \~english Thread-safe variable
//! \~russian Потокобезопасная переменная * \~russian Потокобезопасная переменная
//! */
//! \details
//! \~english Template class for thread-safe variable access with mutex protection.
//! \~russian Шаблонный класс для потокобезопасного доступа к переменной с защитой мьютексом.
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Thread-safe variable Thread-safe variable
Ivan Pelipenko peri4ko@yandex.ru, Stephan Fomenko, Andrey Bychkov work.a.b@yandex.ru Ivan Pelipenko peri4ko@yandex.ru, Stephan Fomenko, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify 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 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 the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License 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/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef PIPROTECTEDVARIABLE_H #ifndef PIPROTECTEDVARIABLE_H
@@ -32,37 +29,25 @@
#include "pimutex.h" #include "pimutex.h"
//! \~english Thread-safe variable template class
//! \~russian Шаблонный класс потокобезопасной переменной
template<typename T> template<typename T>
class PIP_EXPORT PIProtectedVariable { class PIP_EXPORT PIProtectedVariable {
public: public:
//! \~english Pointer wrapper for thread-safe access //! \~english
//! \~russian Обертка указателя для потокобезопасного доступа //! \~russian
class PIP_EXPORT Pointer { class PIP_EXPORT Pointer {
friend class PIProtectedVariable<T>; friend class PIProtectedVariable<T>;
public: public:
//! \~english Copy constructor
//! \~russian Конструктор копирования
Pointer(const Pointer & v): pv(v.pv), counter(v.counter + 1) {} Pointer(const Pointer & v): pv(v.pv), counter(v.counter + 1) {}
//! \~english Destructor - unlocks mutex
//! \~russian Деструктор - разблокирует мьютекс
~Pointer() { ~Pointer() {
if (counter == 0) pv.mutex.unlock(); if (counter == 0) pv.mutex.unlock();
} }
//! \~english Access member
//! \~russian Доступ к члену
T * operator->() { return &pv.var; } T * operator->() { return &pv.var; }
//! \~english Access value
//! \~russian Доступ к значению
T & operator*() { return pv.var; } T & operator*() { return pv.var; }
private: private:
Pointer() = delete; Pointer() = delete;
//! \~english Construct from PIProtectedVariable
//! \~russian Конструктор из PIProtectedVariable
Pointer(PIProtectedVariable<T> & v): pv(v) {} Pointer(PIProtectedVariable<T> & v): pv(v) {}
PIProtectedVariable<T> & pv; PIProtectedVariable<T> & pv;

View File

@@ -1,12 +1,3 @@
//! \file pithreadpoolexecutor.h
//! \ingroup Thread
//! \brief
//! \~english Thread pool executor
//! \~russian Исполнитель пула потоков
//!
//! \details
//! \~english Executes tasks in a pool of worker threads.
//! \~russian Выполняет задачи в пуле рабочих потоков.
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
@@ -35,16 +26,10 @@
#include <atomic> #include <atomic>
//! \~english Thread pool executor for running tasks
//! \~russian Исполнитель пула потоков для выполнения задач
class PIP_EXPORT PIThreadPoolExecutor { class PIP_EXPORT PIThreadPoolExecutor {
public: public:
//! \~english Constructs executor with core pool size
//! \~russian Создает исполнитель с размером ядра пула
explicit PIThreadPoolExecutor(int corePoolSize); explicit PIThreadPoolExecutor(int corePoolSize);
//! \~english Destroys executor
//! \~russian Уничтожает исполнитель
virtual ~PIThreadPoolExecutor(); virtual ~PIThreadPoolExecutor();
//! \brief Executes the given task sometime in the future. The task execute in an existing pooled thread. If the task //! \brief Executes the given task sometime in the future. The task execute in an existing pooled thread. If the task
@@ -52,27 +37,17 @@ public:
//! reached. //! reached.
//! //!
//! \param runnable not empty function for thread pool execution //! \param runnable not empty function for thread pool execution
//! \~english Execute task in thread pool
//! \~russian Выполняет задачу в пуле потоков
void execute(const std::function<void()> & runnable); void execute(const std::function<void()> & runnable);
//! \~english Stop all threads immediately
//! \~russian Немедленно останавливает все потоки
void shutdownNow(); void shutdownNow();
//! \brief Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be //! \brief Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be
//! accepted. Invocation has no additional effect if already shut down. This method does not wait for previously //! accepted. Invocation has no additional effect if already shut down. This method does not wait for previously
//! submitted tasks to complete execution. Use awaitTermination to do that. //! submitted tasks to complete execution. Use awaitTermination to do that.
//! \~english Initiates orderly shutdown
//! \~russian Инициирует упорядоченное завершение
void shutdown(); void shutdown();
//! \~english Returns if executor is shutdown
//! \~russian Возвращает остановлен ли исполнитель
bool isShutdown() const; bool isShutdown() const;
//! \~english Wait for termination
//! \~russian Ожидает завершения
bool awaitTermination(PISystemTime timeout); bool awaitTermination(PISystemTime timeout);
private: private:

View File

@@ -1,8 +1,3 @@
//! \file colors_p.h
//! \ingroup Types
//! \~\brief
//! \~english Color collection
//! \~russian Коллекция цветов
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Color collection Color collection
@@ -28,27 +23,13 @@
#include "pivarianttypes.h" #include "pivarianttypes.h"
//! \ingroup Types
//! \~\brief
//! \~english Color collection singleton for CSS color names.
//! \~russian Синглтон коллекции цветов для CSS имен цветов.
class PIColorCollection { class PIColorCollection {
public: public:
//! \~english Returns singleton instance of color collection.
//! \~russian Возвращает синглтон экземпляр коллекции цветов.
static PIColorCollection & instance(); static PIColorCollection & instance();
//! \~english Returns color by CSS name.
//! \~russian Возвращает цвет по CSS имени.
PIVariantTypes::Color getCSSColor(const PIString & name) const { return css_color.value(name); } PIVariantTypes::Color getCSSColor(const PIString & name) const { return css_color.value(name); }
//! \~english Returns CSS name by color.
//! \~russian Возвращает CSS имя по цвету.
PIString getCSSName(const PIVariantTypes::Color color) const { return css_name.value(color); } PIString getCSSName(const PIVariantTypes::Color color) const { return css_name.value(color); }
private: private:
//! \~english Private constructor.
//! \~russian Приватный конструктор.
PIColorCollection(); PIColorCollection();
PIMap<PIString, PIVariantTypes::Color> css_color; PIMap<PIString, PIVariantTypes::Color> css_color;
PIMap<PIVariantTypes::Color, PIString> css_name; PIMap<PIVariantTypes::Color, PIString> css_name;

View File

@@ -1,8 +1,8 @@
//! \file pibitarray.h /*! \file pibitarray.h
//! \ingroup Types * \~\brief
//! \~\brief * \~english Bit array
//! \~english Bit array * \~russian Битовый массив
//! \~russian Битовый массив */
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Bit array Bit array

View File

@@ -1,8 +1,9 @@
//! \file pibytearray.h /*! \file pibytearray.h
//! \ingroup Types * \ingroup Types
//! \~\brief * \~\brief
//! \~english Byte array * \~english Byte array
//! \~russian Байтовый массив * \~russian Байтовый массив
*/
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Byte array Byte array

View File

@@ -1,8 +1,9 @@
//! \file pidatetime.h /*! \file pidatetime.h
//! \ingroup Types * \ingroup Types
//! \~\brief * \~\brief
//! \~english Time and date structs * \~english Time and date structs
//! \~russian Типы времени и даты * \~russian Типы времени и даты
*/
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Time and date structs Time and date structs

View File

@@ -1,8 +1,9 @@
//! \file piflags.h /*! \file piflags.h
//! \ingroup Types * \ingroup Types
//! \~\brief * \~\brief
//! \~english General flags class * \~english General flags class
//! \~russian Универсальные флаги * \~russian Универсальные флаги
*/
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
General flags class General flags class

View File

@@ -1,11 +1,12 @@
//! \file pinetworkaddress.h /*! \file pinetworkaddress.h
//! \ingroup Types * \ingroup Types
//! \~\brief * \~\brief
//! \~english Network address * \~english Network address
//! \~russian Сетевой адрес * \~russian Сетевой адрес
*/
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Network address Network address
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,8 +1,9 @@
//! \file pipropertystorage.h /*! \file pipropertystorage.h
//! \ingroup Types * \ingroup Types
//! \~\brief * \~\brief
//! \~english Properties array * \~english Properties array
//! \~russian Массив свойств * \~russian Массив свойств
*/
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Storage of properties for GUI usage Storage of properties for GUI usage

View File

@@ -1,8 +1,9 @@
//! \file pisystemtime.h /*! \file pisystemtime.h
//! \ingroup Types * \ingroup Types
//! \~\brief * \~\brief
//! \~english System time structs and methods * \~english System time structs and methods
//! \~russian Типы и методы системного времени * \~russian Типы и методы системного времени
*/
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Time structs Time structs

View File

@@ -1,8 +1,9 @@
//! \file pitime.h /*! \file pitime.h
//! \ingroup Types * \ingroup Types
//! \~\brief * \~\brief
//! \~english System time, time and date * \~english System time, time and date
//! \~russian Системное время, время и дата * \~russian Системное время, время и дата
*/
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru

View File

@@ -1,8 +1,9 @@
//! \file pivaluetree.h /*! \file pivaluetree.h
//! \ingroup Types * \ingroup Types
//! \~\brief * \brief
//! \~english Attributed values tree * \~english Attributed values tree
//! \~russian Дерево атрибутированных значений * \~russian Дерево атрибутированных значений
*/
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Attributed values tree Attributed values tree

View File

@@ -1,8 +1,9 @@
//! \file pivariant.h /*! \file pivariant.h
//! \ingroup Types * \ingroup Types
//! \~\brief * \brief
//! \~english Variant type * \~english Variant type
//! \~russian Вариативный тип * \~russian Вариативный тип
*/
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Variant type Variant type
@@ -101,21 +102,21 @@ struct __PIVariantTypeInfo__ {
typedef const T & ConstReferenceType; typedef const T & ConstReferenceType;
}; };
# define __TYPEINFO_SINGLE(PT, T) \ # define __TYPEINFO_SINGLE(PT, T) \
template<> \ template<> \
struct __PIVariantTypeInfo__<T> { \ struct __PIVariantTypeInfo__<T> { \
typedef PT PureType; \ typedef PT PureType; \
typedef const PT ConstPureType; \ typedef const PT ConstPureType; \
typedef PT * PointerType; \ typedef PT * PointerType; \
typedef const PT * ConstPointerType; \ typedef const PT * ConstPointerType; \
typedef PT & ReferenceType; \ typedef PT & ReferenceType; \
typedef const PT & ConstReferenceType; \ typedef const PT & ConstReferenceType; \
}; };
# define REGISTER_VARIANT_TYPEINFO(T) \ # define REGISTER_VARIANT_TYPEINFO(T) \
__TYPEINFO_SINGLE(T, T &) \ __TYPEINFO_SINGLE(T, T &) \
__TYPEINFO_SINGLE(T, const T) \ __TYPEINFO_SINGLE(T, const T) \
__TYPEINFO_SINGLE(T, const T &) __TYPEINFO_SINGLE(T, const T &)
class PIP_EXPORT __PIVariantInfoStorage__ { class PIP_EXPORT __PIVariantInfoStorage__ {
@@ -124,67 +125,72 @@ public:
}; };
# define REGISTER_VARIANT(classname) \ # define REGISTER_VARIANT(classname) \
template<> \ template<> \
inline PIString __PIVariantFunctions__<classname>::typeNameHelper() { \ inline PIString __PIVariantFunctions__<classname>::typeNameHelper() { \
static PIString tn = PIStringAscii(#classname); \ static PIString tn = PIStringAscii(#classname); \
return tn; \ return tn; \
} \ } \
template<> \ template<> \
inline uint __PIVariantFunctions__<classname>::typeIDHelper() { \ inline uint __PIVariantFunctions__<classname>::typeIDHelper() { \
static uint ret = PIStringAscii(#classname).hash(); \ static uint ret = PIStringAscii(#classname).hash(); \
return ret; \ return ret; \
} \ } \
REGISTER_VARIANT_TYPEINFO(classname) \ REGISTER_VARIANT_TYPEINFO(classname) \
STATIC_INITIALIZER_BEGIN \ STATIC_INITIALIZER_BEGIN \
uint type_id = __PIVariantFunctions__<classname>::typeIDHelper(); \ uint type_id = __PIVariantFunctions__<classname>::typeIDHelper(); \
PIString type_name = __PIVariantFunctions__<classname>::typeNameHelper(); \ PIString type_name = __PIVariantFunctions__<classname>::typeNameHelper(); \
if (__PIVariantInfoStorage__::get().contains(type_id)) return; \ if (__PIVariantInfoStorage__::get().contains(type_id)) return; \
PIByteArray empty; \ PIByteArray empty; \
empty << classname(); \ empty << classname(); \
__PIVariantInfoStorage__::get()[type_id] = new __PIVariantInfo__(type_name, empty); \ __PIVariantInfoStorage__::get()[type_id] = new __PIVariantInfo__(type_name, empty); \
STATIC_INITIALIZER_END STATIC_INITIALIZER_END
# define REGISTER_VARIANT_CAST_H(classname_from, classname_to) \ # define REGISTER_VARIANT_CAST_H(classname_from, classname_to) \
template<> \ template<> \
template<> \ template<> \
inline classname_to __PIVariantFunctions__<classname_from>::castVariant<classname_to>(const classname_from & v); inline classname_to __PIVariantFunctions__<classname_from>::castVariant<classname_to>(const classname_from & v);
# define REGISTER_VARIANT_CAST_CPP(classname_from, classname_to) \ # define REGISTER_VARIANT_CAST_CPP(classname_from, classname_to) \
template<> \ template<> \
template<> \ template<> \
inline PIByteArray __PIVariantFunctions__<classname_from>::castHelper<classname_to>(PIByteArray v) { \ inline PIByteArray __PIVariantFunctions__<classname_from>::castHelper<classname_to>(PIByteArray v) { \
classname_from f; \ classname_from f; \
v >> f; \ v >> f; \
classname_to t = __PIVariantFunctions__<classname_from>::castVariant<classname_to>(f); \ classname_to t = __PIVariantFunctions__<classname_from>::castVariant<classname_to>(f); \
PIByteArray ret; \ PIByteArray ret; \
ret << t; \ ret << t; \
return ret; \ return ret; \
} \
STATIC_INITIALIZER_BEGIN \
__PIVariantInfo__ * vi(__PIVariantInfoStorage__::get().value(__PIVariantFunctions__<classname_from>::typeIDHelper(), nullptr)); \
if (!vi) { \
piCout << "Warning! Using REGISTER_VARIANT_CAST(" #classname_from ", " #classname_to ") before REGISTER_VARIANT(" #classname_from \
"), ignore."; \
return; \
} \ } \
vi->cast[__PIVariantFunctions__<classname_to>::typeIDHelper()] = __PIVariantFunctions__<classname_from>::castHelper<classname_to>; \ STATIC_INITIALIZER_BEGIN \
STATIC_INITIALIZER_END \ __PIVariantInfo__ * vi(__PIVariantInfoStorage__::get().value(__PIVariantFunctions__<classname_from>::typeIDHelper(), nullptr)); \
template<> \ if (!vi) { \
template<> \ piCout << "Warning! Using REGISTER_VARIANT_CAST(" #classname_from ", " #classname_to \
classname_to __PIVariantFunctions__<classname_from>::castVariant<classname_to>(const classname_from & v) ") before REGISTER_VARIANT(" #classname_from "), ignore."; \
return; \
} \
vi->cast[__PIVariantFunctions__<classname_to>::typeIDHelper()] = \
__PIVariantFunctions__<classname_from>::castHelper<classname_to>; \
STATIC_INITIALIZER_END \
template<> \
template<> \
classname_to __PIVariantFunctions__<classname_from>::castVariant<classname_to>(const classname_from & v)
# define REGISTER_VARIANT_CAST(classname_from, classname_to) \ # define REGISTER_VARIANT_CAST(classname_from, classname_to) \
REGISTER_VARIANT_CAST_H(classname_from, classname_to) \ REGISTER_VARIANT_CAST_H(classname_from, classname_to) \
REGISTER_VARIANT_CAST_CPP(classname_from, classname_to) REGISTER_VARIANT_CAST_CPP(classname_from, classname_to)
# define REGISTER_VARIANT_CAST_SIMPLE(classname_from, classname_to) \ # define REGISTER_VARIANT_CAST_SIMPLE(classname_from, classname_to) \
REGISTER_VARIANT_CAST(classname_from, classname_to) { return classname_to(v); } REGISTER_VARIANT_CAST(classname_from, classname_to) { \
return classname_to(v); \
}
# define REGISTER_VARIANT_CAST_SIMPLE_H(classname_from, classname_to) REGISTER_VARIANT_CAST_H(classname_from, classname_to) # define REGISTER_VARIANT_CAST_SIMPLE_H(classname_from, classname_to) REGISTER_VARIANT_CAST_H(classname_from, classname_to)
# define REGISTER_VARIANT_CAST_SIMPLE_CPP(classname_from, classname_to) \ # define REGISTER_VARIANT_CAST_SIMPLE_CPP(classname_from, classname_to) \
REGISTER_VARIANT_CAST_CPP(classname_from, classname_to) { return classname_to(v); } REGISTER_VARIANT_CAST_CPP(classname_from, classname_to) { \
return classname_to(v); \
}
#else #else
@@ -1176,7 +1182,7 @@ REGISTER_VARIANT_CAST(PIGeoPosition, PIString) {
g.setEllipsoidModel(PIEllipsoidModel::WGS84Ellipsoid()); g.setEllipsoidModel(PIEllipsoidModel::WGS84Ellipsoid());
g.transformTo(PIGeoPosition::Geodetic); g.transformTo(PIGeoPosition::Geodetic);
return PIString::fromNumber(g.latitudeGeodetic(), 'f', 8) + ", " + PIString::fromNumber(g.longitude(), 'f', 8) + ", " + return PIString::fromNumber(g.latitudeGeodetic(), 'f', 8) + ", " + PIString::fromNumber(g.longitude(), 'f', 8) + ", " +
PIString::fromNumber(g.height(), 'f', 2); PIString::fromNumber(g.height(), 'f', 2);
}; };
REGISTER_VARIANT_CAST(PIString, PIGeoPosition) { REGISTER_VARIANT_CAST(PIString, PIGeoPosition) {

View File

@@ -1,8 +1,9 @@
//! \file pivariantsimple.h /*! \file pivariantsimple.h
//! \ingroup Types * \ingroup Types
//! \~\brief * \brief
//! \~english Simple variant type * \~english Simple variant type
//! \~russian Простой вариативный тип * \~russian Простой вариативный тип
*/
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Variant simple type Variant simple type
@@ -177,27 +178,35 @@ private:
}; };
#define REGISTER_PIVARIANTSIMPLE(Type) \ #define REGISTER_PIVARIANTSIMPLE(Type) \
template<> \ template<> \
class __VariantFunctions__<Type>: public __VariantFunctionsBase__ { \ class __VariantFunctions__<Type>: public __VariantFunctionsBase__ { \
public: \ public: \
__VariantFunctionsBase__ * instance() final { \ __VariantFunctionsBase__ * instance() final { \
static __VariantFunctions__<Type> ret; \ static __VariantFunctions__<Type> ret; \
return &ret; \ return &ret; \
} \ } \
PIString typeName() const final { \ PIString typeName() const final { \
static PIString ret(#Type); \ static PIString ret(#Type); \
return ret; \ return ret; \
} \ } \
uint hash() const final { \ uint hash() const final { \
static uint ret = typeName().hash(); \ static uint ret = typeName().hash(); \
return ret; \ return ret; \
} \ } \
void newT(void *& ptr, const void * value) final { ptr = (void *)(new Type(*(const Type *)value)); } \ void newT(void *& ptr, const void * value) final { \
void newNullT(void *& ptr) final { ptr = (void *)(new Type()); } \ ptr = (void *)(new Type(*(const Type *)value)); \
void assignT(void *& ptr, const void * value) final { *(Type *)ptr = *(const Type *)value; } \ } \
void deleteT(void *& ptr) final { delete (Type *)(ptr); } \ void newNullT(void *& ptr) final { \
}; ptr = (void *)(new Type()); \
} \
void assignT(void *& ptr, const void * value) final { \
*(Type *)ptr = *(const Type *)value; \
} \
void deleteT(void *& ptr) final { \
delete (Type *)(ptr); \
} \
};
REGISTER_PIVARIANTSIMPLE(std::function<void(void *)>) REGISTER_PIVARIANTSIMPLE(std::function<void(void *)>)

View File

@@ -1,8 +1,9 @@
//! \file pivarianttypes.h /*! \file pivarianttypes.h
//! \ingroup Types * \ingroup Types
//! \~\brief * \brief
//! \~english Types for PIVariant * \~english Types for PIVariant
//! \~russian Типы для PIVariant * \~russian Типы для PIVariant
*/
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Variant types Variant types

View File

@@ -23,171 +23,82 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
//! \~english Units base classes
//! \~russian Базовые классы единиц измерения
//! \defgroup Units Units
//! \~\brief
//! \~english Unit conversions
//! \~russian Преобразование единиц измерения
//!
//! \~\details
//! \~english \section cmake_module_Units Building with CMake
//! \~russian \section cmake_module_Units Сборка с использованием CMake
//!
//! \~\code
//! find_package(PIP REQUIRED)
//! target_link_libraries([target] PIP)
//! \endcode
//!
//! \~english \par Common
//! \~russian \par Общее
//!
//! \~english
//! These files provides unit conversion framework.
//!
//! \~russian
//! Эти файлы обеспечивают фреймворк преобразования единиц.
//!
//! \~\authors
//! \~english
//! Ivan Pelipenko peri4ko@yandex.ru;
//! Andrey Bychkov work.a.b@yandex.ru;
//! \~russian
//! Иван Пелипенко peri4ko@yandex.ru;
//! Андрей Бычков work.a.b@yandex.ru;
//!
#ifndef PIUNITS_BASE_H #ifndef PIUNITS_BASE_H
#define PIUNITS_BASE_H #define PIUNITS_BASE_H
#include "pitranslator.h" #include "pitranslator.h"
//! \~english Macro to declare unit class beginning #define DECLARE_UNIT_CLASS_BEGIN(Name, StartIndex) \
//! \~russian Макрос для объявления начала класса единиц namespace PIUnits { \
#define DECLARE_UNIT_CLASS_BEGIN(Name, StartIndex) \ namespace Class { \
namespace PIUnits { \ class PIP_EXPORT Name \
namespace Class { \ : public Internal::ClassBase \
class PIP_EXPORT Name \ , public Internal::Registrator<Name> { \
: public Internal::ClassBase \ private: \
, public Internal::Registrator<Name> { \ friend class Internal::Registrator<Name>; \
private: \ constexpr static int typeStart = StartIndex; \
friend class Internal::Registrator<Name>; \ PIString name(int type) const override; \
constexpr static int typeStart = StartIndex; \ PIString unit(int type) const override; \
PIString name(int type) const override; \ PIString valueToString(double v, char format, int prec) const override; \
PIString unit(int type) const override; \ double convert(double v, int from, int to) const override; \
PIString valueToString(double v, char format, int prec) const override; \ bool supportPrefixes(int type) const override; \
double convert(double v, int from, int to) const override; \ bool supportPrefixesNon3(int type) const override; \
bool supportPrefixes(int type) const override; \ bool supportPrefixesGreater(int type) const override; \
bool supportPrefixesNon3(int type) const override; \ bool supportPrefixesSmaller(int type) const override; \
bool supportPrefixesGreater(int type) const override; \ \
bool supportPrefixesSmaller(int type) const override; \ public: \
\ PIString className() const override { \
public: \ return piTr(#Name, "PIUnits"); \
PIString className() const override { return piTr(#Name, "PIUnits"); } \ } \
uint classID() const override { \ uint classID() const override { \
static uint ret = PIStringAscii(#Name).hash(); \ static uint ret = PIStringAscii(#Name).hash(); \
return ret; \ return ret; \
} }
//! \~english Macro to declare unit class end #define DECLARE_UNIT_CLASS_END(Name) \
//! \~russian Макрос для объявления конца класса единиц } \
#define DECLARE_UNIT_CLASS_END(Name) \ ; \
} \ } \
; \ } \
} \ STATIC_INITIALIZER_BEGIN \
} \ PIUnits::Class::Name::registerSelf(); \
STATIC_INITIALIZER_BEGIN \ STATIC_INITIALIZER_END
PIUnits::Class::Name::registerSelf(); \
STATIC_INITIALIZER_END
namespace PIUnits { namespace PIUnits {
//! \~english Get class name for type
//! \~russian Получить имя класса для типа
PIP_EXPORT PIString className(int type); PIP_EXPORT PIString className(int type);
//! \~english Get unit name for type
//! \~russian Получить имя единицы для типа
PIP_EXPORT PIString name(int type); PIP_EXPORT PIString name(int type);
//! \~english Get unit symbol for type
//! \~russian Получить символ единицы для типа
PIP_EXPORT PIString unit(int type); PIP_EXPORT PIString unit(int type);
namespace Class { namespace Class {
//! \~english Invalid type marker
//! \~russian Маркер недопустимого типа
enum { enum {
Invalid = -1 Invalid = -1
}; };
//! \~english Internal namespace for unit classes implementation
//! \~russian Внутреннее пространство имен для реализации классов единиц
class PIP_EXPORT Internal { class PIP_EXPORT Internal {
public: public:
//! \~english Base class for all unit classes
//! \~russian Базовый класс для всех классов единиц
class PIP_EXPORT ClassBase { class PIP_EXPORT ClassBase {
public: public:
//! \~english Get class ID
//! \~russian Получить ID класса
virtual uint classID() const = 0; virtual uint classID() const = 0;
//! \~english Get class name
//! \~russian Получить имя класса
virtual PIString className() const = 0; virtual PIString className() const = 0;
//! \~english Get name for unit type
//! \~russian Получить имя для типа единицы
virtual PIString name(int type) const = 0; virtual PIString name(int type) const = 0;
//! \~english Get unit symbol for type
//! \~russian Получить символ единицы для типа
virtual PIString unit(int type) const = 0; virtual PIString unit(int type) const = 0;
//! \~english Convert value to string
//! \~russian Преобразовать значение в строку
virtual PIString valueToString(double v, char format = 'g', int prec = 5) const = 0; virtual PIString valueToString(double v, char format = 'g', int prec = 5) const = 0;
//! \~english Convert value between units
//! \~russian Преобразовать значение между единицами
virtual double convert(double v, int from, int to) const = 0; virtual double convert(double v, int from, int to) const = 0;
//! \~english Check if prefixes are supported
//! \~russian Проверить поддерживаются ли префиксы
virtual bool supportPrefixes(int type) const { return true; } virtual bool supportPrefixes(int type) const { return true; }
//! \~english Check if non-3 prefixes are supported
//! \~russian Проверить поддерживаются ли не-3 префиксы
virtual bool supportPrefixesNon3(int type) const { return false; } virtual bool supportPrefixesNon3(int type) const { return false; }
//! \~english Check if greater prefixes are supported
//! \~russian Проверить поддерживаются ли большие префиксы
virtual bool supportPrefixesGreater(int type) const { return true; } virtual bool supportPrefixesGreater(int type) const { return true; }
//! \~english Check if smaller prefixes are supported
//! \~russian Проверить поддерживаются ли меньшие префиксы
virtual bool supportPrefixesSmaller(int type) const { return true; } virtual bool supportPrefixesSmaller(int type) const { return true; }
//! \~english Get all available types
//! \~russian Получить все доступные типы
const PIVector<int> & allTypes() const { return types; } const PIVector<int> & allTypes() const { return types; }
protected: protected:
//! \~english List of types
//! \~russian Список типов
PIVector<int> types; PIVector<int> types;
}; };
//! \~english Template for self-registration of unit classes
//! \~russian Шаблон для саморегистрации классов единиц
template<typename P> template<typename P>
class Registrator { class Registrator {
public: public:
//! \~english Register unit class
//! \~russian Зарегистрировать класс единиц
static void registerSelf() { static void registerSelf() {
auto * uc = new P(); auto * uc = new P();
for (int t = P::typeStart; t < P::_LastType; ++t) { for (int t = P::typeStart; t < P::_LastType; ++t) {
@@ -197,25 +108,14 @@ public:
if (!Internal::allTypeClasses.contains(uc)) Internal::allTypeClasses << uc; if (!Internal::allTypeClasses.contains(uc)) Internal::allTypeClasses << uc;
} }
}; };
//! \~english Map of type to class instance
//! \~russian Карта типа к экземпляру класса
static PIMap<int, ClassBase *> typeClasses; static PIMap<int, ClassBase *> typeClasses;
//! \~english List of all registered classes
//! \~russian Список всех зарегистрированных классов
static PIVector<ClassBase *> allTypeClasses; static PIVector<ClassBase *> allTypeClasses;
//! \~english Unknown name placeholder
//! \~russian Заполнитель для неизвестного имени
static const PIString unknown; static const PIString unknown;
}; };
} // namespace Class } // namespace Class
//! \~english Get all registered unit classes
//! \~russian Получить все зарегистрированные классы единиц
PIP_EXPORT PIVector<Class::Internal::ClassBase *> allClasses(); PIP_EXPORT PIVector<Class::Internal::ClassBase *> allClasses();
} // namespace PIUnits } // namespace PIUnits

View File

@@ -1,5 +1,9 @@
//! \~english Unit prefixes /*! \file piunits_prefix.h
//! \~russian Префиксы единиц измерения * \ingroup Core
* \~\brief
* \~english Unit prefixes
* \~russian Префиксы единиц измерения
*/
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Unit prefix Unit prefix
@@ -26,59 +30,41 @@
namespace PIUnits { namespace PIUnits {
//! \~english Unit prefix class
//! \~russian Класс префикса единиц
class PIP_EXPORT Prefix { class PIP_EXPORT Prefix {
friend class Value; friend class Value;
public: public:
//! \~english Prefix values
//! \~russian Значения префиксов
enum { enum {
None, //!< No prefix None,
Deca = 0x100, //!< da 10^1 10 Deca = 0x100, // da 10^1 10
Hecto, //!< h 10^2 100 Hecto, // h 10^2 100
Kilo, //!< k 10^3 1000 Kilo, // k 10^3 1000
Mega, //!< M 10^6 1000000 Mega, // M 10^6 1000000
Giga, //!< G 10^9 1000000000 Giga, // G 10^9 1000000000
Tera, //!< T 10^12 1000000000000 Tera, // T 10^12 1000000000000
Peta, //!< P 10^15 1000000000000000 Peta, // P 10^15 1000000000000000
Exa, //!< E 10^18 1000000000000000000 Exa, // E 10^18 1000000000000000000
Zetta, //!< Z 10^21 1000000000000000000000 Zetta, // Z 10^21 1000000000000000000000
Yotta, //!< Y 10^24 1000000000000000000000000 Yotta, // Y 10^24 1000000000000000000000000
Ronna, //!< R 10^27 1000000000000000000000000000 Ronna, // R 10^27 1000000000000000000000000000
Quetta, //!< Q 10^30 1000000000000000000000000000000 Quetta, // Q 10^30 1000000000000000000000000000000
Deci = 0x200, //!< d 10^1 0.1 Deci = 0x200, // d 10^1 0.1
Centi, //!< c 10^2 0.01 Centi, // c 10^2 0.01
Milli, //!< m 10^3 0.001 Milli, // m 10^3 0.001
Micro, //!< μ 10^6 0.000001 Micro, // μ 10^6 0.000001
Nano, //!< n 10^9 0.000000001 Nano, // n 10^9 0.000000001
Pico, //!< p 10^12 0.000000000001 Pico, // p 10^12 0.000000000001
Femto, //!< f 10^15 0.000000000000001 Femto, // f 10^15 0.000000000000001
Atto, //!< a 10^18 0.000000000000000001 Atto, // a 10^18 0.000000000000000001
Zepto, //!< z 10^21 0.000000000000000000001 Zepto, // z 10^21 0.000000000000000000001
Yocto, //!< y 10^24 0.000000000000000000000001 Yocto, // y 10^24 0.000000000000000000000001
Ronto, //!< r 10^27 0.000000000000000000000000001 Ronto, // r 10^27 0.000000000000000000000000001
}; };
//! \~english Get prefix name
//! \~russian Получить имя префикса
//! \param prefix Prefix value
//! \return Prefix name
static PIString name(int prefix); static PIString name(int prefix);
//! \~english Get prefix symbol
//! \~russian Получить символ префикса
//! \param prefix Prefix value
//! \return Prefix symbol
static PIString prefix(int prefix); static PIString prefix(int prefix);
//! \~english Get multiplier for prefix
//! \~russian Получить множитель для префикса
//! \param prefix Prefix value
//! \return Multiplier value
static double multiplier(int prefix); static double multiplier(int prefix);
private: private:
@@ -87,8 +73,6 @@ private:
static Prefix & instance(); static Prefix & instance();
static PIString valueToString(double v, void * type_class, int type, char format = 'g', int prec = 5); static PIString valueToString(double v, void * type_class, int type, char format = 'g', int prec = 5);
//! \~english Prefix data structure
//! \~russian Структура данных префикса
struct P { struct P {
PIString name; PIString name;
PIString prefix; PIString prefix;
@@ -97,12 +81,7 @@ private:
bool non3; bool non3;
}; };
//! \~english Get prefix by value
//! \~russian Получить префикс по значению
const P getPrefix(int p) const; const P getPrefix(int p) const;
//! \~english Get prefix for value
//! \~russian Получить префикс для значения
const P getPrefixForValue(double v, bool use_non3, bool use_greater, bool use_smaller) const; const P getPrefixForValue(double v, bool use_non3, bool use_greater, bool use_smaller) const;
PIMap<int, P> prefixes; PIMap<int, P> prefixes;

View File

@@ -1,5 +1,9 @@
//! \~english Unit value class /*! \file piunits_value.h
//! \~russian Класс значения единицы * \ingroup Core
* \~\brief
* \~english Unit value
* \~russian Единица измерения
*/
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Unit value Unit value
@@ -27,67 +31,27 @@
namespace PIUnits { namespace PIUnits {
//! \~english Unit value representation
//! \~russian Представление значения единицы
class PIP_EXPORT Value { class PIP_EXPORT Value {
public: public:
//! \~english Constructor
//! \~russian Конструктор
//! \param v Value
//! \param t Unit type
Value(double v = 0., int t = Class::Invalid); Value(double v = 0., int t = Class::Invalid);
//! \~english Check if value is valid
//! \~russian Проверить значение на корректность
//! \return true if valid
bool isValid() const { return m_type >= 0 && m_class; } bool isValid() const { return m_type >= 0 && m_class; }
//! \~english Check if value is not valid
//! \~russian Проверить значение на некорректность
//! \return true if not valid
bool isNotValid() const { return m_type < 0 || !m_class; } bool isNotValid() const { return m_type < 0 || !m_class; }
//! \~english Get raw value
//! \~russian Получить сырое значение
double value() const { return m_value; } double value() const { return m_value; }
//! \~english Convert to string
//! \~russian Преобразовать в строку
//! \param format Format specifier
//! \param prec Precision
//! \return String representation
PIString toString(char format = 'g', int prec = 5) const; PIString toString(char format = 'g', int prec = 5) const;
//! \~english Convert to different unit type
//! \~russian Преобразовать в другой тип единицы
//! \param type_to Target unit type
//! \return true if successful
bool convert(int type_to); bool convert(int type_to);
//! \~english Get converted value
//! \~russian Получить преобразованное значение
//! \param type_to Target unit type
//! \return Converted value
Value converted(int type_to); Value converted(int type_to);
private: private:
//! \~english Numeric value double m_value = 0.;
//! \~russian Числовое значение int m_type = -1;
double m_value; Class::Internal::ClassBase * m_class = nullptr;
//! \~english Unit type
//! \~russian Тип единицы
int m_type;
//! \~english Class pointer
//! \~russian Указатель на класс
Class::Internal::ClassBase * m_class;
}; };
}; // namespace PIUnits }; // namespace PIUnits
//! \~english Output stream operator
//! \~russian Оператор вывода в поток
inline PICout operator<<(PICout s, const PIUnits::Value & v) { inline PICout operator<<(PICout s, const PIUnits::Value & v) {
s << v.toString(); s << v.toString();
return s; return s;

View File

@@ -379,6 +379,419 @@ TEST_F(Vector2DTest, addRow_with_shorter_vector_uses_min) {
} }
} }
// ==================== APPEND ROWS TESTS ====================
TEST_F(Vector2DTest, appendRows_adds_rows_at_bottom) {
size_t oldRows = vec.rows();
size_t oldCols = vec.cols();
vec.appendRows(5, 42);
EXPECT_EQ(vec.rows(), oldRows + 5);
EXPECT_EQ(vec.cols(), oldCols);
// Original data preserved
for (size_t r = 0; r < oldRows; ++r) {
for (size_t c = 0; c < oldCols; ++c) {
EXPECT_EQ(vec.element(r, c), static_cast<int>(r * COLS_COUNT_INIT + c));
}
}
// New rows filled with 42
for (size_t r = oldRows; r < vec.rows(); ++r) {
for (size_t c = 0; c < oldCols; ++c) {
EXPECT_EQ(vec.element(r, c), 42);
}
}
}
TEST_F(Vector2DTest, appendRows_with_zero_count_does_nothing) {
auto oldVec = vec;
vec.appendRows(0);
EXPECT_EQ(vec, oldVec);
}
TEST_F(Vector2DTest, appendRows_on_empty_matrix) {
PIVector2D<int> empty;
empty.appendRows(5, 99);
EXPECT_TRUE(empty.isNotEmpty());
EXPECT_EQ(empty.rows(), 5);
EXPECT_EQ(empty.cols(), 1);
EXPECT_EQ(empty.size(), empty.entries(99));
}
TEST_F(Vector2DTest, appendRows_with_default_value) {
size_t oldRows = vec.rows();
vec.appendRows(3);
for (size_t r = oldRows; r < vec.rows(); ++r) {
for (size_t c = 0; c < vec.cols(); ++c) {
EXPECT_EQ(vec.element(r, c), 0);
}
}
}
// ==================== APPEND COLUMNS TESTS ====================
TEST_F(Vector2DTest, appendColumns_adds_columns_at_right) {
size_t oldRows = vec.rows();
size_t oldCols = vec.cols();
vec.appendColumns(3, 99);
EXPECT_EQ(vec.rows(), oldRows);
EXPECT_EQ(vec.cols(), oldCols + 3);
// Original data preserved in original columns
for (size_t r = 0; r < oldRows; ++r) {
for (size_t c = 0; c < oldCols; ++c) {
EXPECT_EQ(vec.element(r, c), static_cast<int>(r * COLS_COUNT_INIT + c));
}
}
// New columns filled with 99
for (size_t r = 0; r < oldRows; ++r) {
for (size_t c = oldCols; c < vec.cols(); ++c) {
EXPECT_EQ(vec.element(r, c), 99);
}
}
}
TEST_F(Vector2DTest, appendColumns_with_zero_count_does_nothing) {
auto oldVec = vec;
vec.appendColumns(0);
EXPECT_EQ(vec, oldVec);
}
TEST_F(Vector2DTest, appendColumns_on_empty_matrix) {
PIVector2D<int> empty;
empty.appendColumns(5, 99);
EXPECT_TRUE(empty.isNotEmpty());
EXPECT_EQ(empty.cols(), 5);
EXPECT_EQ(empty.rows(), 1);
EXPECT_EQ(empty.size(), empty.entries(99));
}
TEST_F(Vector2DTest, appendColumns_single_column) {
auto oldVec = vec;
vec.appendColumns(1, 77);
EXPECT_EQ(vec.rows(), oldVec.rows());
EXPECT_EQ(vec.cols(), oldVec.cols() + 1);
// Check original data
for (size_t r = 0; r < vec.rows(); ++r) {
for (size_t c = 0; c < oldVec.cols(); ++c) {
EXPECT_EQ(vec.element(r, c), oldVec.element(r, c));
}
}
// Check new column
for (size_t r = 0; r < vec.rows(); ++r) {
EXPECT_EQ(vec.element(r, oldVec.cols()), 77);
}
}
// ==================== DELETE ROWS TESTS ====================
TEST_F(Vector2DTest, deleteRows_removes_rows_from_middle) {
size_t oldRows = vec.rows();
size_t oldCols = vec.cols();
vec.deleteRows(5, 3);
EXPECT_EQ(vec.rows(), oldRows - 3);
EXPECT_EQ(vec.cols(), oldCols);
// Rows before deleted remain
for (size_t r = 0; r < 5; ++r) {
for (size_t c = 0; c < oldCols; ++c) {
EXPECT_EQ(vec.element(r, c), static_cast<int>(r * COLS_COUNT_INIT + c));
}
}
// Rows after deleted shifted up
for (size_t r = 5; r < vec.rows(); ++r) {
for (size_t c = 0; c < oldCols; ++c) {
EXPECT_EQ(vec.element(r, c), static_cast<int>((r + 3) * COLS_COUNT_INIT + c));
}
}
}
TEST_F(Vector2DTest, deleteRows_at_end_works) {
size_t oldRows = vec.rows();
size_t oldCols = vec.cols();
vec.deleteRows(oldRows - 2, 2);
EXPECT_EQ(vec.rows(), oldRows - 2);
EXPECT_EQ(vec.cols(), oldCols);
// All remaining rows should have original content
for (size_t r = 0; r < vec.rows(); ++r) {
for (size_t c = 0; c < oldCols; ++c) {
EXPECT_EQ(vec.element(r, c), static_cast<int>(r * COLS_COUNT_INIT + c));
}
}
}
TEST_F(Vector2DTest, deleteRows_beyond_bounds_is_limited) {
size_t oldRows = vec.rows();
size_t oldCols = vec.cols();
size_t count = 10;
vec.deleteRows(oldRows - 2, count);
EXPECT_EQ(vec.rows(), oldRows - count);
EXPECT_EQ(vec.cols(), oldCols);
// All remaining rows should have original content
for (size_t r = 0; r < oldRows; ++r) {
for (size_t c = 0; c < vec.cols(); ++c) {
EXPECT_EQ(vec.element(r, c), static_cast<int>(r * COLS_COUNT_INIT + c));
}
}
// All new rows should have original content
for (size_t r = oldRows; r < vec.rows(); ++r) {
for (size_t c = 0; c < vec.cols(); ++c) {
EXPECT_EQ(vec.element(r, c), static_cast<int>((r+count) * COLS_COUNT_INIT + c));
}
}
}
TEST_F(Vector2DTest, deleteRows_invalid_start_does_nothing) {
auto oldVec = vec;
vec.deleteRows(oldVec.rows() + 10, 2);
EXPECT_EQ(vec, oldVec);
}
TEST_F(Vector2DTest, deleteRows_zero_count_does_nothing) {
auto oldVec = vec;
vec.deleteRows(5, 0);
EXPECT_EQ(vec, oldVec);
}
TEST_F(Vector2DTest, deleteRows_all_rows_creates_empty) {
vec.deleteRows(0, vec.rows());
EXPECT_TRUE(vec.isEmpty());
EXPECT_EQ(vec.rows(), 0);
EXPECT_EQ(vec.cols(), 0);
}
// ==================== DELETE COLUMNS TESTS ====================
TEST_F(Vector2DTest, deleteColumns_removes_columns_from_middle) {
size_t oldRows = vec.rows();
size_t oldCols = vec.cols();
vec.deleteColumns(4, 3);
EXPECT_EQ(vec.rows(), oldRows);
EXPECT_EQ(vec.cols(), oldCols - 3);
// Columns before deleted remain
for (size_t r = 0; r < oldRows; ++r) {
for (size_t c = 0; c < 4; ++c) {
EXPECT_EQ(vec.element(r, c), static_cast<int>(r * COLS_COUNT_INIT + c));
}
}
// Columns after deleted shifted left
for (size_t r = 0; r < oldRows; ++r) {
for (size_t c = 4; c < vec.cols(); ++c) {
EXPECT_EQ(vec.element(r, c), static_cast<int>(r * COLS_COUNT_INIT + c + 3));
}
}
}
TEST_F(Vector2DTest, deleteColumns_at_end_works) {
size_t oldRows = vec.rows();
size_t oldCols = vec.cols();
vec.deleteColumns(oldCols - 2, 2);
EXPECT_EQ(vec.rows(), oldRows);
EXPECT_EQ(vec.cols(), oldCols - 2);
// All remaining columns should have original content
for (size_t r = 0; r < oldRows; ++r) {
for (size_t c = 0; c < vec.cols(); ++c) {
EXPECT_EQ(vec.element(r, c), static_cast<int>(r * COLS_COUNT_INIT + c));
}
}
}
TEST_F(Vector2DTest, deleteColumns_beyond_bounds_is_limited) {
size_t oldRows = vec.rows();
size_t oldCols = vec.cols();
vec.deleteColumns(oldCols - 2, 10);
EXPECT_EQ(vec.rows(), oldRows);
EXPECT_EQ(vec.cols(), oldCols - 2);
}
TEST_F(Vector2DTest, deleteColumns_invalid_start_does_nothing) {
auto oldVec = vec;
vec.deleteColumns(oldVec.cols() + 10, 2);
EXPECT_EQ(vec, oldVec);
}
TEST_F(Vector2DTest, deleteColumns_zero_count_does_nothing) {
auto oldVec = vec;
vec.deleteColumns(5, 0);
EXPECT_EQ(vec, oldVec);
}
TEST_F(Vector2DTest, deleteColumns_all_columns_preserves_rows) {
vec.deleteColumns(0, vec.cols());
EXPECT_EQ(vec.rows(), ROWS_COUNT_INIT);
EXPECT_EQ(vec.cols(), 0);
EXPECT_EQ(vec.size(), 0);
}
// ==================== ADD COLUMN TESTS ====================
TEST_F(Vector2DTest, addColumn_appends_column_to_empty) {
PIVector2D<int> empty;
PIVector<int> newCol(5);
for (size_t i = 0; i < 5; ++i)
newCol[i] = static_cast<int>(100 + i);
empty.addColumn(newCol);
EXPECT_EQ(empty.rows(), 5);
EXPECT_EQ(empty.cols(), 1);
for (size_t r = 0; r < 5; ++r) {
EXPECT_EQ(empty.element(r, 0), static_cast<int>(100 + r));
}
}
TEST_F(Vector2DTest, addColumn_appends_column_to_existing) {
size_t oldRows = vec.rows();
size_t oldCols = vec.cols();
PIVector<int> newCol(oldRows, [](size_t i){return -900 - (int)i;});
vec.addColumn(newCol);
EXPECT_EQ(vec.rows(), oldRows);
EXPECT_EQ(vec.cols(), oldCols + 1);
// Check that old data is preserved
for (size_t r = 0; r < oldRows; ++r) {
for (size_t c = 0; c < oldCols; ++c) {
EXPECT_EQ(vec.element(r, c), static_cast<int>(r * COLS_COUNT_INIT + c));
}
}
// Check new column
for (size_t r = 0; r < oldRows; ++r) {
EXPECT_EQ(vec.element(r, oldCols), -900 - (int)r);
}
}
TEST_F(Vector2DTest, addColumn_with_shorter_vector_uses_min) {
size_t oldRows = vec.rows();
size_t oldCols = vec.cols();
size_t shortLen = oldRows - 10;
PIVector<int> shortCol(shortLen, 777);
vec.addColumn(shortCol);
EXPECT_EQ(vec.cols(), oldCols + 1);
// First shortLen rows should be 777
for (size_t r = 0; r < shortLen; ++r) {
EXPECT_EQ(vec.element(r, oldCols), 777);
}
// Remaining rows should be default-initialized (0)
for (size_t r = shortLen; r < oldRows; ++r) {
EXPECT_EQ(vec.element(r, oldCols), 0);
}
}
TEST_F(Vector2DTest, addColumn_with_longer_vector_truncates) {
size_t oldRows = vec.rows();
size_t oldCols = vec.cols();
size_t longLen = oldRows + 10;
PIVector<int> longCol(longLen, 555);
vec.addColumn(longCol);
EXPECT_EQ(vec.cols(), oldCols + 1);
// All rows should be 555 (only first oldRows elements are used)
for (size_t r = 0; r < oldRows; ++r) {
EXPECT_EQ(vec.element(r, oldCols), 555);
}
}
TEST_F(Vector2DTest, addColumn_with_empty_source_does_nothing_on_empty) {
PIVector2D<int> empty;
PIVector<int> emptyCol;
empty.addColumn(emptyCol);
EXPECT_TRUE(empty.isEmpty());
EXPECT_EQ(empty.rows(), 0);
EXPECT_EQ(empty.cols(), 0);
}
TEST_F(Vector2DTest, addColumn_with_empty_source_adds_default_column) {
auto oldVec = vec;
vec.addColumn({});
EXPECT_EQ(vec.cols(), oldVec.cols());
EXPECT_EQ(vec.rows(), oldVec.rows());
for (size_t r = 0; r < oldVec.rows(); ++r) {
for (size_t c = 0; c < oldVec.cols(); ++c) {
EXPECT_EQ(vec.element(r, c), oldVec.element(r, c));
}
}
}
TEST_F(Vector2DTest, addColumn_with_Col_proxy_works) {
auto oldVec = vec;
const size_t colIndex = 5;
auto srcCol = oldVec.col(colIndex);
vec.addColumn(srcCol);
EXPECT_EQ(vec.cols(), oldVec.cols() + 1);
EXPECT_EQ(vec.rows(), oldVec.rows());
for (size_t r = 0; r < oldVec.rows(); ++r) {
for (size_t c = 0; c < oldVec.cols(); ++c) {
EXPECT_EQ(vec.element(r, c), oldVec.element(r, c));
}
}
for (size_t r = 0; r < vec.rows(); ++r) {
// EXPECT_EQ(vec.element(r, oldVec.cols()), int());
EXPECT_EQ(vec.element(r, oldVec.cols()), oldVec.element(r, colIndex));
}
}
TEST_F(Vector2DTest, addColumn_with_ColConst_proxy_works) {
size_t oldRows = vec.rows();
size_t oldCols = vec.cols();
const auto & constVec = vec;
auto srcCol = constVec.col(7);
// Need a non-const array to add to
PIVector2D<int> mutableVec = vec; // copy
mutableVec.addColumn(srcCol);
EXPECT_EQ(mutableVec.cols(), oldCols + 1);
for (size_t r = 0; r < oldRows; ++r) {
EXPECT_EQ(mutableVec.element(r, oldCols), vec.element(r, 7));
}
}
// ==================== RESIZE TESTS ==================== // ==================== RESIZE TESTS ====================
class Vector2DResizeTest: public Vector2DTest { class Vector2DResizeTest: public Vector2DTest {
protected: protected:
@@ -470,17 +883,15 @@ TEST_F(Vector2DTest, contains_finds_element_in_flat_vector) {
TEST_F(Vector2DTest, contains_with_start_parameter_works) { TEST_F(Vector2DTest, contains_with_start_parameter_works) {
int target = 10 * COLS_COUNT_INIT + 15; int target = 10 * COLS_COUNT_INIT + 15;
EXPECT_TRUE(vec.contains(target)); EXPECT_TRUE(vec.contains(target));
EXPECT_TRUE(vec.contains(target, target)); // start exactly at target (inclusive)
EXPECT_FALSE(vec.contains(target, target + 1)); // start after target
} }
TEST_F(Vector2DTest, contains_vector_of_elements_works) { TEST_F(Vector2DTest, contains_vector_of_elements_works) {
PIVector<int> searchFor; PIVector<int> searchFor;
searchFor << 100 << 200 << 300; searchFor << 100 << 200 << 300;
EXPECT_TRUE(vec.contains(searchFor)); EXPECT_TRUE(vec.asPlainVector().containsAll(searchFor));
searchFor << -999; searchFor << -999;
EXPECT_FALSE(vec.contains(searchFor)); EXPECT_FALSE(vec.asPlainVector().containsAll(searchFor));
} }
TEST_F(Vector2DTest, entries_counts_occurrences) { TEST_F(Vector2DTest, entries_counts_occurrences) {
@@ -652,6 +1063,53 @@ TEST_F(Vector2DTest, transposed_returns_correct_dimensions) {
} }
} }
TEST(Vector2DTransposeTest, emptyMatrix_returnsEmpty) {
PIVector2D<int> empty;
auto transposed = empty.transposed();
EXPECT_TRUE(transposed.isEmpty());
EXPECT_EQ(transposed.rows(), 0);
EXPECT_EQ(transposed.cols(), 0);
}
TEST(Vector2DTransposeTest, singleElement_returnsSame) {
PIVector2D<int> single(1, 1, 42);
auto transposed = single.transposed();
EXPECT_EQ(transposed.rows(), 1);
EXPECT_EQ(transposed.cols(), 1);
EXPECT_EQ(transposed.element(0, 0), 42);
}
TEST(Vector2DTransposeTest, oneRow_becomesOneColumn) {
PIVector2D<int> rowVec(1, 5);
for (size_t c = 0; c < 5; ++c)
rowVec.element(0, c) = static_cast<int>(c);
auto transposed = rowVec.transposed();
EXPECT_EQ(transposed.rows(), 5);
EXPECT_EQ(transposed.cols(), 1);
for (size_t r = 0; r < 5; ++r) {
EXPECT_EQ(transposed.element(r, 0), static_cast<int>(r));
}
}
TEST(Vector2DTransposeTest, oneColumn_becomesOneRow) {
PIVector2D<int> colVec(5, 1);
for (size_t r = 0; r < 5; ++r)
colVec.element(r, 0) = static_cast<int>(r);
auto transposed = colVec.transposed();
EXPECT_EQ(transposed.rows(), 1);
EXPECT_EQ(transposed.cols(), 5);
for (size_t c = 0; c < 5; ++c) {
EXPECT_EQ(transposed.element(0, c), static_cast<int>(c));
}
}
TEST_F(Vector2DTest, transposed_doesNotModifyOriginal) {
auto original = vec; // копия для сравнения
auto transposed = vec.transposed();
// Проверяем, что исходный массив не изменился
EXPECT_EQ(vec, original);
}
TEST_F(Vector2DTest, reverseRows_reverses_row_order) { TEST_F(Vector2DTest, reverseRows_reverses_row_order) {
auto original = vec; auto original = vec;
vec.reverseRows(); vec.reverseRows();
@@ -767,36 +1225,36 @@ TEST_F(Vector2DTest, forEach_modifying_changes_elements) {
TEST_F(Vector2DTest, indexOf_returns_correct_pair) { TEST_F(Vector2DTest, indexOf_returns_correct_pair) {
auto p = vec.indexOf(vec.element(10, 15)); auto p = vec.indexOf(vec.element(10, 15));
EXPECT_EQ(p.first, 10); EXPECT_EQ(p.row, 10);
EXPECT_EQ(p.second, 15); EXPECT_EQ(p.col, 15);
p = vec.indexOf(-999); p = vec.indexOf(-999);
EXPECT_EQ(p.first, -1); EXPECT_EQ(p.row, -1);
EXPECT_EQ(p.second, -1); EXPECT_EQ(p.col, -1);
} }
TEST_F(Vector2DTest, indexWhere_returns_correct_pair) { TEST_F(Vector2DTest, indexWhere_returns_correct_pair) {
vec.element(5, 5) = -42; vec.element(5, 5) = -42;
auto isTarget = [](const int & e) { return e == -42; }; auto isTarget = [](const int & e) { return e == -42; };
auto p = vec.indexWhere(isTarget); auto p = vec.indexWhere(isTarget);
EXPECT_EQ(p.first, 5); EXPECT_EQ(p.row, 5);
EXPECT_EQ(p.second, 5); EXPECT_EQ(p.col, 5);
} }
TEST_F(Vector2DTest, lastIndexOf_works) { TEST_F(Vector2DTest, lastIndexOf_works) {
int val = vec.element(10, 10); int val = vec.element(10, 10);
vec.element(20, 20) = val; // duplicate vec.element(20, 20) = val; // duplicate
auto p = vec.lastIndexOf(val); auto p = vec.lastIndexOf(val);
EXPECT_EQ(p.first, 20); EXPECT_EQ(p.row, 20);
EXPECT_EQ(p.second, 20); EXPECT_EQ(p.col, 20);
} }
TEST_F(Vector2DTest, lastIndexWhere_works) { TEST_F(Vector2DTest, lastIndexWhere_works) {
auto isLarge = [](const int & e) { return e > 500; }; auto isLarge = [](const int & e) { return e > 500; };
auto p = vec.lastIndexWhere(isLarge); auto p = vec.lastIndexWhere(isLarge);
EXPECT_GE(p.first, 0); EXPECT_GE(p.row, 0);
EXPECT_GE(p.second, 0); EXPECT_GE(p.col, 0);
// The last element with value >500 should be the largest index // The last element with value >500 should be the largest index
size_t lastFlat = p.first * vec.cols() + p.second; size_t lastFlat = p.row * vec.cols() + p.col;
size_t expectedLastFlat = vec.size() - 1; size_t expectedLastFlat = vec.size() - 1;
EXPECT_EQ(lastFlat, expectedLastFlat); EXPECT_EQ(lastFlat, expectedLastFlat);
} }
@@ -993,6 +1451,242 @@ TEST(Vector2DEdgeTest, single_element_vector) {
EXPECT_EQ(single.element(0, 0), 42); EXPECT_EQ(single.element(0, 0), 42);
} }
// ==================== PROXY ADDITIONAL OPERATIONS TESTS ====================
TEST_F(Vector2DTest, row_proxy_forEach_modifies_elements) {
auto row = vec[5];
row.forEach([](int & e) { e += 100; });
for (size_t c = 0; c < COLS_COUNT_INIT; ++c) {
EXPECT_EQ(vec.element(5, c), 5 * COLS_COUNT_INIT + c + 100);
}
}
TEST_F(Vector2DTest, row_proxy_forEach_const_iterates) {
const auto & constVec = vec;
auto row = constVec[5];
size_t count = 0;
row.forEach([&count](const int &) { ++count; });
EXPECT_EQ(count, COLS_COUNT_INIT);
}
TEST_F(Vector2DTest, row_proxy_fill_sets_all_elements) {
auto row = vec[12];
row.fill(999);
for (size_t c = 0; c < COLS_COUNT_INIT; ++c) {
EXPECT_EQ(vec.element(12, c), 999);
}
}
TEST_F(Vector2DTest, row_proxy_contains_finds_element) {
auto row = vec[8];
EXPECT_TRUE(row.contains(vec.element(8, 10)));
EXPECT_FALSE(row.contains(-999));
}
TEST_F(Vector2DTest, row_proxy_entries_counts_occurrences) {
auto row = vec[15];
// Add a duplicate
int val = vec.element(15, 5);
vec.element(15, 20) = val;
EXPECT_EQ(row.entries(val), 2);
EXPECT_EQ(row.entries(-999), 0);
}
TEST_F(Vector2DTest, row_proxy_entries_with_predicate_counts_matches) {
auto row = vec[20];
auto isEven = [](const int & e) { return e % 2 == 0; };
int expected = 0;
for (size_t c = 0; c < COLS_COUNT_INIT; ++c) {
if (row[c] % 2 == 0) ++expected;
}
EXPECT_EQ(row.entries(isEven), expected);
}
TEST_F(Vector2DTest, row_proxy_any_returns_true_if_any_match) {
auto row = vec[25];
auto isNegative = [](const int & e) { return e < 0; };
EXPECT_FALSE(row.any(isNegative));
auto isPositive = [](const int & e) { return e >= 0; };
EXPECT_TRUE(row.any(isPositive));
}
TEST_F(Vector2DTest, row_proxy_every_returns_true_if_all_match) {
auto row = vec[30];
auto isLessThanMax = [&](const int & e) { return e < static_cast<int>(vec.size()); };
EXPECT_TRUE(row.every(isLessThanMax));
auto isEven = [](const int & e) { return e % 2 == 0; };
EXPECT_FALSE(row.every(isEven));
}
// ----------------------------------------------------------------------------
TEST_F(Vector2DTest, col_proxy_forEach_modifies_elements) {
auto col = vec.col(7);
col.forEach([](int & e) { e += 50; });
for (size_t r = 0; r < ROWS_COUNT_INIT; ++r) {
EXPECT_EQ(vec.element(r, 7), r * COLS_COUNT_INIT + 7 + 50);
}
}
TEST_F(Vector2DTest, col_proxy_forEach_const_iterates) {
const auto & constVec = vec;
auto col = constVec.col(9);
size_t count = 0;
col.forEach([&count](const int &) { ++count; });
EXPECT_EQ(count, ROWS_COUNT_INIT);
}
TEST_F(Vector2DTest, col_proxy_fill_sets_all_elements) {
auto col = vec.col(11);
col.fill(777);
for (size_t r = 0; r < ROWS_COUNT_INIT; ++r) {
EXPECT_EQ(vec.element(r, 11), 777);
}
}
TEST_F(Vector2DTest, col_proxy_contains_finds_element) {
auto col = vec.col(13);
EXPECT_TRUE(col.contains(vec.element(5, 13)));
EXPECT_FALSE(col.contains(-999));
}
TEST_F(Vector2DTest, col_proxy_entries_counts_occurrences) {
auto col = vec.col(17);
int val = vec.element(3, 17);
vec.element(22, 17) = val; // duplicate
EXPECT_EQ(col.entries(val), 2);
EXPECT_EQ(col.entries(-999), 0);
}
TEST_F(Vector2DTest, col_proxy_entries_with_predicate_counts_matches) {
auto col = vec.col(19);
auto isOdd = [](const int & e) { return e % 2 != 0; };
int expected = 0;
for (size_t r = 0; r < ROWS_COUNT_INIT; ++r) {
if (col[r] % 2 != 0) ++expected;
}
EXPECT_EQ(col.entries(isOdd), expected);
}
TEST_F(Vector2DTest, col_proxy_any_returns_true_if_any_match) {
auto col = vec.col(21);
auto isNegative = [](const int & e) { return e < 0; };
EXPECT_FALSE(col.any(isNegative));
auto isPositive = [](const int & e) { return e >= 0; };
EXPECT_TRUE(col.any(isPositive));
}
TEST_F(Vector2DTest, col_proxy_every_returns_true_if_all_match) {
auto col = vec.col(23);
auto isLessThanMax = [&](const int & e) { return e < static_cast<int>(vec.size()); };
EXPECT_TRUE(col.every(isLessThanMax));
auto isEven = [](const int & e) { return e % 2 == 0; };
EXPECT_FALSE(col.every(isEven));
}
// ----------------------------------------------------------------------------
TEST_F(Vector2DTest, rowconst_proxy_forEach_iterates) {
const auto & constVec = vec;
auto row = constVec[5];
size_t count = 0;
row.forEach([&count](const int &) { ++count; });
EXPECT_EQ(count, COLS_COUNT_INIT);
}
TEST_F(Vector2DTest, rowconst_proxy_contains_finds_element) {
const auto & constVec = vec;
auto row = constVec[6];
EXPECT_TRUE(row.contains(vec.element(6, 10)));
EXPECT_FALSE(row.contains(-999));
}
TEST_F(Vector2DTest, rowconst_proxy_entries_counts_occurrences) {
const auto & constVec = vec;
auto row = constVec[7];
int val = vec.element(7, 5);
// We can't modify through const proxy, but duplicates already exist from previous tests
EXPECT_GE(row.entries(val), 1); // at least one
}
TEST_F(Vector2DTest, rowconst_proxy_entries_with_predicate_counts_matches) {
const auto & constVec = vec;
auto row = constVec[9];
auto isEven = [](const int & e) { return e % 2 == 0; };
int expected = 0;
for (size_t c = 0; c < COLS_COUNT_INIT; ++c) {
if (vec.element(9, c) % 2 == 0) ++expected;
}
EXPECT_EQ(row.entries(isEven), expected);
}
TEST_F(Vector2DTest, rowconst_proxy_any_returns_true_if_any_match) {
const auto & constVec = vec;
auto row = constVec[10];
auto isNegative = [](const int & e) { return e < 0; };
EXPECT_FALSE(row.any(isNegative));
auto isPositive = [](const int & e) { return e >= 0; };
EXPECT_TRUE(row.any(isPositive));
}
TEST_F(Vector2DTest, rowconst_proxy_every_returns_true_if_all_match) {
const auto & constVec = vec;
auto row = constVec[11];
auto isLessThanMax = [&](const int & e) { return e < static_cast<int>(vec.size()); };
EXPECT_TRUE(row.every(isLessThanMax));
auto isEven = [](const int & e) { return e % 2 == 0; };
EXPECT_FALSE(row.every(isEven));
}
// ----------------------------------------------------------------------------
TEST_F(Vector2DTest, colconst_proxy_forEach_iterates) {
const auto & constVec = vec;
auto col = constVec.col(25);
size_t count = 0;
col.forEach([&count](const int &) { ++count; });
EXPECT_EQ(count, ROWS_COUNT_INIT);
}
TEST_F(Vector2DTest, colconst_proxy_contains_finds_element) {
const auto & constVec = vec;
auto col = constVec.col(27);
EXPECT_TRUE(col.contains(vec.element(4, 27)));
EXPECT_FALSE(col.contains(-999));
}
TEST_F(Vector2DTest, colconst_proxy_entries_counts_occurrences) {
const auto & constVec = vec;
auto col = constVec.col(29);
int val = vec.element(8, 29);
EXPECT_GE(col.entries(val), 1);
}
TEST_F(Vector2DTest, colconst_proxy_entries_with_predicate_counts_matches) {
const auto & constVec = vec;
auto col = constVec.col(31);
auto isOdd = [](const int & e) { return e % 2 != 0; };
int expected = 0;
for (size_t r = 0; r < ROWS_COUNT_INIT; ++r) {
if (vec.element(r, 31) % 2 != 0) ++expected;
}
EXPECT_EQ(col.entries(isOdd), expected);
}
TEST_F(Vector2DTest, colconst_proxy_any_returns_true_if_any_match) {
const auto & constVec = vec;
auto col = constVec.col(33);
auto isNegative = [](const int & e) { return e < 0; };
EXPECT_FALSE(col.any(isNegative));
auto isPositive = [](const int & e) { return e >= 0; };
EXPECT_TRUE(col.any(isPositive));
}
TEST_F(Vector2DTest, colconst_proxy_every_returns_true_if_all_match) {
const auto & constVec = vec;
auto col = constVec.col(0);
auto isLessThanMax = [&](const int & e) { return e < static_cast<int>(vec.size()); };
EXPECT_TRUE(col.every(isLessThanMax));
auto isNotEven = [](const int & e) { return e % 2 != 0; };
EXPECT_FALSE(col.every(isNotEven));
}
// ==================== OUTPUT TESTS ==================== // ==================== OUTPUT TESTS ====================
TEST_F(Vector2DTest, picout_operator_works) { TEST_F(Vector2DTest, picout_operator_works) {
// Just test that it compiles and doesn't crash // Just test that it compiles and doesn't crash
@@ -1010,3 +1704,94 @@ TEST_F(Vector2DTest, iostream_operator_works) {
// No assertion, just ensure it runs // No assertion, just ensure it runs
} }
#endif #endif
// ==================== INDEX STRUCTURE ACCESS TESTS ====================
TEST_F(Vector2DTest, operator_bracket_with_index_allows_read_access) {
PIVector2D<int>::Index idx = {5, 7};
int value = vec[idx];
int expected = vec.element(5, 7);
EXPECT_EQ(value, expected);
}
TEST_F(Vector2DTest, operator_bracket_with_index_allows_write_access) {
PIVector2D<int>::Index idx = {10, 15};
vec[idx] = 999;
EXPECT_EQ(vec.element(10, 15), 999);
}
TEST_F(Vector2DTest, operator_bracket_with_const_index_works) {
const auto & constVec = vec;
PIVector2D<int>::Index idx = {3, 12};
int value = constVec[idx];
int expected = vec.element(3, 12);
EXPECT_EQ(value, expected);
}
TEST_F(Vector2DTest, element_function_with_index_works) {
PIVector2D<int>::Index idx = {8, 20};
int value = vec.element(idx);
int expected = vec.element(8, 20);
EXPECT_EQ(value, expected);
}
TEST_F(Vector2DTest, element_function_with_index_modifies_value) {
PIVector2D<int>::Index idx = {12, 8};
vec.element(idx) = 555;
EXPECT_EQ(vec.element(12, 8), 555);
}
TEST_F(Vector2DTest, element_function_with_const_index_works) {
const auto & constVec = vec;
PIVector2D<int>::Index idx = {7, 5};
int value = constVec.element(idx);
int expected = vec.element(7, 5);
EXPECT_EQ(value, expected);
}
TEST_F(Vector2DTest, at_function_with_index_works) {
PIVector2D<int>::Index idx = {4, 11};
int value = vec.at(idx);
int expected = vec.at(4, 11);
EXPECT_EQ(value, expected);
}
TEST_F(Vector2DTest, index_structure_with_brace_initialization_works) {
vec[{0, 0}] = 100;
EXPECT_EQ(vec.element(0, 0), 100);
vec[{static_cast<ssize_t>(ROWS_COUNT_INIT - 1), static_cast<ssize_t>(COLS_COUNT_INIT - 1)}] = 200;
EXPECT_EQ(vec.element(ROWS_COUNT_INIT - 1, COLS_COUNT_INIT - 1), 200);
}
TEST(Vector2DIndexTest, default_constructor_initializes_to_invalid) {
PIVector2D<int>::Index idx;
EXPECT_TRUE(idx.isNotValid());
EXPECT_FALSE(idx.isValid());
EXPECT_EQ(idx.row, -1);
EXPECT_EQ(idx.col, -1);
}
TEST(Vector2DIndexTest, parameterized_constructor_initializes_correctly) {
PIVector2D<int>::Index idx(5, 10);
EXPECT_TRUE(idx.isValid());
EXPECT_FALSE(idx.isNotValid());
EXPECT_EQ(idx.row, 5);
EXPECT_EQ(idx.col, 10);
}
TEST(Vector2DIndexTest, isValid_returns_true_for_non_negative_values) {
PIVector2D<int>::Index idx(0, 0);
EXPECT_TRUE(idx.isValid());
EXPECT_FALSE(idx.isNotValid());
}
TEST(Vector2DIndexTest, isNotValid_returns_true_for_negative_values) {
PIVector2D<int>::Index idx1;
EXPECT_TRUE(idx1.isNotValid());
PIVector2D<int>::Index idx2(-1, 5);
EXPECT_TRUE(idx2.isNotValid());
PIVector2D<int>::Index idx3(5, -1);
EXPECT_TRUE(idx3.isNotValid());
}