0
0
mirror of https://github.com/nodejs/node.git synced 2024-11-24 12:10:08 +01:00

src: convert all endian checks to constexpr

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: https://github.com/nodejs/node/pull/44411
PR-URL: https://github.com/nodejs/node/pull/52974
Reviewed-By: Yagiz Nizipli <yagiz.nizipli@sentry.io>
Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
Tobias Nießen 2024-05-25 11:04:20 +02:00 committed by GitHub
parent 0cbbab9a4d
commit 177b8b957b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 21 additions and 27 deletions

View File

@ -666,7 +666,7 @@ void Fill(const FunctionCallbackInfo<Value>& args) {
} else if (enc == UCS2) { } else if (enc == UCS2) {
str_length = str_obj->Length() * sizeof(uint16_t); str_length = str_obj->Length() * sizeof(uint16_t);
node::TwoByteValue str(env->isolate(), args[1]); node::TwoByteValue str(env->isolate(), args[1]);
if (IsBigEndian()) if constexpr (IsBigEndian())
SwapBytes16(reinterpret_cast<char*>(&str[0]), str_length); SwapBytes16(reinterpret_cast<char*>(&str[0]), str_length);
memcpy(ts_obj_data + start, *str, std::min(str_length, fill_length)); memcpy(ts_obj_data + start, *str, std::min(str_length, fill_length));
@ -960,7 +960,7 @@ void IndexOfString(const FunctionCallbackInfo<Value>& args) {
return args.GetReturnValue().Set(-1); return args.GetReturnValue().Set(-1);
} }
if (IsBigEndian()) { if constexpr (IsBigEndian()) {
StringBytes::InlineDecoder decoder; StringBytes::InlineDecoder decoder;
if (decoder.Decode(env, needle, enc).IsNothing()) return; if (decoder.Decode(env, needle, enc).IsNothing()) return;
const uint16_t* decoded_string = const uint16_t* decoded_string =

View File

@ -2262,10 +2262,12 @@ static void WriteString(const FunctionCallbackInfo<Value>& args) {
auto ext = string->GetExternalOneByteStringResource(); auto ext = string->GetExternalOneByteStringResource();
buf = const_cast<char*>(ext->data()); buf = const_cast<char*>(ext->data());
len = ext->length(); len = ext->length();
} else if (enc == UCS2 && IsLittleEndian() && string->IsExternalTwoByte()) { } else if (enc == UCS2 && string->IsExternalTwoByte()) {
auto ext = string->GetExternalStringResource(); if constexpr (IsLittleEndian()) {
buf = reinterpret_cast<char*>(const_cast<uint16_t*>(ext->data())); auto ext = string->GetExternalStringResource();
len = ext->length() * sizeof(*ext->data()); buf = reinterpret_cast<char*>(const_cast<uint16_t*>(ext->data()));
len = ext->length() * sizeof(*ext->data());
}
} }
} }

View File

@ -111,7 +111,7 @@ MaybeLocal<Object> ToBufferEndian(Environment* env, MaybeStackBuffer<T>* buf) {
static_assert(sizeof(T) == 1 || sizeof(T) == 2, static_assert(sizeof(T) == 1 || sizeof(T) == 2,
"Currently only one- or two-byte buffers are supported"); "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); SPREAD_BUFFER_ARG(ret.ToLocalChecked(), retbuf);
SwapBytes16(retbuf_data, retbuf_length); SwapBytes16(retbuf_data, retbuf_length);
} }
@ -128,7 +128,7 @@ void CopySourceBuffer(MaybeStackBuffer<UChar>* dest,
dest->AllocateSufficientStorage(length_in_chars); dest->AllocateSufficientStorage(length_in_chars);
char* dst = reinterpret_cast<char*>(**dest); char* dst = reinterpret_cast<char*>(**dest);
memcpy(dst, data, length); memcpy(dst, data, length);
if (IsBigEndian()) { if constexpr (IsBigEndian()) {
SwapBytes16(dst, length); SwapBytes16(dst, length);
} }
} }
@ -527,7 +527,7 @@ void ConverterObject::Decode(const FunctionCallbackInfo<Value>& args) {
char* value = reinterpret_cast<char*>(output) + beginning; char* value = reinterpret_cast<char*>(output) + beginning;
if (IsBigEndian()) { if constexpr (IsBigEndian()) {
SwapBytes16(value, length); SwapBytes16(value, length);
} }

View File

@ -339,8 +339,7 @@ size_t StringBytes::Write(Isolate* isolate,
// the Buffer, so we need to reorder on BE platforms. See // the Buffer, so we need to reorder on BE platforms. See
// https://nodejs.org/api/buffer.html regarding Node's "ucs2" // https://nodejs.org/api/buffer.html regarding Node's "ucs2"
// encoding specification // encoding specification
if (IsBigEndian()) if constexpr (IsBigEndian()) SwapBytes16(buf, nbytes);
SwapBytes16(buf, nbytes);
break; break;
} }
@ -756,7 +755,7 @@ MaybeLocal<Value> StringBytes::Encode(Isolate* isolate,
case UCS2: { case UCS2: {
size_t str_len = buflen / 2; size_t str_len = buflen / 2;
if (IsBigEndian()) { if constexpr (IsBigEndian()) {
uint16_t* dst = node::UncheckedMalloc<uint16_t>(str_len); uint16_t* dst = node::UncheckedMalloc<uint16_t>(str_len);
if (str_len != 0 && dst == nullptr) { if (str_len != 0 && dst == nullptr) {
*error = node::ERR_MEMORY_ALLOCATION_FAILED(isolate); *error = node::ERR_MEMORY_ALLOCATION_FAILED(isolate);
@ -803,7 +802,7 @@ MaybeLocal<Value> StringBytes::Encode(Isolate* isolate,
// Buffer, so we need to reorder on BE platforms. See // Buffer, so we need to reorder on BE platforms. See
// https://nodejs.org/api/buffer.html regarding Node's "ucs2" // https://nodejs.org/api/buffer.html regarding Node's "ucs2"
// encoding specification // encoding specification
if (IsBigEndian()) { if constexpr (IsBigEndian()) {
uint16_t* dst = node::UncheckedMalloc<uint16_t>(buflen); uint16_t* dst = node::UncheckedMalloc<uint16_t>(buflen);
if (dst == nullptr) { if (dst == nullptr) {
*error = node::ERR_MEMORY_ALLOCATION_FAILED(isolate); *error = node::ERR_MEMORY_ALLOCATION_FAILED(isolate);

View File

@ -37,6 +37,7 @@
#include <cstring> #include <cstring>
#include <array> #include <array>
#include <bit>
#include <limits> #include <limits>
#include <memory> #include <memory>
#include <set> #include <set>
@ -778,24 +779,16 @@ inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
.Check(); \ .Check(); \
} while (0) } while (0)
enum class Endianness { LITTLE, BIG }; constexpr inline bool IsLittleEndian() {
return std::endian::native == std::endian::little;
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;
} }
inline bool IsLittleEndian() { constexpr inline bool IsBigEndian() {
return GetEndianness() == Endianness::LITTLE; return std::endian::native == std::endian::big;
} }
inline bool IsBigEndian() { static_assert(IsLittleEndian() || IsBigEndian(),
return GetEndianness() == Endianness::BIG; "Node.js does not support mixed-endian systems");
}
// Round up a to the next highest multiple of b. // Round up a to the next highest multiple of b.
template <typename T> template <typename T>