Skip to content

Commit 5f89a2e

Browse files
committed
DPL: revamp / remove Endian.h
C++20 (and even more so 23) has understanding of endianess. No need to have a special wrapper include anymore.
1 parent 2742e40 commit 5f89a2e

10 files changed

Lines changed: 263 additions & 123 deletions

File tree

Framework/AnalysisSupport/src/TTreePlugin.cxx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
#include "Framework/RootArrowFilesystem.h"
1313
#include "Framework/Plugins.h"
1414
#include "Framework/Signpost.h"
15-
#include "Framework/Endian.h"
15+
#include "Framework/BigEndian.h"
1616
#include <TBufferFile.h>
1717
#include <TBufferIO.h>
1818
#include <arrow/buffer.h>
@@ -197,7 +197,7 @@ auto readValues = [](uint8_t* target, ReadOps& op, TBufferFile& rootBuffer) {
197197
}
198198
int size = readLast * op.listSize;
199199
readEntries += readLast;
200-
swapCopy(target, rootBuffer.GetCurrent(), size, op.typeSize);
200+
bigEndianCopy(target, rootBuffer.GetCurrent(), size, op.typeSize);
201201
target += (ptrdiff_t)(size * op.typeSize);
202202
}
203203
};
@@ -230,7 +230,7 @@ auto readVLAValues = [](uint8_t* target, ReadOps& op, ReadOps const& offsetOp, T
230230
auto readLast = op.branch->GetBulkRead().GetEntriesSerialized(readEntries, rootBuffer);
231231
int size = offsets[readEntries + readLast] - offsets[readEntries];
232232
readEntries += readLast;
233-
swapCopy(target, rootBuffer.GetCurrent(), size, op.typeSize);
233+
bigEndianCopy(target, rootBuffer.GetCurrent(), size, op.typeSize);
234234
target += (ptrdiff_t)(size * op.typeSize);
235235
}
236236
};
@@ -581,7 +581,8 @@ auto readOffsets = [](ReadOps& op, TBufferFile& rootBuffer) {
581581
readEntries += readLast;
582582
for (auto i = 0; i < readLast; ++i) {
583583
offsets[count++] = (int)offset;
584-
offset += swap32_(reinterpret_cast<uint32_t*>(rootBuffer.GetCurrent())[i]);
584+
uint32_t raw = reinterpret_cast<uint32_t*>(rootBuffer.GetCurrent())[i];
585+
offset += (std::endian::native == std::endian::little) ? __builtin_bswap32(raw) : raw;
585586
}
586587
}
587588
offsets[count] = (int)offset;

Framework/AnalysisSupport/src/TableTreeHelpers.cxx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
// or submit itself to any jurisdiction.
1111
#include "Framework/TableTreeHelpers.h"
1212
#include "Framework/Logger.h"
13-
#include "Framework/Endian.h"
1413
#include "Framework/Signpost.h"
1514

1615
#include <arrow/dataset/file_base.h>

Framework/Core/src/FragmentToBatch.cxx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
// or submit itself to any jurisdiction.
1111
#include "Framework/FragmentToBatch.h"
1212
#include "Framework/Logger.h"
13-
#include "Framework/Endian.h"
1413
#include "Framework/Signpost.h"
1514

1615
#include <arrow/dataset/file_base.h>

