Skip to content

Commit

Permalink
src: convert all endian checks to constexpr
Browse files Browse the repository at this point in the history
This is finally possible in C++20 without having to rely on
compiler-defined macros, assuming none of our supported platforms are
mixed-endian.

Refs: nodejs#44411
PR-URL: nodejs#52974
Reviewed-By: Yagiz Nizipli <yagiz.nizipli@sentry.io>
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information
tniessen committed May 25, 2024
1 parent 0cbbab9 commit 177b8b9
Show file tree
Hide file tree
Showing 5 changed files with 21 additions and 27 deletions.
4 changes: 2 additions & 2 deletions src/node_buffer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -666,7 +666,7 @@ void Fill(const FunctionCallbackInfo<Value>& args) {
} else if (enc == UCS2) {
str_length = str_obj->Length() * sizeof(uint16_t);
node::TwoByteValue str(env->isolate(), args[1]);
if (IsBigEndian())
if constexpr (IsBigEndian())
SwapBytes16(reinterpret_cast<char*>(&str[0]), str_length);

memcpy(ts_obj_data + start, *str, std::min(str_length, fill_length));
Expand Down Expand Up @@ -960,7 +960,7 @@ void IndexOfString(const FunctionCallbackInfo<Value>& args) {
return args.GetReturnValue().Set(-1);
}

if (IsBigEndian()) {
if constexpr (IsBigEndian()) {
StringBytes::InlineDecoder decoder;
if (decoder.Decode(env, needle, enc).IsNothing()) return;
const uint16_t* decoded_string =
Expand Down
10 changes: 6 additions & 4 deletions src/node_file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2262,10 +2262,12 @@ static void WriteString(const FunctionCallbackInfo<Value>& args) {
auto ext = string->GetExternalOneByteStringResource();
buf = const_cast<char*>(ext->data());
len = ext->length();
} else if (enc == UCS2 && IsLittleEndian() && string->IsExternalTwoByte()) {
auto ext = string->GetExternalStringResource();
buf = reinterpret_cast<char*>(const_cast<uint16_t*>(ext->data()));
len = ext->length() * sizeof(*ext->data());
} else if (enc == UCS2 && string->IsExternalTwoByte()) {
if constexpr (IsLittleEndian()) {
auto ext = string->GetExternalStringResource();
buf = reinterpret_cast<char*>(const_cast<uint16_t*>(ext->data()));
len = ext->length() * sizeof(*ext->data());
}
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/node_i18n.cc
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ MaybeLocal<Object> ToBufferEndian(Environment* env, MaybeStackBuffer<T>* buf) {

static_assert(sizeof(T) == 1 || sizeof(T) == 2,
"Currently only one- or two-byte buffers are supported");
if (sizeof(T) > 1 && IsBigEndian()) {
if constexpr (sizeof(T) > 1 && IsBigEndian()) {
SPREAD_BUFFER_ARG(ret.ToLocalChecked(), retbuf);
SwapBytes16(retbuf_data, retbuf_length);
}
Expand All @@ -128,7 +128,7 @@ void CopySourceBuffer(MaybeStackBuffer<UChar>* dest,
dest->AllocateSufficientStorage(length_in_chars);
char* dst = reinterpret_cast<char*>(**dest);
memcpy(dst, data, length);
if (IsBigEndian()) {
if constexpr (IsBigEndian()) {
SwapBytes16(dst, length);
}
}
Expand Down Expand Up @@ -527,7 +527,7 @@ void ConverterObject::Decode(const FunctionCallbackInfo<Value>& args) {

char* value = reinterpret_cast<char*>(output) + beginning;

if (IsBigEndian()) {
if constexpr (IsBigEndian()) {
SwapBytes16(value, length);
}

Expand Down
7 changes: 3 additions & 4 deletions src/string_bytes.cc
Original file line number Diff line number Diff line change
Expand Up @@ -339,8 +339,7 @@ size_t StringBytes::Write(Isolate* isolate,
// the Buffer, so we need to reorder on BE platforms. See
// https://nodejs.org/api/buffer.html regarding Node's "ucs2"
// encoding specification
if (IsBigEndian())
SwapBytes16(buf, nbytes);
if constexpr (IsBigEndian()) SwapBytes16(buf, nbytes);

break;
}
Expand Down Expand Up @@ -756,7 +755,7 @@ MaybeLocal<Value> StringBytes::Encode(Isolate* isolate,

case UCS2: {
size_t str_len = buflen / 2;
if (IsBigEndian()) {
if constexpr (IsBigEndian()) {
uint16_t* dst = node::UncheckedMalloc<uint16_t>(str_len);
if (str_len != 0 && dst == nullptr) {
*error = node::ERR_MEMORY_ALLOCATION_FAILED(isolate);
Expand Down Expand Up @@ -803,7 +802,7 @@ MaybeLocal<Value> StringBytes::Encode(Isolate* isolate,
// Buffer, so we need to reorder on BE platforms. See
// https://nodejs.org/api/buffer.html regarding Node's "ucs2"
// encoding specification
if (IsBigEndian()) {
if constexpr (IsBigEndian()) {
uint16_t* dst = node::UncheckedMalloc<uint16_t>(buflen);
if (dst == nullptr) {
*error = node::ERR_MEMORY_ALLOCATION_FAILED(isolate);
Expand Down
21 changes: 7 additions & 14 deletions src/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include <cstring>

#include <array>
#include <bit>
#include <limits>
#include <memory>
#include <set>
Expand Down Expand Up @@ -778,24 +779,16 @@ inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
.Check(); \
} while (0)

enum class Endianness { LITTLE, BIG };

inline Endianness GetEndianness() {
// Constant-folded by the compiler.
const union {
uint8_t u8[2];
uint16_t u16;
} u = {{1, 0}};
return u.u16 == 1 ? Endianness::LITTLE : Endianness::BIG;
constexpr inline bool IsLittleEndian() {
return std::endian::native == std::endian::little;
}

inline bool IsLittleEndian() {
return GetEndianness() == Endianness::LITTLE;
constexpr inline bool IsBigEndian() {
return std::endian::native == std::endian::big;
}

inline bool IsBigEndian() {
return GetEndianness() == Endianness::BIG;
}
static_assert(IsLittleEndian() || IsBigEndian(),
"Node.js does not support mixed-endian systems");

// Round up a to the next highest multiple of b.
template <typename T>
Expand Down

0 comments on commit 177b8b9

Please sign in to comment.