/*!
\page oess_1_2_0__optional_fields	oess_1.2.0. Опциональные поля

\section oess_1_2_0__optional_fields__intro	Введение

	Сериализация объекта требует затрат как времени процессора, так
	и пространства для хранения сериализованных атрибутов объекта.
	Стандартная сериализация ObjESSty, выполняемая средствами компонента
	oess_1::stdsn, не является самой экономичной с точки зрения компактности
	получаемого двоичного образа. Например, упаковка ASN1 PER дает
	намного более компактное представление.

	Поэтому, для улучшения параметров скорости/экономичности сериализации
	объектов необходимо для каждого сериализуемого объекта сократить к
	минимуму количество сериализуемых полей (атрибутов). Одним из
	способов является использование <i>опциональных полей</i>.
	
	<i>Опциональным полем</i> является атрибут объекта, которому можно
	назначить значение по-умолчанию, использующееся в подавляющем
	большинстве случаев. Если при сериализации проверить, что поле
	содержит такое значение, то поле можно не сериализовать. Достаточно
	указать в двоичном представлении, что поле имеет значение по-умолчанию.
	При десериализации можно определить, что поле не было сериализовано
	и назначить ему значение по-умолчанию сразу после десериализации
	всего объекта.
	
	Пример. Пусть есть некое сообщение handshake, в котором требуется
	передать параметры коммуникационной сессии. Среди прочих параметров
	в нем содержатся: параметры использования подписи
	передаваемых данных и параметры компрессии передаваемых данных.
	При этом, в большинстве случаев в качестве подписи будет
	использоваться алгоритм md5. Компрессия по умолчанию не используется,
	но если используется, то обычно применяется gzip со средней степенью
	сжатия. Представить это на DDL можно следующим образом:
\verbatim
|| Параметры компрессии.
{type	compression_t
	|| Алгоритм копрессии.
	{attr	m_algorithm {of std::string}
		{default
			|| По-умолчанию в C++ значение задается константой gzip.
			{c++ compression_t::gzip}
			|| Сериализовать атрибут необходимо только, если
			|| значение отличается от gzip.
			{present_if {c++ m_algorithm != compression_t::gzip}}
		}
	}
	|| Степень сжатия.
	{attr	m_level {of oess_1::uint_t}}
}

|| Описание параметров для коммуникационной сессии.
{type	handshake_t
	|| Остальные атрибуты опущены за ненадобностью.
	
	|| Алгоритм подписи данных.
	{attr	m_signature {of std::string}
		{default
			|| По-умолчанию в C++ значение задается константой md5.
			{c++ handshake_t::signature_md5}
			|| Сериализовать атрибут необходимо только, если
			|| значение отличается от md5.
			{present_if
				{c++ handshake_t::signature_md5 != m_signature}
			}
		}
	}
	
	|| Признак необходимости использования компрессии данных.
	{attr	m_is_compression {of oess_1::uchar_t}}
	|| Параметры компрессии.
	{attr	m_compression {of compression_t}
		{default
			|| По-умолчанию должен использоваться конструктор
			|| класса compression_t.
			{c++ compression_t() }
			|| Сериализовать атрибут нужно только, если флаг
			|| m_is_compression отличен от 0.
			{present_if {c++ m_is_compression}}
		}
	}
}
\endverbatim

\section oess_1_2_0__optional_fields__ddl_syntax	Теги DDL для описания опциональных полей

	Для того, чтобы сделать атрибут объекта опциональным полем необходимо
	использовать следующие теги:
	- <i>{attr {default ...}}</i>. Указывает, что атрибут имеет значение
	по-умолчанию. Опциональное поле является частным случаем атрибута
	со значением по-умолчанию;
	- <i>{attr {default {c++ ...}}}</i>. Содержит C++ выражение, которое, будучи
	подставленным в правую часть оператора присваивания, назначит
	атрибуту значение по умолчанию. Выражением может быть имя C++
	константы, вызов функции (в том числе и конструктора по-умолчанию),
	C++ литерал (число, строка, символ);
	- <i>{attr {default {present_if ...}}}</i>. Указывает, что атрибут является
	опциональным полем;
	- <i>{attr {default {present_if {c++ ...}}}}</i>. Содержит C++ выражение,
	которое, будучи подставленным в оператор <tt>if()</tt>, укажет, должен ли
	атрибут быть сериализован. Атрибут сериализуется только, если данный
	предикат производит значение \b true. Выражением может быть любое
	корректное C++ выражение, приводящееся к булевому результату.

\par Использование escape-последовательностей

	Из-за правил синтаксиса cls_2 C++ выражениях необходимо так же
	использовать escape-последовательности для представления
	символов:
	- двойной кавычки:
\verbatim
{attr m_algorithm {of std::string}
	{default {c++ \"md5\"}
		{present_if {c++ m_algorithm != \"md5\"}}
	}
}
\endverbatim
	Если этого не сделать, то по правилам синтаксиса cls_2
	заключенная в простые двойные кавычки строка будет перенесена в
	C++ код без кавычек;
	- вертикальной черты `|'. В cls_2 две вертикальные черты начинают
	комментарий. В C++ эта же конструкция используется для написания
	оператора "логического ИЛИ". Поэтому в DDL легко написать:
\verbatim
{attr m_compression {of std::string}
	{default {c++ \"gzip\"}
		{present_if {c++ m_compression != \"gzip\" || m_compression != \"zip\"}}
	}
}
\endverbatim
	что вызовет ошибку разбора DDL описания, т.к. `||' начинает cls_2
	комментарий. Правильная запись:
\verbatim
{attr m_compression {of std::string}
	{default {c++ \"gzip\"}
		{present_if {c++ m_compression != \"gzip\" \|\| m_compression != \"zip\"}}
	}
}
\endverbatim

\par Предикаты сериализации атрибутов

	Предикат сериализации атрибута, указываемый в теге
	<i>{attr {default {present_if {c++ ...}}}}</i> может быть \b произвольным
	C++ выражением. Т.е. он может содержать обращения не только к самому
	опциональному атрибуту, но и к другим атрибутам объекта, к любым
	константным методам этого объекта, к любым функциям или статическим
	методам любых C++ классов.
	
\section oess_1_2_0__optional_fields__code	Дополнения во вспомогательном коде

	Для поддержки опциональных полей во вспомогательном коде для
	сериализуемого класса генерируется два новых метода:
	- \a oess_present_if, который содержит код предикатов сериализации
	опциональных полей;
	- \a oess_set_default, который содержит код по назначению атрибутам
	значений по умолчанию.
	
	В версии 1.2.0 для приведенного выше DDL описания методы
	oess_present_if, oess_set_default будут иметь вид:
\code
bool compression_t::oess_present_if( const std::string & a ) const {
	if( a == "m_algorithm" )
		return ( m_algorithm != compression_t::gzip );
	return false;
}
void compression_t::oess_set_default( const std::string & a ) {
	if( a == "m_algorithm" )
		m_algorithm = compression_t::gzip ;
}

bool handshake_t::oess_present_if( const std::string & a ) const {
	if( a == "m_signature" )
		return ( handshake_t::signature_md5 != m_signature );
	if( a == "m_compression" )
		return ( m_is_compression );
	return false;
}
void handshake_t::oess_set_default( const std::string & a ) {
	if( a == "m_signature" )
		m_signature = handshake_t::signature_md5 ;
	if( a == "m_compression" )
		m_compression = compression_t() ;
}
\endcode

\section oess_1_2_0__optional_fields__binary_image	Двоичное представление

	В двоичном представлении каждому опциональному полю
	предшествует байтовое значение, равное:
	- 0, если атрибут не сериализован и при десериализации ему должно
	быть назначено значение по-умолчанию;
	- 1, если атрибут сериализован и далее следует его двоичное
	представление.
*/