- Журнал изменений в версиях системы Papyrus
- PAPYRUS (Демо)
- Papyrus: development
- ppd-chapter-000
- Введение #2
- Инструментарий
- Сборка проекта
- Code style
- Общие функции
- Базовые типы данных
- Базовые структуры данных
- Базовые алгоритмы
- Управление строковыми ресурсами
- Контроллеры анализа данных (классы семейства PPView)
- Соображения по вопросу неотрицательности товарных остатков
- Котировки
- Модель объемной оптимизации товарных запасов
- Проект SARTR
- Протокол взаимодействия
- Зарезервированные объекты
- Регламентированные задания
- Papyrus: возможности системы
- Papyrus: руководство пользователя
- Библиотека
- Все об обязательной маркировке 2021
- Все об онлайн-кассах
- Презентации
- Руководства
- Свидетельство о регистрации системы Papyrus
- Технологии и функции
Базовые типы данных
Начнем обсуждение разработки с обзора используемых типов данных. В этой главе мы сосредоточимся на базовых или элементарных типах, которые применяются как самостоятельно, так и в составе более сложных структур.
Целочисленные типы
Наиболее простыми и популярными в использовании являются целочисленные типы данных.
Классификация
Целочисленные типы классифицируются по следующим двум критериям:
- Длина
- Измеряется в байтах или битах. Типичными вариантами могут быть следующие:
Какие целочисленные типы мы используем
Исходя из приведенной классификации, мы можем оперировать набором из 8 целочисленных типов. В действительности их получается несколько больше из-за того, что некоторые такие типы данных дублируются (по разным причинам, от исторических до нюансов восприятия).Мы здесь перечислим те типы которыми будем пользоваться и приведем особенности их применения:
- char
- Стандарт. Знаковое целое число размером 1 байт. Размер не гарантируется. Используется для представления символов в мультибайтовых строках.
- uchar
- Беззнаковое целое число размером 1 байт. Размер не гарантируется.
- wchar_t
- Условный стандарт (зависит от компилятора). Знаковое целое число размером 2 байта. Размер не гарантируется. Используется для представления символов в unicode-строках.
- short
- Стандарт. Знаковое целое число размером 2 байта. Размер не гарантируется.
- ushort
- Беззнаковое целое число размером 2 байта. Размер не гарантируется.
- int
- Стандарт. Знаковое целое число размером 4 байта. Размер не гарантируется. Наиболее часто используемый целочисленный тип. Главный недостаток - отсутствие гарантии размера. По этому для хранимых (persistent) структур применять не рекомендуется, вместо него в этих случаях следует использовать int32.
- uint
- Беззнаковое целое число размером 4 байта. Размер не гарантируется. Чаще всего используется в качестве целочисленного счетчика, поскольку в этом качестве процессором обрабатывается несколько оптимальнее, чем int.
- long
- Знаковое целое число размером 4 байта. Размер не гарантируется. Для 32-битных архитектур аналогичен int.
- ulong
- Беззнаковое целое число размером 4 байта. Размер не гарантируется.
- int8
- Знаковое целое число размером 1 байт. Размер гарантируется.
- uint8
- Беззнаковое целое число размером 1 байт. Размер гарантируется.
- int16
- Знаковое целое число размером 2 байта. Размер гарантируется.
- uint16
- Беззнаковое целое число размером 2 байта. Размер гарантируется.
- int32
- Знаковое целое число размером 4 байта. Размер гарантируется.
- uint32
- Беззнаковое целое число размером 4 байта. Размер гарантируется.
- int64
- Знаковое целое число размером 8 байт. Размер гарантируется.
- uint64
- Беззнаковое целое число размером 8 байт. Размер гарантируется.
- size_t
- Стандарт. Беззнаковое целое число, используемое для представления размера участка памяти.
- ssize_t
- Знаковое целое число, используемое для представления размера участка памяти. Часто применяется для представления результата вычитания одного адреса из другого (если уменьшаемое меньше вычитаемого, то результат будет отрицательным, что неприемлемо для стандартного типа size_t).
Общие подходы к выбору целочисленного типа в конкретных ситуациях
При выборе целочисленного типа мы руководствуемся следующими соображениями:
for(uint i = 0; i < list.getCount(); i++) { // ... }
for(int i = list.getCount()-1; i >= 0; i--) { // ... }Однако, вместо цикла for в таких случаях правильнее использовать if() do { } while. Например:
uint i = list.getCount(); if(i) do { type & r_item = list.at(--i); // Обратите внимание на префиксный декремент } while(i);
struct Entry { // @persistent int32 Ident; int16 Flags; uint8 F2; uint8 F3; };
struct Entry { // @persistent int32 Ident; int16 Flags; uint8 Reserve[2]; // @alignment Выравнивает предыдущее поле по границе 4 байт. double R; };
void foo() { size_t data_size = sizeof(some_value); // Так правильно } struct SomeStruc { int Ident; size_t S; // ! Так нельзя. Используйте либо uint, uint32 либо uint64. double R; };
Включенный файл stdint.h
Основной каталог с include-файлами src/include содержит файл stdint.h. Это сделано для того, чтобы упростить сборку внешних компонентов, импортированных из мира open-source.Аспекты переносимости
Здесь мы приведем несколько замечаний, касающихся переносимости данных между различными аппаратными платформами, операционными системами и языками программирования.
Порядок следования байтов
Разные процессорные архитектуры могут использовать разные соглашения о порядке следования байтов в двух- и четырех-байтовых целых числах.Существует два случая:
- little-endian
- big-endian
Бинарная совместимость с другими языками программирования
При необходимости обмена бинарными данными между приложениями написанных на разных языках программирования может оказаться существенным выбор типов данных.
“Плоские” байтовые отрезки фиксированной длины
Для операций с бинарными отрезками фиксированной длины, которые не должны трактоваться как целочисленные переменным, используется шаблонизированный тип
templateclass TSBinary;
Самое очевидное применение таких отрезков: результаты работы хэш-функций. Собственно, в рамках нашей работы, они пока только для этого и используются.Несколько предопределенных типов в парадигме TSBinary:
typedef TSBinary <16> binary128; typedef TSBinary <20> binary160; typedef TSBinary <32> binary256; typedef TSBinary <64> binary512;
Типы для представления нецелых чисел
Классификация
Форматы данных для представления нецелых чисел будем классифицировать по следующим критериям:
- По признаку плавающей точки
- Дробное число можно представить либо с фиксированной десятичной точкой, либо с плавающей. В первом случае, формат хранения неявно предполагает позицию десятичной точки, представляя при этом число фактически в целочисленном виде. Все операции с такими числами учитывают положение десятичной точки. Для этого вида представления применяются либо, так называемые, двоично-десятичные форматы, либо целочисленные типы, с неявным определением положения точки. Во втором случае формат содержит информацию о положении десятичной точки. Такое представление описывается семейством стандартов IEEE 754.
- По длине
- Числа с плавающей точкой (IEEE 754) могут иметь длину 4 или 8 байт. Двоично-десятичные числа с фиксированной точкой могут иметь, вообще говоря, произвольную длину от 2 байт. Однако, в наших проектах мы чаще всего применяем 8-байтовые величины. Для чисел с фиксированной точкой в целочисленном формате мы обычно используем 4-байтовые целые (int32), с другой стороны, здесь так же нет ограничения для применения 1-, 2-, 8-байтовых целых типов (int8, int16, int64).
Дата и время
Дата
В библиотеке SLIB определен специальный тип LDATE, содержащий бинарное представление даты и необходимые методы для работы с ней.Вот иллюстрация бинарной структуры типа LDATE:
uint16 Year; uint8 Month; uint8 Day;Таким образом, видно, что формат занимает 4 байта и использует структурированное представление даты. Альтернативным для структурированного, является представление, при котором дата хранится как количество дней, прошедших с какой-то фиксированной даты.
Специальные значения даты
Значение ZERODATE содержит нулевую (пустую) дату.Время
В библиотеке SLIB определена специальная структура LTIME, содержащая бинарное представление даты и необходимые методы для работы с ней.Вот иллюстрация бинарной структуры типа LTIME:
uint8 Hour; uint8 Minuts; uint8 Seconds; uint8 HandredthsOfSecond;Как и LDATE, данный тип занимает в памяти 4 байта.
Специальные значения времени
Значение ZEROTIME содержит нулевое время. Заметим, что нулевое время не является недопустимым. То есть, 00:00:00 - вполне допустимое значение.Дата-время
Комбинированный тип LDATETIME (определен в SLIB.H) состоит из 8 байт. Старшие 4 байта заняты типом LDATE, младшие - типом LTIME.
Унифицированное масштабированное представление даты/времени
Относительно недавно в проект введен новый тип данных SUniTime позволяющих хранить масштабируемое время.Декларируется в файле slib.h.Бинарное представления этого типа состоит из 8 байт, самый старший из которых является индикатором, обеспечивающим информацию о масштабировании времени, установленном в остальных 7 байтах.
Диапазон дат
Тип DateRange используется для представления диапазона дат. Он состоит из даты нижней границы диапазона и даты верхней границы.
LDATE low; LDATE upp;Существуют следующие особенности трактовки границ диапазона:
Класс DateRange содержит метод CheckAndSwap(), который меняет местами low и upp в таком случае.
Строковые типы
SString
Основной класс для представления multibyte-строк в системе. Декларируется в файле slib.h.SStringU
Основной класс для представления unicode-строк. Декларируется в файле slib.h.
Проблема кодировки multibyte-строк
Унификации кодировки строк в проекте Papyrus - проблема. Из-за работы система со множеством источников данных и учитывая возраст проекта накопилось значительное число неразрешенных вопросов.Состояние вопроса следующее: базы данных используют кодировку cp866 (Windows OEM для русскоязычной версии операционной системы). Эта же кодировка трактуется как “INNER” то есть основная внутренняя. Далее, так как на текущий момент большая часть окружения для представления русских текстовых данных использует кодировку windows-1251 (Windows ANSI для русскоязычной версии операционной системы) то такая кодировка трактуется как “OUTER” то есть внешняя. Эта терминология применена для постепенной унификации кодировок первой целью которой является полный переход на OUTER-кодировку. Следующий этап предполагает полный переход либо на UTF-8 либо на UNICODE.Для трансляции кодировок для объектов SString используется функция SString::Transf() единственным аргументом которой задается направление перекодировки:
- CTRANSF_INNER_TO_OUTER 0x0102
- Из внутренней во внешнюю кодировку (OEM->ANSI)
- CTRANSF_OUTER_TO_INNER 0x0201
- Из внешней во внутреннюю кодировку (ANSI->OEM)
- CTRANSF_INNER_TO_UTF8 0x0103
- Из внутренней в utf-8
- CTRANSF_OUTER_TO_UTF8 0x0203
- Из внешней в utf-8
- CTRANSF_UTF8_TO_INNER 0x0301
- Из utf-8 во внутреннюю
- CTRANSF_UTF8_TO_OUTER 0x0302
- Из utf-8 во внешнюю
Другие инструменты перекодировки
Другие типы данных
Несколько типов данных, которые часто используются в проекте:- S_GUID_Base
- Базовое представление для GUID. Обеспечивает всю необходимую функциональность кроме конструктора и деструктора (ради возможности использовать как член union'ов).
- S_GUID
- Наследуется от S_GUID_Base и реализует конструктор и деструктор.
- SVerT
- SBaseBuffer
- STempBuffer
- Динамически распределяемый буфер фиксированного размера, применяемый для временного хранения данных неизвестного во время компиляции размера.
- SBuffer
- Буфер для чтения и записи. Хранит одновременно указатели позиции считывания и позиции записи, благодаря чему позволяет реализовать смешанные операции чтения и записи. При записи, если размер вносимых данных превышает доступный объем буфера, динамически расширяется.
- SColorBase
- Базовое представление для цвета в формате ARGB. Обеспечивает основные функции для работы с цветом, но не содержит конструктора и деструктора.
- SColor
- Прямой наследник SColorBase с конструктором и деструктором.
- SPoint2S
- 2-х мерная точка с представлением каждой из ортогональных координат в формате int16. Кроме представления точки применяется для представления пары размеров по ортогональным осям.
- SPoint2I
- 2-х мерная точка с представлением каждой из ортогональных координат в формате int. Используется, главным образом, при интеграции сторонних библиотек.
- SPoint2R
- 2-х мерная точка с представлением каждой из ортогональных координат в формате double.
- SPoint2F
- 2-х мерная точка с представлением каждой из ортогональных координат в формате float. Кроме представления точки может применяться для представления пары размеров по ортогональным осям.
- SPoint3R
- 3-х мерная точка с представлением каждой из ортогональных координат в формате double.
- SPoint3F
- 3-х мерная точка с представлением каждой из ортогональных координат в формате float.
- TRect
- 2-х мерный прямоугольник, представленный границами в виде левого верхнего и правого нижнего углов. В качестве координат углов использует SPoint2S. Иногда, кроме прямого назначения, используется для представления полей и отступов по четырем направлениям.
- FRect
- 2-х мерный прямоугольник, представленный границами в виде левого верхнего и правого нижнего углов. В качестве координат углом использует SPoint2F. Иногда используется для представления полей и отступов по четырем направлениям.