Хочу странного: свой string для enum class
От: пффф  
Дата: 26.03.24 10:35
Оценка:
Привет!

Есть enum class:
enum class EMyEnum : std::uint16_t
{
    Zero   = 0,
    //...
};



Хочу делать из него строки. Изначально думал использовать просто вектор, но потом подумалось, что хочу, чтобы работало всё как со строками. Плюс ещё профит от оптимизации коротких строк.

По сути — это и есть строки, только упакованные — коды до 256 — соотв. ASCII символам, а коды больше — это идентификаторы строк в контейнере-словаре.


Хотел сначала простым
using MyEnumString = std::basic_string<EMyEnum>


Потом подумалось, что скорее всего не прокатит, и надо делать свой char_traits для EMyEnum.

Начал копать. В MSVC там так:
[ccode]
template <class _Elem>
struct char_traits : _Char_traits<_Elem, long> {}; // properties of a string or stream unknown element

template <>
struct char_traits<char16_t> : _WChar_traits<char16_t> {};

using u16streampos = streampos;

template <>
struct char_traits<char32_t> : _Char_traits<char32_t, unsigned int> {};

using u32streampos = streampos;

template <>
struct char_traits<wchar_t> : _WChar_traits<wchar_t> {};
[/ccode]


Т.е. все использует либо _Char_traits, либо _WChar_traits.
_Char_traits поуниверсальнее, как я понял, _WChar_traits скорее всего его использует.

Тут проблема — я не могу использовать _Char_traits/_WChar_traits — это же просто детали MSVC реализации. Хотя, подозреваю, у других компиляторов реализация char_traits наверняка тоже через какую-то общую базу, но имена, скорее всего другие. Ну, и у MSVC в другой версии имена могут быть другими.

Можно было бы написать целиком свою реализацию, но я глянул у MS реализацию _Char_traits. Там оно обмазано всё макросами _NODISCARD, _CONSTEXPR17, _CONSTEXPR20, _HAS_MEMCPY_MEMMOVE_INTRINSICS и тп, ну и по возможности, интринсиками.
Хочется, чтобы моя реализация была тоже максимально оптимальной, но тут придётся самому под каждый компилер писать.


Как быть?

В принципе, для MSVC можно заюзать _Char_traits, и надеяться, что в других версиях либы это не поменяется; для GCC — подглядеть как у них сделано, и взять их базовую реализацию, так же и для других компилеров.

Или есть ещё варианты?
Re: Хочу странного: свой string для enum class
От: LaptevVV Россия  
Дата: 26.03.24 11:06
Оценка:
П>Есть enum class:
П>
П>enum class EMyEnum : std::uint16_t
П>{
П>    Zero   = 0,
П>    //...
П>};
П>

П>Хочу делать из него строки. Изначально думал использовать просто вектор, но потом подумалось, что хочу, чтобы работало всё как со строками. Плюс ещё профит от оптимизации коротких строк.
А что в строках-то ?
Имена енумов ?
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[2]: Хочу странного: свой string для enum class
От: пффф  
Дата: 26.03.24 11:23
Оценка:
Здравствуйте, LaptevVV, Вы писали:

П>>Хочу делать из него строки. Изначально думал использовать просто вектор, но потом подумалось, что хочу, чтобы работало всё как со строками. Плюс ещё профит от оптимизации коротких строк.

LVV>А что в строках-то ?
LVV>Имена енумов ?

Да. Есть какие-то предопределённые, они имеют соотв константы в enum'е, с которыми я могу работать напрямую, или пользовательские строки, которые пользователь сам может добавить в словарь и сохранить соотв идентификатор в какой-нибудь переменной
Re: Хочу странного: свой string для enum class
От: пффф  
Дата: 26.03.24 14:57
Оценка:
Здравствуйте, пффф, Вы писали:

