Класс из одной статической функции на фиг не нужен. К тому же, функция не работает, она не устанавливает байт в нужное значение, а делает OR старого и нового значения. Надо было сначала байт обнулить. Ну и автор хотел шаблонное решение, а не только для uint16_t, насколько я понял.
А что мешает завернуть то же самое в функцию-член?
class my_byte_vector
{
public:
int len;
unsigned char* v;
// Разные конструкторы, деструкторы и пр. функции.
inline void set_byte(int n, unsigned char val)
{ if(n>=0 && n<len) v[n]=val; };
};
Я к тому, что такой способ бесполезен, если стоит задача «установить определённый байт в числе». Как я этим способом установлю младший байт в ноль, например?
А в big endian наоборот. И как мне тогда написать код с этим union, который младший байт установит в ноль? Он будет не работать либо на big endian, либо на little endian, либо придётся вставлять уродливых #ifdef'ов (в функцию изменения байта, например).
Имхо, ничего уродливого в этом нет. Это одна из парадигм C/C++ - возможность делать максимально эффективный код для различных архитектур, но не всегда полностью машинно-независимый. А большую независимость от архитектуры обеспечивать директивами препроцессора.
Если такой подход не нравится, никто не мешает перейти на ту же яву. У неё свои недостатки, но есть и свои достоинства.
Это одна из парадигм C/C++ - возможность делать максимально эффективный код для различных архитектур, но не всегда полностью машинно-независимый.
GCC довольно умный: когда встречает сдвиги и битовые операции, это не означает, что на выхлопе будут соответствующие ассемблерные команды. Например, код (a >> 16) | (a << 16) генерирует одну-единственную операцию циклического сдвига на 16, в то время как аналогичный swap слов в инте, реализованный с помощью union, будет поувесистее и будет работать с несколькими регистрами, а может и с памятью (насчёт памяти не помню, этот тест делал давно).
Т.к. моя реализация setbyte ещё и отмечена constexpr, то в случае compile-time-констант функция вообще не будет вызвана, а будет подставлена константа; если только некоторые параметры известны, то тоже будут проведены соответствующие оптимизации. Так что я считаю, что версия кода со сдвигами во многих случаях будет быстрее версии с mov'ами. Бенчмарков я не делал, тем более тупой бенчмарк, много раз запускающий функцию setbyte, будет далёк от реальных условий, поскольку многое ещё и зависит от кол-ва используемых регистров, а это скажется лишь на окружающем коде.
код (a >> 16) | (a << 16) генерирует одну-единственную операцию циклического сдвига на 16
Да, скорее всего так и есть.
Бенчмарков я не делал, тем более тупой бенчмарк, много раз запускающий функцию setbyte, будет далёк от реальных условий, поскольку многое ещё и зависит от кол-ва используемых регистров, а это скажется лишь на окружающем коде.
Кстати, есть очень хорошая команда x68 rdtsc специально для бенчмарков, чтобы не вызывать много раз функцию для замеров времени. См., например, статью на хабре «Максимально точное измерение кода». А чтобы учесть влияние окружения/на окружение, надо просто включить это самое окружение в измерения, только не слишком большой участок, чтобы результаты для setbyte не попали в пределы погрешности. :-)
Кстати, есть очень хорошая команда x68 rdtsc специально для бенчмарков, чтобы не вызывать много раз функцию для замеров времени.
Точно, что-то я и не подумал, что можно так замерять время, причём можно даже не выдумывать искусственные бенчмарки, а просто натыкать rdtsc в конкретную программу (хотя про эту команду я знал, но ни разу не пользовался). Тогда и естественное окружение как раз будет. Но даже так нужно делать аккуратно, rdtsc сама по себе не безобидна, она портит на x86_32 аж два регистра (ну и в любом случае сохранить её значение ещё где-то надо).