Периодически возникает потребность определить десятки-сотни элементов статических/константных данных (числовых/логических значений, строк, указателей), произвольным образом объединенных в структуры/массивы — для описания различных концепций.
В языках "сверхвысокого" уровня это традиционно делается через XML/JSON — последовательность данных задается в литеральном виде, компилятор/интерпретатор ее как-то кодирует, и затем ее можно обходить, извлекая сведения о типе каждого элемента и его содержимом.
В C/C++ это традиционно делается через определение типов всех возможных данных, размещение каждого элемента данных в отдельной переменной/объекте, с последующим собиранием указателей на все это в линейный массив.
Хочется чего-нибудь промежуточного, вроде последовательного размещения всех нужных элементов, каждому из которых предшествуют универсальные поля типа и размера, чтоб парсер потом мог все это обойти. Но все равно нужно оформлять каждый элемент в виде отдельной переменной, присваивая ей имя, и порядок размещения не гарантируется ни стандартами, ни компиляторами (многие компиляторы сортируют объекты для лучшей упаковки в памяти).
Внешние средства оформления/компиляции не годятся — в большинстве случаев требуется использовать стандартные типы/значения из разных SDK для C/C++.
В стандарты C++ последних лет ничего такого не завезли?
Re: Определение регулярных последовательностей статических д
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Периодически возникает потребность определить десятки-сотни элементов статических/константных данных (числовых/логических значений, строк, указателей), произвольным образом объединенных в структуры/массивы — для описания различных концепций.
ЕМ>В языках "сверхвысокого" уровня это традиционно делается через XML/JSON — последовательность данных задается в литеральном виде, компилятор/интерпретатор ее как-то кодирует, и затем ее можно обходить, извлекая сведения о типе каждого элемента и его содержимом.
ЕМ>В C/C++ это традиционно делается через определение типов всех возможных данных, размещение каждого элемента данных в отдельной переменной/объекте, с последующим собиранием указателей на все это в линейный массив.
Нифига не понял. Десятки-сотни констант разных типов, объединяются в структуры/массивы, оптять же, разных типов и указатели на всё это богатство каким-то магическим образом собираются в один линейный массив. Там массив void* что ли? Ты бы хоть эскиз кода набросал какой-то.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>В C/C++ это традиционно делается через определение типов всех возможных данных, размещение каждого элемента данных в отдельной переменной/объекте, с последующим собиранием указателей на все это в линейный массив.
getValue(id) ?
ЕМ>Хочется чего-нибудь промежуточного, вроде последовательного размещения всех нужных элементов, каждому из которых предшествуют универсальные поля типа и размера, чтоб парсер потом мог все это обойти. Но все равно нужно оформлять каждый элемент в виде отдельной переменной, присваивая ей имя, и порядок размещения не гарантируется ни стандартами, ни компиляторами (многие компиляторы сортируют объекты для лучшей упаковки в памяти). https://en.wikipedia.org/wiki/Key%E2%80%93value_database https://arrow.apache.org/
ЕМ>Внешние средства оформления/компиляции не годятся — в большинстве случаев требуется использовать стандартные типы/значения из разных SDK для C/C++.
Тогда генерировать скриптом (на php,perl,lua,python,...) data.cpp и data.h
ЕМ>В стандарты C++ последних лет ничего такого не завезли?
В последнии стандарты завезли уйму дури, вам какую?
Re[2]: Определение регулярных последовательностей статических д
Здравствуйте, rg45, Вы писали:
R>Здравствуйте, Евгений Музыченко, Вы писали:
R>Там массив void* что ли?
Если всё совершенно разнородное, то или void*, или указатели на самый общий union, из которого парсер потом добывает нужный тип по общему полю селектора.
Ты бы хоть эскиз кода набросал какой-то.
R>Лень набрасывать код только ради примера. Одно из типичных применений — параметризуемые программы, настраиваемые на конкретного заказчика. Поначалу хватает набора простейших #define или констант, потом софт постепенно усложняется, добавляются новые параметры и их группы, которые уже замучишься перечислять в виде имен вида Node7_Channel3_TempMax, и вдобавок легко перепутать номера/индексы. А главное — в этой куче с ходу не видно структуры, ибо она делается в некотором роде подобно реляционным БД, где иерархия и группировка достигаются гибкими, но неочевидными способами.
Поэтому хочется это дело оформить в структурированно-иерархическом виде, как в cfg-файлах, виндовом реестре или том же JSON, чтоб максимум данных можно было задавать литералами. Чтоб в любой однородный перечень, указанный в отдельно взятом наборе параметров, можно было тупо вставить дополнительный элемент, и это не ломало соответствия с предопределенным типом и/или форматами остальных наборов параметров.
Я знаю, что можно наплодить классов, наделать из них полиморфных объектов, но инициализировать и собирать в контейнеры это все можно только во время выполнения. Поскольку я примерно представляю, в какой жирный и уродливый код это будет раскрываться, мне заранее противно даже думать в эту сторону.
На любом приличном ассемблере я б наделал макросов, и изящно описал бы структуру данных любой сложности.
Re[2]: Определение регулярных последовательностей статических данных
Судя по описанию, это что-то необъятное, претендующее на всеобщность. Мне точно имеет смысл это изучать?
_>Тогда генерировать скриптом (на php,perl,lua,python,...) data.cpp и data.h
Это будет еще более громоздко и запутанно, чем традиционный сишный способ.
_>В последнии стандарты завезли уйму дури
Ужас. Это вместо того, чтоб уже закопать стюардессу препроцессор...
Re[3]: Определение регулярных последовательностей статически
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Лень набрасывать код только ради примера. Одно из типичных применений — параметризуемые программы, настраиваемые на конкретного заказчика. Поначалу хватает набора простейших #define или констант, потом софт постепенно усложняется, добавляются новые параметры и их группы, которые уже замучишься перечислять в виде имен вида Node7_Channel3_TempMax, и вдобавок легко перепутать номера/индексы. А главное — в этой куче с ходу не видно структуры, ибо она делается в некотором роде подобно реляционным БД, где иерархия и группировка достигаются гибкими, но неочевидными способами.
ЕМ>Поэтому хочется это дело оформить в структурированно-иерархическом виде, как в cfg-файлах, виндовом реестре или том же JSON, чтоб максимум данных можно было задавать литералами. Чтоб в любой однородный перечень, указанный в отдельно взятом наборе параметров, можно было тупо вставить дополнительный элемент, и это не ломало соответствия с предопределенным типом и/или форматами остальных наборов параметров.
ЕМ>Я знаю, что можно наплодить классов, наделать из них полиморфных объектов, но инициализировать и собирать в контейнеры это все можно только во время выполнения. Поскольку я примерно представляю, в какой жирный и уродливый код это будет раскрываться, мне заранее противно даже думать в эту сторону.
Ну то есть, это просто конфигурация программы, задаваемая в коде? А откуда берется желание запихнуть её в массив?
Просто чтоб мне стало понятно. Можешь объяснить, чем тебе не угодило решение "в лоб"? Вот тебе тот самый "структурированно-иерархический вид, как в cfg-файлах, виндовом реестре или том же JSON", о котором ты мечтаешь:
Здравствуйте, rg45, Вы писали:
R>Ну то есть, это просто конфигурация программы, задаваемая в коде?
Да, причем исключительно (ну, или почти) на этапе компиляции.
R>А откуда берется желание запихнуть её в массив?
Чтобы можно было задавать только необходимые параметры, а добавление поддержки новых параметров не ломало существующих конфигураций.
R>Вот тебе тот самый "структурированно-иерархический вид
Как его обойти универсальным парсером, который в общем случае не знает, какие параметры (и каких типов) включены в конкретную конфигурацию?
R>как в cfg-файлах, виндовом реестре или том же JSON", о котором ты мечтаешь:
Это совершенно не то, о чем я мечтаю. Здесь доступ к параметрам возможен только по заранее известным именам. Такое у меня уже есть, не нравится.
Re[5]: Определение регулярных последовательностей статически
Здравствуйте, Евгений Музыченко, Вы писали:
R>>Вот тебе тот самый "структурированно-иерархический вид
ЕМ>Как его обойти универсальным парсером, который в общем случае не знает, какие параметры (и каких типов) включены в конкретную конфигурацию?
Ну вот я же это и пытаюсь у тебя выведать. Зачем нужно обходить эту структуру каким-то парсером?
P.S. Есть подход, который позволяет работать с произвольными С++ структурами как с кортежами с использованием стандарных утилит std::get, std::apply, std::tuple_size, std::tuple_element (ну или с самописными аналогами). Ну и само собой, организовать рекурсивный обход структуры не составит труда при этом. Этот подход обеспечивает возможность вненсения изменений в структры без модификации алгоритмов, работающих с этими структурами. Но делать нужно самому. Само решение не выглядит простым, использует концепты и ненавистную шаблонную магию. Но делается один раз, лежит в отдельном файле и есть не просит. Интересует такое?
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, Евгений Музыченко, Вы писали: ЕМ>Ужас. Это вместо того, чтоб уже закопать стюардессу препроцессор...
Ну если я правильно понял вам и нужен ужас. Примерно такой:
[test.cpp]
#include <string>
#include <iostream>
// где-то по кодуstatic const int z[]={1,2};
static const double x=10;
static const int y[]={1,2,3,4,5,6,7,8,9,10};
// собираем всех кого нужно в древовидную структуру в отдельной единице трансляции маркер имя namespace-аnamespace Consts {
auto &z=::z;
namespace Nested {
auto &x=::x;
auto &y=::y;
}
}
// decltypedef decltype(typeid(0)) ti;
#define DECL(name) decl(ctx,(void*)&name,sizeof(name),#name,typeid(name));
void enum_vars( void (*decl)(void *ctx,void *ptr,size_t size,const char* name,ti t),void *ctx) {
#include"consts.inc"// что-бы вручную не писать используем готовый код. готовим отдельно
}
#undef DECL
// utils#include <cxxabi.h>
#include <stdlib.h>
std::string getTypeName(ti t) {
std::string res; int err=0;
char* name=abi::__cxa_demangle(t.name(),0,0,&err);
if (name) { res=name; free(name); }
return res;
}
void print_var(void *ctx,void *ptr,size_t size,const char* name,ti t) {
std::cout<<size<<"\t"<<name<<"\t"<<getTypeName(t)<<"\n";
}
int main() {
enum_vars(print_var,0); // пробегаем по линейному списку (можем делать всё что хотим, например выводим на печать)return 0;
}
for line in io.lines() do
local size,name=line:match"%.data%.rel%.ro%.local%s+(%x+)%s+(Consts::[%w%d:_]+)"
if name then print("DECL("..name..")") end
end
[output]
8 Consts::z int [2]
8 Consts::Nested::x double
40 Consts::Nested::y int [10]
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Внешние средства оформления/компиляции не годятся — в большинстве случаев требуется использовать стандартные типы/значения из разных SDK для C/C++.
А protobuf/flatbuffers не подойдут? Они внешние, но работают на этапе компиляции. Можно в message запихать любых типов, те, которые не будут использоваться, не будут и сериализовывааться. Плюс, они кроссплатформенны, кросс языковые и т.д. Можно в бинарном виде хранить, можно, например для отладки, в json сохранять.
Re[6]: Определение регулярных последовательностей статически
Здравствуйте, rg45, Вы писали:
R>Зачем нужно обходить эту структуру каким-то парсером?
Чтоб разобрать и применить только явно заданные параметры, схемы задания которых могут сильно меняться от конфигурации к конфигурации, и вдобавок умолчания для многих опущенных параметров могут меняться в зависимости от значений явно указанных.
Сейчас у меня это организовано в виде традиционных структур и массивов, но, по мере добавления новых параметров, многие конфигурации без нужды приобретают чрезмерно развесистый вид из-за явного перечисления предыдущих полей структуры (я пока не использую desingated initializers из соображений совместимости).
R>Есть подход, который позволяет работать с произвольными С++ структурами как с кортежами
Такое я и сам могу сделать, но это опять же потянет за собой изрядный объем двоичного исполняемого кода. Хочется по максимуму обойтись статическими определениями на этапе компиляции.
Re[4]: Определение регулярных последовательностей статически
Здравствуйте, kov_serg, Вы писали:
_>если я правильно понял вам и нужен ужас
Не, ужас не нужен, и тем более не такой. В идеале, меня бы полностью устроила поддержка компилятором формата вроде JSON, из которого он при компиляции тупо складывал бы в память значения/адреса, снабжая каждый элемент кодом типа (значение char/int/float, строка, указатель, список элементов и т.п.) и размером в памяти. Удивительно, что при бешеной популярности JSON, до такого до сих пор не додумались. Оно ж и очень удобно, и в реализации совсем несложно.
Re[7]: Определение регулярных последовательностей статически
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Такое я и сам могу сделать, но это опять же потянет за собой изрядный объем двоичного исполняемого кода. Хочется по максимуму обойтись статическими определениями на этапе компиляции.
Ты, по-видимому, не придал значения ключевым словам "inline constexpr" в моем примере. Вся эта структура данных вычисляется во время компиляции. Во что выльется обход этой структуры — это уже зависит, от операций, выполняемых во время обхода. Если все операции будут времени компиляции, то и вся процедура обхода также будет выполнена во время компиляции. И в сгенерированном объекном коде ты увидишь лишь результаты этого обхода, подставленные инлайном в места использования. Машинного кода, соответсвующего самому компайл-тайм обходу, в сгенерированном объектном коде не будет.
Я, для большей наглядности, добавил в мой пример пару строчек, чтоб было видно, что вся эта структура вычисляется во время компиляции:
Здравствуйте, Nuzhny, Вы писали:
N>А protobuf/flatbuffers не подойдут?
Хотелось бы обойтись без внешних средств.
N>Они внешние, но работают на этапе компиляции. Можно в message запихать любых типов
А как эти тулзы понимают константы/структуры, определенные в C++? Я могу в любом месте указать литерал вида { 7, "abc" } в качестве значения структуры определенного ранее типа?
Вообще, мне только что пришла в голову мысль, что можно попробовать задавать параметры в "реестроподобной" форме. Один хрен почти всегда нужно извлекать какие-то параметры из реестра, имена элементов в коде присутствуют, осталось додумать удобные способы представления структур/массивов. Тогда можно задавать только явно определяемые параметры в виде "ключ/значение", а для разбора вообще сделать универсальный код, берущий данные или из реестра, или из собственной памяти.
Re[8]: Определение регулярных последовательностей статически
Здравствуйте, rg45, Вы писали:
R>Ты, по-видимому, не придал значения ключевым словам "inline constexpr" в моем примере.
Придал, но в Вашем примере все типы и переменные явно именованы. А я хочу как раз избежать этого явного именования, задавая в конфигурации только сами данные, а не определения множества переменных.
Re[9]: Определение регулярных последовательностей статически
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Придал, но в Вашем примере все типы и переменные явно именованы. А я хочу как раз избежать этого явного именования, задавая в конфигурации только сами данные, а не определения множества переменных.
, почему этого нужно избежать. Что плохого в том, что к компайл-тайм данным будет доступ как по именам, так и по компайл-тайм индексам (как к кортежам)?
Так в моём примере два следующих выражения будут эквивалентны:
Здравствуйте, rg45, Вы писали:
R>Что плохого в том, что к компайл-тайм данным будет доступ как по именам, так и по компайл-тайм индексам (как к кортежам)?
Доступа в compile-time мне вообще не нужно — только в run-time. Но Ваш вариант, как я понял, плотно завязан на RTTI, а эта хрень не только тащит лишний код из CRT, но и не умеет работать без плюсовых исключений, а в ядре ни то, ни другое не поддерживается.
Re[11]: Определение регулярных последовательностей статическ
ты говорил, что хочешь по максимуму статических определений на этапе компиляции. Так я тебе именно это и предлагаю.
ЕМ>Но Ваш вариант, как я понял, плотно завязан на RTTI,
Полностью мимо. Я всю дорогу пишу про компайл-тайм, тут на тебе — RTTI. Как, вообще, можно было сделать такой вывод из того, что я писал?
ЕМ>а эта хрень не только тащит лишний код из CRT, но и не умеет работать без плюсовых исключений, а в ядре ни то, ни другое не поддерживается.
Это я вообще не распарсил. Какое отношение это имеет к тому, что я пишу?
Ты, вообще, читаешь, что я тебе пишу?
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, rg45, Вы писали:
R>ты говорил, что хочешь по максимуму статических определений на этапе компиляции.
Я хочу самих определений, а доступа к ним на этапе компиляции мне не нужно. Хотя какие-то из определений и могут использовать значения ранее известных, но это не обязательно. Разбор всей этой кучи происходит только во время работы.
R>тут на тебе — RTTI.
Прошу прощения, я попутал Ваш пример с примером от kov_serg, где typeid — промотал не туда. То-то у меня было странное ощущение.
Только как организовать это все в какое-то подобие кортежа, не привлекая std::tuple и ненавистную магию?
Re[5]: Определение регулярных последовательностей статически
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Не, ужас не нужен, и тем более не такой. В идеале, меня бы полностью устроила поддержка компилятором формата вроде JSON, из которого он при компиляции тупо складывал бы в память значения/адреса, снабжая каждый элемент кодом типа (значение char/int/float, строка, указатель, список элементов и т.п.) и размером в памяти. Удивительно, что при бешеной популярности JSON, до такого до сих пор не додумались. Оно ж и очень удобно, и в реализации совсем несложно.
Если бы вы привели конкретный пример было бы проще понять вашу боль