Насколько стандартны функции __builtin_memmove/__builtin_memcpy?
Re: Хочу странного: свой string для enum class
От: flаt  
Дата: 26.03.24 15:29
Оценка:
Здравствуйте, пффф, Вы писали:


П>Хочу делать из него строки. Изначально думал использовать просто вектор, но потом подумалось, что хочу, чтобы работало всё как со строками.


П>По сути — это и есть строки, только упакованные — коды до 256 — соотв. ASCII символам, а коды больше — это идентификаторы строк в контейнере-словаре.


Наркомания какая-то. Что означают первые два предложения? Или хотя бы пример использования в виде кода.


П>Хотел сначала простым

П>
П>using MyEnumString = std::basic_string<EMyEnum>
П>


basic_string — это массив символов и операции над ним. basic_string<EMyEnum> — массив енумов. А дальше что? Что у тебя будет в c_str(), data(), length()? Чего добиться хочешь?

П>Потом подумалось, что скорее всего не прокатит, и надо делать свой char_traits для EMyEnum.


https://en.cppreference.com/w/cpp/string/char_traits — посмотри, что такое char trait.
Re[2]: Хочу странного: свой string для enum class
От: пффф  
Дата: 26.03.24 15:39
Оценка:
Здравствуйте, flаt, Вы писали:

П>>Хочу делать из него строки. Изначально думал использовать просто вектор, но потом подумалось, что хочу, чтобы работало всё как со строками.


П>>По сути — это и есть строки, только упакованные — коды до 256 — соотв. ASCII символам, а коды больше — это идентификаторы строк в контейнере-словаре.


F>Наркомания какая-то. Что означают первые два предложения? Или хотя бы пример использования в виде кода.


Не очень понятно, что тебе не понятно. Нужен контейнер, и я решил сделать такой контейнер на базе basic_string


П>>Хотел сначала простым

П>>
П>>using MyEnumString = std::basic_string<EMyEnum>
П>>


F>basic_string — это массив символов и операции над ним. basic_string<EMyEnum> — массив енумов. А дальше что? Что у тебя будет в c_str(), data(), length()? Чего добиться хочешь?


А у меня — массив моих токенов. c_str() — будет возвращать указатель на массив токенов, заканчивающийся нулём. data() — тоже указатель, но финальный ноль вроде не гарантирован. length() — вернёт количество токенов. Чего не понятного?


П>>Потом подумалось, что скорее всего не прокатит, и надо делать свой char_traits для EMyEnum.


F>https://en.cppreference.com/w/cpp/string/char_traits — посмотри, что такое char trait.


Посмотрел.

The char_traits class is a traits class template that abstracts basic character and string operations for a given character type. The defined operation set is such that generic algorithms almost always can be implemented in terms of it. It is thus possible to use such algorithms with almost any possible character or string type, just by supplying a customized char_traits class.


И?
Re: Хочу странного: свой string для enum class
От: watchmaker  
Дата: 26.03.24 16:13
Оценка: 2 (1)
Здравствуйте, пффф, Вы писали:

П>Тут проблема — я не могу использовать _Char_traits/_WChar_traits — это же просто детали MSVC реализации.


Правильно, не нужно эти детали реализации использовать.
Нужно просто предоставить свою специализацию шаблона std::char_traits<EMyEnum>, написанную тобой, и с той логикой, которая тебе нужна.

П>Можно было бы написать целиком свою реализацию, но я глянул у MS реализацию _Char_traits. Там оно обмазано всё макросами _NODISCARD, _CONSTEXPR17, _CONSTEXPR20, _HAS_MEMCPY_MEMMOVE_INTRINSICS и тп, ну и по возможности, интринсиками.

П>Хочется, чтобы моя реализация была тоже максимально оптимальной, но тут придётся самому под каждый компилер писать.

Скорее нет, чем да. Тебе не нужно повторять большую часть из того, что там написано. Все эти макросы присутствуют потому, что с их помощью была сделана совместимость со старыми платформами и компиляторами.
Если ты знаешь под какую версию языка С++ пишешь свою программу/библиотеку, то во многих из них исчезает смысл (практически во всех, если это не совсем древняя версия С++).