Framework/Core/src/HTTPParser.cxx

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ void encode_websocket_frames(std::vector<uv_buf_t>& outputs, char const* src, si
5454
int maskSize = mask ? 4 : 0;
5555

5656
if (size < 126) {
57-
headerSize = sizeof(WebSocketFrameTiny);
57+
headerSize = sizeof(WebSocketFrameTiny<std::endian::native>);
5858
// Allocate a new page if we do not fit in the current one
5959
if (outputs.empty() || outputs.back().len > WebSocketConstants::MaxChunkSize || (size + maskSize + headerSize) > (WebSocketConstants::MaxChunkSize - outputs.back().len)) {
6060
char* chunk = (char*)malloc(WebSocketConstants::MaxChunkSize);
@@ -64,11 +64,11 @@ void encode_websocket_frames(std::vector<uv_buf_t>& outputs, char const* src, si
6464
// Reposition the buffer to the end of the current page
6565
buffer = buf.base + buf.len;
6666
buf.len += headerSize + size + maskSize;
67-
WebSocketFrameTiny* header = (WebSocketFrameTiny*)buffer;
67+
auto* header = (WebSocketFrameTiny<std::endian::native>*)buffer;
6868
memset(buffer, 0, headerSize);
6969
header->len = size;
7070
} else if (size < 1 << 16) {
71-
headerSize = sizeof(WebSocketFrameShort);
71+
headerSize = sizeof(WebSocketFrameShort<std::endian::native>);
7272
// Allocate a new page if we do not fit in the current one
7373
if (outputs.empty() || outputs.back().len > WebSocketConstants::MaxChunkSize || (size + maskSize + headerSize) > (WebSocketConstants::MaxChunkSize - outputs.back().len)) {
7474
char* chunk = (char*)malloc(WebSocketConstants::MaxChunkSize);
@@ -78,24 +78,24 @@ void encode_websocket_frames(std::vector<uv_buf_t>& outputs, char const* src, si
7878
// Reposition the buffer to the end of the current page
7979
buffer = buf.base + buf.len;
8080
buf.len += headerSize + size + maskSize;
81-
WebSocketFrameShort* header = (WebSocketFrameShort*)buffer;
81+
auto* header = (WebSocketFrameShort<std::endian::native>*)buffer;
8282
memset(buffer, 0, headerSize);
8383
header->len = 126;
8484
header->len16 = htons(size);
8585
} else {
8686
// For larger messages we do standalone allocation
8787
// so that the message does not need to be sent in multiple chunks
88-
headerSize = sizeof(WebSocketFrameHuge);
88+
headerSize = sizeof(WebSocketFrameHuge<std::endian::native>);
8989
buffer = (char*)malloc(headerSize + maskSize + size);
90-
WebSocketFrameHuge* header = (WebSocketFrameHuge*)buffer;
90+
auto* header = (WebSocketFrameHuge<std::endian::native>*)buffer;
9191
memset(buffer, 0, headerSize);
9292
header->len = 127;
93-
header->len64 = htonll(size);
93+
header->len64 = (std::endian::native == std::endian::little) ? __builtin_bswap64(size) : size;
9494
outputs.push_back(uv_buf_init(buffer, size + maskSize + headerSize));
9595
}
9696
size_t fullHeaderSize = maskSize + headerSize;
9797
startPayload = buffer + fullHeaderSize;
98-
WebSocketFrameTiny* header = (WebSocketFrameTiny*)buffer;
98+
auto* header = (WebSocketFrameTiny<std::endian::native>*)buffer;
9999
header->fin = 1;
100100
header->opcode = (unsigned char)opcode; // binary or text for now
101101
// Mask is right before payload.
@@ -143,7 +143,7 @@ void decode_websocket(char* start, size_t size, WebSocketHandler& handler)
143143
handler.beginChunk();
144144
// The + 2 is there because we need at least 2 bytes.
145145
while (cur - start < size) {
146-
WebSocketFrameTiny* header = (WebSocketFrameTiny*)cur;
146+
auto* header = (WebSocketFrameTiny<std::endian::native>*)cur;
147147
size_t payloadSize = 0;
148148
size_t headerSize = 0;
149149
if ((cur + 2 - start >= size) ||
@@ -160,12 +160,12 @@ void decode_websocket(char* start, size_t size, WebSocketHandler& handler)
160160
payloadSize = header->len;
161161
headerSize = 2 + (header->mask ? 4 : 0);
162162
} else if (header->len == 126) {
163-
WebSocketFrameShort* headerSmall = (WebSocketFrameShort*)cur;
163+
auto* headerSmall = (WebSocketFrameShort<std::endian::native>*)cur;
164164
payloadSize = ntohs(headerSmall->len16);
165165
headerSize = 2 + 2 + (header->mask ? 4 : 0);
166166
} else if (header->len == 127) {
167-
WebSocketFrameHuge* headerSmall = (WebSocketFrameHuge*)cur;
168-
payloadSize = ntohll(headerSmall->len64);
167+
auto* headerSmall = (WebSocketFrameHuge<std::endian::native>*)cur;
168+
payloadSize = (std::endian::native == std::endian::little) ? __builtin_bswap64(headerSmall->len64) : headerSmall->len64;
169169
headerSize = 2 + 8 + (header->mask ? 4 : 0);
170170
}
171171
size_t availableSize = size - (cur - start);

Framework/Core/src/HTTPParser.h

Lines changed: 42 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
#ifndef O2_FRAMEWORK_HTTPPARSER_H_
1313
#define O2_FRAMEWORK_HTTPPARSER_H_
1414

15-
#include "Framework/Endian.h"
15+
#include <bit>
16+
#include <cstdint>
1617
#include <fmt/format.h>
1718
#include <uv.h>
1819
#include <string>
@@ -22,71 +23,82 @@
2223
namespace o2::framework
2324
{
2425

25-
struct __attribute__((__packed__)) WebSocketFrameTiny {
26-
#if O2_HOST_BYTE_ORDER == O2_LITTLE_ENDIAN
26+
template <std::endian E>
27+
struct __attribute__((__packed__)) WebSocketFrameTiny;
28+
29+
template <>
30+
struct __attribute__((__packed__)) WebSocketFrameTiny<std::endian::little> {
2731
unsigned char opcode : 4;
2832
unsigned char rsv3 : 1;
2933
unsigned char rsv2 : 1;
3034
unsigned char rsv1 : 1;
3135
unsigned char fin : 1;
3236
unsigned char len : 7;
3337
unsigned char mask : 1;
34-
#elif O2_HOST_BYTE_ORDER == O2_BIG_ENDIAN
38+
};
39+
40+
template <>
41+
struct __attribute__((__packed__)) WebSocketFrameTiny<std::endian::big> {
3542
unsigned char fin : 1;
3643
unsigned char rsv1 : 1;
3744
unsigned char rsv2 : 1;
3845
unsigned char rsv3 : 1;
3946
unsigned char opcode : 4;
4047
unsigned char mask : 1;
4148
unsigned char len : 7;
42-
#else
43-
#error Uknown endiannes
44-
#endif
4549
};
4650

47-
struct __attribute__((__packed__)) WebSocketFrameShort {
48-
#if O2_HOST_BYTE_ORDER == O2_LITTLE_ENDIAN
51+
template <std::endian E>
52+
struct __attribute__((__packed__)) WebSocketFrameShort;
53+
54+
template <>
55+
struct __attribute__((__packed__)) WebSocketFrameShort<std::endian::little> {
4956
unsigned char opcode : 4;
5057
unsigned char rsv3 : 1;
5158
unsigned char rsv2 : 1;
5259
unsigned char rsv1 : 1;
5360
unsigned char fin : 1;
5461
unsigned char len : 7;
5562
unsigned char mask : 1;
56-
#elif O2_HOST_BYTE_ORDER == O2_BIG_ENDIAN
63+
uint16_t len16;
64+
};
65+
66+
template <>
67+
struct __attribute__((__packed__)) WebSocketFrameShort<std::endian::big> {
5768
unsigned char fin : 1;
5869
unsigned char rsv1 : 1;
5970
unsigned char rsv2 : 1;
6071
unsigned char rsv3 : 1;
6172
unsigned char opcode : 4;
6273
unsigned char mask : 1;
6374
unsigned char len : 7;
64-
#else
65-
#error Uknown endiannes
66-
#endif
6775
uint16_t len16;
6876
};
6977

70-
struct __attribute__((__packed__)) WebSocketFrameHuge {
71-
#if O2_HOST_BYTE_ORDER == O2_LITTLE_ENDIAN
78+
template <std::endian E>
79+
struct __attribute__((__packed__)) WebSocketFrameHuge;
80+
81+
template <>
82+
struct __attribute__((__packed__)) WebSocketFrameHuge<std::endian::little> {
7283
unsigned char opcode : 4;
7384
unsigned char rsv3 : 1;
7485
unsigned char rsv2 : 1;
7586
unsigned char rsv1 : 1;
7687
unsigned char fin : 1;
7788
unsigned char len : 7;
7889
unsigned char mask : 1;
79-
#elif O2_HOST_BYTE_ORDER == O2_BIG_ENDIAN
90+
uint64_t len64;
91+
};
92+
93+
template <>
94+
struct __attribute__((__packed__)) WebSocketFrameHuge<std::endian::big> {
8095
unsigned char fin : 1;
8196
unsigned char rsv1 : 1;
8297
unsigned char rsv2 : 1;
8398
unsigned char rsv3 : 1;
8499
unsigned char opcode : 4;
85100
unsigned char mask : 1;
86101
unsigned char len : 7;
87-
#else
88-
#error Uknown endiannes
89-
#endif
90102
uint64_t len64;
91103
};
92104

@@ -138,9 +150,9 @@ struct WebSocketHandler {
138150
virtual ~WebSocketHandler() = default;
139151

140152
/// Invoked when all the headers are received.
141-
virtual void headers(std::map<std::string, std::string> const& headers){};
153+
virtual void headers(std::map<std::string, std::string> const& headers) {};
142154
/// FIXME: not implemented
143-
virtual void beginFragmentation(){};
155+
virtual void beginFragmentation() {};
144156
/// Invoked when a frame it's parsed. Notice you do not own the data and you must
145157
/// not free the memory.
146158
virtual void frame(char const* frame, size_t s) {}
@@ -205,18 +217,18 @@ struct HTTPParser {
205217
std::string remaining;
206218
std::string error;
207219
std::vector<HTTPState> states;
208-
virtual void method(std::string_view const& s){};
209-
virtual void target(std::string_view const& s){};
210-
virtual void version(std::string_view const& s){};
211-
virtual void header(std::string_view const& k, std::string_view const& v){};
212-
virtual void endHeaders(){};
220+
virtual void method(std::string_view const& s) {};
221+
virtual void target(std::string_view const& s) {};
222+
virtual void version(std::string_view const& s) {};
223+
virtual void header(std::string_view const& k, std::string_view const& v) {};
224+
virtual void endHeaders() {};
213225
/// Invoked whenever we are parsing data.
214226
/// In order to allow for xoring (as required by the websocket standard)
215227
/// in place, we pass it as a mutable pointer.
216-
virtual void body(char* data, size_t s){};
217-
virtual void replyVersion(std::string_view const& s){};
218-
virtual void replyCode(std::string_view const& s){};
219-
virtual void replyMessage(std::string_view const& s){};
228+
virtual void body(char* data, size_t s) {};
229+
virtual void replyVersion(std::string_view const& s) {};
230+
virtual void replyCode(std::string_view const& s) {};
231+
virtual void replyMessage(std::string_view const& s) {};
220232
};
221233

222234
struct HTTPParserHelpers {

Framework/Foundation/CMakeLists.txt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ add_executable(o2-test-framework-foundation
3232
test/test_CallbackRegistry.cxx
3333
test/test_CompilerBuiltins.cxx
3434
# test/test_Signpost.cxx
35-
test/test_RuntimeError.cxx)
35+
test/test_RuntimeError.cxx
36+
test/test_BigEndian.cxx)
3637
target_link_libraries(o2-test-framework-foundation PRIVATE O2::FrameworkFoundation)
3738
target_link_libraries(o2-test-framework-foundation PRIVATE O2::Catch2)
3839

@@ -65,4 +66,10 @@ install(TARGETS o2-log RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
6566

6667
add_test(NAME framework:foundation COMMAND o2-test-framework-foundation)
6768

69+
add_executable(o2-benchmark-framework-BigEndian
70+
test/benchmark_BigEndian.cxx)
71+
target_link_libraries(o2-benchmark-framework-BigEndian
72+
PRIVATE O2::FrameworkFoundation benchmark::benchmark)
73+
set_property(TARGET o2-benchmark-framework-BigEndian PROPERTY RUNTIME_OUTPUT_DIRECTORY ${outdir})
74+
6875
add_subdirectory(3rdparty)
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Copyright 2019-2026 CERN and copyright holders of ALICE O2.
2+
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3+
// All rights not expressly granted are reserved.
4+
//
5+
// This software is distributed under the terms of the GNU General Public
6+
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7+
//
8+
// In applying this license CERN does not waive the privileges and immunities
9+
// granted to it by virtue of its status as an Intergovernmental Organization
10+
// or submit itself to any jurisdiction.
11+
12+
#ifndef O2_FRAMEWORK_BIGENDIAN_H_
13+
#define O2_FRAMEWORK_BIGENDIAN_H_
14+
15+
#include <bit>
16+
#include <cstddef>
17+
#include <cstdint>
18+
#include <cstring>
19+
20+
namespace o2::framework
21+
{
22+
23+
/// Copy @a count elements of @a typeSize bytes each from big-endian @a src
24+
/// into native byte order at @a dest. For typeSize == 1 or on big-endian
25+
/// platforms this reduces to a plain memcpy. @a dest and @a src must not overlap.
26+
inline void bigEndianCopy(void* dest, const void* src, int count, size_t typeSize)
27+
{
28+
auto const totalBytes = static_cast<size_t>(count) * typeSize;
29+
if constexpr (std::endian::native == std::endian::big) {
30+
std::memcpy(dest, src, totalBytes);
31+
return;
32+
}
33+
switch (typeSize) {
34+
case 2: {
35+
auto* p = static_cast<uint16_t*>(dest);
36+
auto* q = static_cast<const uint16_t*>(src);
37+
for (int i = 0; i < count; ++i) {
38+
p[i] = __builtin_bswap16(q[i]);
39+
}
40+
return;
41+
}
42+
case 4: {
43+
auto* p = static_cast<uint32_t*>(dest);
44+
auto* q = static_cast<const uint32_t*>(src);
45+
for (int i = 0; i < count; ++i) {
46+
p[i] = __builtin_bswap32(q[i]);
47+
}
48+
return;
49+
}
50+
case 8: {
51+
auto* p = static_cast<uint64_t*>(dest);
52+
auto* q = static_cast<const uint64_t*>(src);
53+
for (int i = 0; i < count; ++i) {
54+
p[i] = __builtin_bswap64(q[i]);
55+
}
56+
return;
57+
}
58+
}
59+
std::memcpy(dest, src, totalBytes);
60+
}
61+
62+
} // namespace o2::framework
63+
64+
#endif // O2_FRAMEWORK_BIGENDIAN_H_

0 commit comments

Comments
 (0)