- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
/**
* @brief Serializer generic interface.
*/
template<typename ValueType>
struct serializer
{
/**
* @brief Parses value from raw bytes.
* @param from byte buffer parse value from
*/
static ValueType parse(uint8_t *from);
/**
* @brief Writes value to raw byte buffer.
* @param value value to write
* @param dest destination buffer
*/
static void write(ValueType value, uint8_t *dest);
};
template<>
struct serializer<uint8_t>
{
static uint8_t parse(uint8_t *from)
{
return *from;
}
static void write(const uint8_t value, uint8_t *to)
{
*to = value;
}
};
template<>
struct serializer<uint16_t>
{
static uint16_t parse(uint8_t *from)
{
return (uint16_t)from[0] << 8 | from[1];
}
static void write(const uint16_t value, uint8_t *to)
{
to[0] = (value >> 8);
to[1] = value & 0xff;
}
};
template<>
struct serializer<uint32_t>
{
static uint32_t parse(uint8_t *from)
{
return from[0] << 24 | from[1] << 16 | from[2] << 8 | from[3];
}
static void write(const uint32_t value, uint8_t *to)
{
serializer<uint16_t>::write(value >> 16, to);
serializer<uint16_t>::write(value & 0xffff, to + 2);
}
};
template<>
struct serializer<uint64_t>
{
static uint64_t parse(uint8_t *from)
{
const uint32_t high = serializer<uint32_t>::parse(from);
const uint32_t low = serializer<uint32_t>::parse(from + 4);
return ((uint64_t) high << 32) | low;
}
static void write(const uint64_t value, uint8_t *to)
{
serializer<uint32_t>::write(value >> 32, to);
serializer<uint32_t>::write(value & 0xffffffff, to + 4);
}
};
Тут поднялась тема неуместного битолюбства... Решил поделиться одним из моих первых крестОпусов.
"кроссплатформенный hton(sl)".
Dummy00001 22.01.2013 23:13 # 0
искать пытаться не буду, но в прошлом находил крутой кусок дефайнов, который несколькими компиляторами распознавался как `ntoh[ls]()` и конвертился (по возможности) в соответствующую инструкцию проца. вот тот кусок дефайнов был настоящим джигитским говном.
defecate-plusplus 22.01.2013 23:30 # 0
может просто на твоей платформе не было bswap?
касательно темы
1) гораздо лучше гонять value_type в value_type (получится вообще один метод), а не указатели в число и назад
2) в обобщенной форме тоже несложно сделать, воспользовавшись std::reverse
roman-kashitsyn 22.01.2013 23:37 # 0
Dummy00001 22.01.2013 23:56 # 0
я сам такое всегда на уровне С держу, что бы если надо макросами простую кодогенерацию делать. хотя это и с твоим пакетом тоже можно. (но я лично С++ с препроцессором пердпочитаю не мешать. дело вкуса.)
к слову напомнило: http://en.wikipedia.org/wiki/Protocol_Buffers
defecate-plusplus 22.01.2013 23:59 # 0
зачем бояться (uint8_t *)&value, он же reinterpret_cast<uint8_t *>(&value)?
и не надо юнионов писать
никаких проверок на переполнение в packet
и немного попахивает злоупотреблением operator >>, но это уже субъективное
совсем тонкости - только надеяться, что кроме целочисленных ValueType пользователь не догадается ничего присунуть в packet
Dummy00001 23.01.2013 00:18 # 0
надо.
http://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html
defecate-plusplus 23.01.2013 00:23 # 0
ValueType result = arg;
<swap result here>;
return result;
defecate-plusplus 23.01.2013 00:34 # 0
может я не до конца понимаю особенности сишного компилятора в этом плане
поэкспериментировал с опциями O2, O3, fstrict-aliasing, fno-string-aliasing, ворнинга не получил даже на примере по твоей ссылке
http://bit.ly/10q2dlB
bormand 23.01.2013 06:09 # +2
It is always presumed that a char* may refer to an alias of any object. It is therefore quite safe, if perhaps a bit unoptimal (for architecture with wide loads and stores) to cast any pointer of any type to a char* type.
Т.е. судя по всему можно написать вот такой код, как и предлагал defecate-plusplus: P.S. Неясно, действует ли это правило и на unsigned char *, поэтому и написал char * вместо uint8_t.
bormand 23.01.2013 06:13 # +3
Desktop 20.01.2021 00:18 # 0
вот зачем дуров сломал стену, а страйкер эмодзи
MAKAKA 20.01.2021 00:53 # 0
Никто не может совладать с дабл эскейпингом в вебе.
Тут вот какое дело: чтобы решить проблему дабл-эскейпинга, нужно иметь IQ, превышающий IQ гиббона минимум в два раза.
Но тот, чей IQ превышает IQ гиббона, не занимается веб-разработкой.
Получается как-бы замкнутый круг. В результате любой веб-сайт и любое веб-приложение всегда имеет проблему с double escape.
Это не только на ГК: на работе в Slack я наблюдаю тоже самое, а до этого я видел это в Salesforce, и даже в некоторым продуктах CI/CD.
Тот, кто решит эту проблему, воистину достоин нобелевской премии!
roman-kashitsyn 23.01.2013 12:35 # +1
Это не часть публичной библиотеки (и пока не собирается ей стать), и размеры объектов проверяются перед записью. Я уже думал над добавлением нижней границы, возможно, ещё один указатель и лишняя проверка того стоят.
> зачем бояться (uint8_t *)&value, он же reinterpret_cast<uint8_t *>(&value)?
Я знаю, что можно, это скорее сишная привычка и выглядит безопаснее. Воможно, исправлю на reinterpret_cast.
> кроме целочисленных ValueType пользователь не догадается ничего присунуть
В том-то и дело, что если присунет - не скомпилится, не найдётся перегрузки.
Радует, что родной говнокодик предоставляет гораздо более конструктивное code review, чем буржуйское поделие.
Dummy00001 23.01.2013 00:08 # 0
bormand 22.01.2013 23:50 # 0
Ну я так понимаю, Роман не ради htons через read+write этот код писал, а все-таки ради сериализации каких-нибудь объектов в массив байт и обратно.
P.S. Интересно, скоро ли компилятор начнет оптимизировать код, который разбивает число циклом на байты, упихивает их в какой-нибудь вектор, вызывает std::reverse, и собирает число из вектора в... bswap? ;)
Dummy00001 23.01.2013 00:03 # 0
скорее всего мои компиляторы "были" устаревшими сегодня. :)
не про bswap речь. речь об инструкциях чтения из памяти с автоматическим bswap'ом. уж не помню как они зовутся. давно это было. и Intel, и PowerPC поддерживают такие инструкции.
если есть желание ковырни линух на предмет /cpu_to_(be|le)|(be|le)_to_cpu/ - там эти инструкции используются.
defecate-plusplus 23.01.2013 00:09 # +1
Dummy00001 23.01.2013 00:16 # 0
в позиксных хидерах, htonl/htons это библиотечные функции. потому что должны быть совместимы со всем чем не попади. поэтому и функции. и значение уже должно быть вычитано из памяти и передано как параметр.
в линухе, в ядре, эта группа специально платформенно-оптимизированых макросов/функций. там и можно увидеть в хидерах для интела/етц эти асмовые инструкции и/или трюки компилятора. включая свап при чтение из/запись в память и свап значения в регистре.
bormand 23.01.2013 08:17 # +1
LispGovno 23.01.2013 00:32 # +2
ab368 24.08.2021 23:00 # 0