И на "оптимальность" большая часть из них не влияет. Разве что упомянутый тобой _HAS_MEMCPY_MEMMOVE_INTRINSICS как-то с натяжкой можно притянуть. Да и то, эта конструкция служит больше для оптимизации времени компиляции, а не времени работы в runtime. И вряд-ли ты когда-то свои строки будешь использовать так же широко, как и std::string, чтобы хоть сколько-нибудь заметить эффект.


П>Плюс ещё профит от оптимизации коротких строк.


Учти, что код для нестандартных char_traits протестирован весьма плохо даже в STL.
Вот, например, (ещё непочиненный) баг в libc++: https://github.com/llvm/llvm-project/issues/51158
Конкретно с EMyEnum едва ли будут какие-то проблемы, но если будешь использовать что-то ещё более экзотичное, то появляются риски того, что STL не полностью поддерживает стандарт для таких типов "символов".
Отредактировано 26.03.2024 16:24 watchmaker . Предыдущая версия . Еще …
Отредактировано 26.03.2024 16:16 watchmaker . Предыдущая версия .
Re: Хочу странного: свой string для enum class
От: sergii.p  
Дата: 26.03.24 16:16
Оценка:
Здравствуйте, пффф, Вы писали:

П>Потом подумалось, что скорее всего не прокатит, и надо делать свой char_traits для EMyEnum.


так скорее всего не прокатит, или не прокатит?

у меня прокатило

enum class MyEnum{};

using MyEnumString = std::basic_string<MyEnum>;

int main()
{
    MyEnumString str1;
    str1.append(10, MyEnum{1});
    MyEnumString str2;
    str2.append(10, MyEnum{2});

    std::cout << (str1 == str2);
}


Вопрос ведь что надо. Получается стандартные вещи он вполне умеет делать из коробки.
Re[2]: Хочу странного: свой string для enum class
От: пффф  
Дата: 27.03.24 01:46
Оценка:
Здравствуйте, watchmaker, Вы писали:

П>>Тут проблема — я не могу использовать _Char_traits/_WChar_traits — это же просто детали MSVC реализации.


W>Правильно, не нужно эти детали реализации использовать.


Ну, в версии для MSVC таки решил взять её. Если что, просто отключу этот выбор и перейду на универсальную


W>Нужно просто предоставить свою специализацию шаблона std::char_traits<EMyEnum>, написанную тобой, и с той логикой, которая тебе нужна.


А для других стырил из GCC. Там пошли своим путём и ручками все специализации описали. Ну, любят видимо люди копипастить. В принципе, там вроде только оconstexpr был замакрошен, я его заменил на ключевое слово.
Функции _builtin_mem* аналогичные MSVCшным, так что похоже они де факто стандартны


П>>Плюс ещё профит от оптимизации коротких строк.


W>Учти, что код для нестандартных char_traits протестирован весьма плохо даже в STL.

W>Вот, например, (ещё непочиненный) баг в libc++: https://github.com/llvm/llvm-project/issues/51158
W>Конкретно с EMyEnum едва ли будут какие-то проблемы, но если будешь использовать что-то ещё более экзотичное, то появляются риски того, что STL не полностью поддерживает стандарт для таких типов "символов".

Спасибо
Re[2]: Хочу странного: свой string для enum class
От: пффф  
Дата: 27.03.24 01:58
Оценка:
Здравствуйте, sergii.p, Вы писали:

SP>у меня прокатило


SP>
SP>enum class MyEnum : std::uin16_t{};
SP>


SP>Вопрос ведь что надо. Получается стандартные вещи он вполне умеет делать из коробки.


Я что-то заранее испугался, что выделенное не прокатит. Но вроде и так работает. Зато немного полезного узнал про char_traits
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.