Replace extension with eight-byte values

This commit is contained in:
Benoit Blanchon
2025-05-31 16:20:08 +02:00
parent bd2dccda0e
commit 94aacf873e
6 changed files with 77 additions and 71 deletions

View File

@@ -274,9 +274,9 @@
#endif #endif
#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_DOUBLE #if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_DOUBLE
# define ARDUINOJSON_USE_EXTENSIONS 1 # define ARDUINOJSON_USE_8_BYTE_VALUES 1
#else #else
# define ARDUINOJSON_USE_EXTENSIONS 0 # define ARDUINOJSON_USE_8_BYTE_VALUES 0
#endif #endif
#if defined(nullptr) #if defined(nullptr)

View File

@@ -18,12 +18,7 @@ class VariantData;
class VariantWithId; class VariantWithId;
class ResourceManager { class ResourceManager {
union SlotData { using SlotData = VariantData; // TODO: remove SlotData?
VariantData variant;
#if ARDUINOJSON_USE_EXTENSIONS
VariantExtension extension;
#endif
};
public: public:
constexpr static size_t slotSize = sizeof(SlotData); constexpr static size_t slotSize = sizeof(SlotData);
@@ -44,6 +39,7 @@ class ResourceManager {
swap(a.stringPool_, b.stringPool_); swap(a.stringPool_, b.stringPool_);
swap(a.variantPools_, b.variantPools_); swap(a.variantPools_, b.variantPools_);
swap(a.staticStringsPools_, b.staticStringsPools_); swap(a.staticStringsPools_, b.staticStringsPools_);
swap(a.lgValuePools_, b.lgValuePools_);
swap_(a.allocator_, b.allocator_); swap_(a.allocator_, b.allocator_);
swap_(a.overflowed_, b.overflowed_); swap_(a.overflowed_, b.overflowed_);
} }
@@ -64,10 +60,10 @@ class ResourceManager {
void freeVariant(Slot<VariantData> slot); void freeVariant(Slot<VariantData> slot);
VariantData* getVariant(SlotId id) const; VariantData* getVariant(SlotId id) const;
#if ARDUINOJSON_USE_EXTENSIONS #if ARDUINOJSON_USE_8_BYTE_VALUES
Slot<VariantExtension> allocExtension(); Slot<EightByteValue> allocEightByte();
void freeExtension(SlotId slot); void freeEightByte(SlotId slot);
VariantExtension* getExtension(SlotId id) const; EightByteValue* getEightByte(SlotId id) const;
#endif #endif
template <typename TAdaptedString> template <typename TAdaptedString>
@@ -136,11 +132,17 @@ class ResourceManager {
variantPools_.clear(allocator_); variantPools_.clear(allocator_);
stringPool_.clear(allocator_); stringPool_.clear(allocator_);
staticStringsPools_.clear(allocator_); staticStringsPools_.clear(allocator_);
#if ARDUINOJSON_USE_8_BYTE_VALUES
lgValuePools_.clear(allocator_);
#endif
} }
void shrinkToFit() { void shrinkToFit() {
variantPools_.shrinkToFit(allocator_); variantPools_.shrinkToFit(allocator_);
staticStringsPools_.shrinkToFit(allocator_); staticStringsPools_.shrinkToFit(allocator_);
#if ARDUINOJSON_USE_8_BYTE_VALUES
lgValuePools_.shrinkToFit(allocator_);
#endif
} }
private: private:
@@ -149,6 +151,9 @@ class ResourceManager {
StringPool stringPool_; StringPool stringPool_;
MemoryPoolList<SlotData> variantPools_; MemoryPoolList<SlotData> variantPools_;
MemoryPoolList<const char*> staticStringsPools_; MemoryPoolList<const char*> staticStringsPools_;
#if ARDUINOJSON_USE_8_BYTE_VALUES
MemoryPoolList<EightByteValue> eightBytePools_;
#endif
}; };
ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -29,23 +29,23 @@ inline VariantData* ResourceManager::getVariant(SlotId id) const {
return reinterpret_cast<VariantData*>(variantPools_.getSlot(id)); return reinterpret_cast<VariantData*>(variantPools_.getSlot(id));
} }
#if ARDUINOJSON_USE_EXTENSIONS #if ARDUINOJSON_USE_8_BYTE_VALUES
inline Slot<VariantExtension> ResourceManager::allocExtension() { inline Slot<EightByteValue> ResourceManager::allocEightByte() {
auto p = variantPools_.allocSlot(allocator_); auto slot = eightBytePools_.allocSlot(allocator_);
if (!p) { if (!slot) {
overflowed_ = true; overflowed_ = true;
return {}; return {};
} }
return {&p->extension, p.id()}; return slot;
} }
inline void ResourceManager::freeExtension(SlotId id) { inline void ResourceManager::freeEightByte(SlotId id) {
auto p = getExtension(id); auto p = getEightByte(id);
variantPools_.freeSlot({reinterpret_cast<SlotData*>(p), id}); eightBytePools_.freeSlot({p, id});
} }
inline VariantExtension* ResourceManager::getExtension(SlotId id) const { inline EightByteValue* ResourceManager::getEightByte(SlotId id) const {
return &variantPools_.getSlot(id)->extension; return eightBytePools_.getSlot(id).ptr();
} }
#endif #endif

View File

@@ -16,9 +16,7 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
enum class VariantTypeBits : uint8_t { enum class VariantTypeBits : uint8_t {
OwnedStringBit = 0x01, // 0000 0001 OwnedStringBit = 0x01, // 0000 0001
NumberBit = 0x08, // 0000 1000 NumberBit = 0x08, // 0000 1000
#if ARDUINOJSON_USE_EXTENSIONS EightByteBit = 0x10, // 0001 0000
ExtensionBit = 0x10, // 0001 0000
#endif
CollectionMask = 0x60, CollectionMask = 0x60,
}; };
@@ -64,8 +62,8 @@ union VariantContent {
char asTinyString[tinyStringMaxLength + 1]; char asTinyString[tinyStringMaxLength + 1];
}; };
#if ARDUINOJSON_USE_EXTENSIONS #if ARDUINOJSON_USE_8_BYTE_VALUES
union VariantExtension { union EightByteValue {
# if ARDUINOJSON_USE_LONG_LONG # if ARDUINOJSON_USE_LONG_LONG
uint64_t asUint64; uint64_t asUint64;
int64_t asInt64; int64_t asInt64;
@@ -74,6 +72,9 @@ union VariantExtension {
double asDouble; double asDouble;
# endif # endif
}; };
static_assert(sizeof(EightByteValue) == 8,
"sizeof(EightByteValue) must be 8 bytes");
#endif #endif
ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -53,8 +53,8 @@ class VariantData {
template <typename TVisitor> template <typename TVisitor>
typename TVisitor::result_type accept( typename TVisitor::result_type accept(
TVisitor& visit, const ResourceManager* resources) const { TVisitor& visit, const ResourceManager* resources) const {
#if ARDUINOJSON_USE_EXTENSIONS #if ARDUINOJSON_USE_EIGHT_BYTE_VALUES
auto extension = getExtension(resources); auto eightByteValue = getEightByte(resources);
#else #else
(void)resources; // silence warning (void)resources; // silence warning
#endif #endif
@@ -64,7 +64,7 @@ class VariantData {
#if ARDUINOJSON_USE_DOUBLE #if ARDUINOJSON_USE_DOUBLE
case VariantType::Double: case VariantType::Double:
return visit.visit(extension->asDouble); return visit.visit(eightByteValue->asDouble);
#endif #endif
case VariantType::Array: case VariantType::Array:
@@ -95,10 +95,10 @@ class VariantData {
#if ARDUINOJSON_USE_LONG_LONG #if ARDUINOJSON_USE_LONG_LONG
case VariantType::Int64: case VariantType::Int64:
return visit.visit(extension->asInt64); return visit.visit(eightByteValue->asInt64);
case VariantType::Uint64: case VariantType::Uint64:
return visit.visit(extension->asUint64); return visit.visit(eightByteValue->asUint64);
#endif #endif
case VariantType::Boolean: case VariantType::Boolean:
@@ -145,8 +145,8 @@ class VariantData {
} }
bool asBoolean(const ResourceManager* resources) const { bool asBoolean(const ResourceManager* resources) const {
#if ARDUINOJSON_USE_EXTENSIONS #if ARDUINOJSON_USE_EIGHT_BYTE_VALUES
auto extension = getExtension(resources); auto eightByteValue = getEightByte(resources);
#else #else
(void)resources; // silence warning (void)resources; // silence warning
#endif #endif
@@ -160,14 +160,14 @@ class VariantData {
return content_.asFloat != 0; return content_.asFloat != 0;
#if ARDUINOJSON_USE_DOUBLE #if ARDUINOJSON_USE_DOUBLE
case VariantType::Double: case VariantType::Double:
return extension->asDouble != 0; return eightByteValue->asDouble != 0;
#endif #endif
case VariantType::Null: case VariantType::Null:
return false; return false;
#if ARDUINOJSON_USE_LONG_LONG #if ARDUINOJSON_USE_LONG_LONG
case VariantType::Uint64: case VariantType::Uint64:
case VariantType::Int64: case VariantType::Int64:
return extension->asUint64 != 0; return eightByteValue->asUint64 != 0;
#endif #endif
default: default:
return true; return true;
@@ -193,8 +193,8 @@ class VariantData {
template <typename T> template <typename T>
T asFloat(const ResourceManager* resources) const { T asFloat(const ResourceManager* resources) const {
static_assert(is_floating_point<T>::value, "T must be a floating point"); static_assert(is_floating_point<T>::value, "T must be a floating point");
#if ARDUINOJSON_USE_EXTENSIONS #if ARDUINOJSON_USE_EIGHT_BYTE_VALUES
auto extension = getExtension(resources); auto eightByteValue = getEightByte(resources);
#else #else
(void)resources; // silence warning (void)resources; // silence warning
#endif #endif
@@ -208,9 +208,9 @@ class VariantData {
return static_cast<T>(content_.asInt32); return static_cast<T>(content_.asInt32);
#if ARDUINOJSON_USE_LONG_LONG #if ARDUINOJSON_USE_LONG_LONG
case VariantType::Uint64: case VariantType::Uint64:
return static_cast<T>(extension->asUint64); return static_cast<T>(eightByteValue->asUint64);
case VariantType::Int64: case VariantType::Int64:
return static_cast<T>(extension->asInt64); return static_cast<T>(eightByteValue->asInt64);
#endif #endif
case VariantType::TinyString: case VariantType::TinyString:
str = content_.asTinyString; str = content_.asTinyString;
@@ -225,7 +225,7 @@ class VariantData {
return static_cast<T>(content_.asFloat); return static_cast<T>(content_.asFloat);
#if ARDUINOJSON_USE_DOUBLE #if ARDUINOJSON_USE_DOUBLE
case VariantType::Double: case VariantType::Double:
return static_cast<T>(extension->asDouble); return static_cast<T>(eightByteValue->asDouble);
#endif #endif
default: default:
return 0.0; return 0.0;
@@ -238,8 +238,8 @@ class VariantData {
template <typename T> template <typename T>
T asIntegral(const ResourceManager* resources) const { T asIntegral(const ResourceManager* resources) const {
static_assert(is_integral<T>::value, "T must be an integral type"); static_assert(is_integral<T>::value, "T must be an integral type");
#if ARDUINOJSON_USE_EXTENSIONS #if ARDUINOJSON_USE_EIGHT_BYTE_VALUES
auto extension = getExtension(resources); auto eightByteValue = getEightByte(resources);
#else #else
(void)resources; // silence warning (void)resources; // silence warning
#endif #endif
@@ -253,9 +253,9 @@ class VariantData {
return convertNumber<T>(content_.asInt32); return convertNumber<T>(content_.asInt32);
#if ARDUINOJSON_USE_LONG_LONG #if ARDUINOJSON_USE_LONG_LONG
case VariantType::Uint64: case VariantType::Uint64:
return convertNumber<T>(extension->asUint64); return convertNumber<T>(eightByteValue->asUint64);
case VariantType::Int64: case VariantType::Int64:
return convertNumber<T>(extension->asInt64); return convertNumber<T>(eightByteValue->asInt64);
#endif #endif
case VariantType::TinyString: case VariantType::TinyString:
str = content_.asTinyString; str = content_.asTinyString;
@@ -270,7 +270,7 @@ class VariantData {
return convertNumber<T>(content_.asFloat); return convertNumber<T>(content_.asFloat);
#if ARDUINOJSON_USE_DOUBLE #if ARDUINOJSON_USE_DOUBLE
case VariantType::Double: case VariantType::Double:
return convertNumber<T>(extension->asDouble); return convertNumber<T>(eightByteValue->asDouble);
#endif #endif
default: default:
return 0; return 0;
@@ -314,8 +314,8 @@ class VariantData {
} }
} }
#if ARDUINOJSON_USE_EXTENSIONS #if ARDUINOJSON_USE_8_BYTE_VALUES
const VariantExtension* getExtension(const ResourceManager* resources) const; const EightByteValue* getEightByte(const ResourceManager* resources) const;
#endif #endif
VariantData* getElement(size_t index, VariantData* getElement(size_t index,
@@ -378,7 +378,7 @@ class VariantData {
template <typename T> template <typename T>
bool isInteger(const ResourceManager* resources) const { bool isInteger(const ResourceManager* resources) const {
#if ARDUINOJSON_USE_LONG_LONG #if ARDUINOJSON_USE_LONG_LONG
auto extension = getExtension(resources); auto eightByteValue = getEightByte(resources);
#else #else
(void)resources; // silence warning (void)resources; // silence warning
#endif #endif
@@ -391,10 +391,10 @@ class VariantData {
#if ARDUINOJSON_USE_LONG_LONG #if ARDUINOJSON_USE_LONG_LONG
case VariantType::Uint64: case VariantType::Uint64:
return canConvertNumber<T>(extension->asUint64); return canConvertNumber<T>(eightByteValue->asUint64);
case VariantType::Int64: case VariantType::Int64:
return canConvertNumber<T>(extension->asInt64); return canConvertNumber<T>(eightByteValue->asInt64);
#endif #endif
default: default:

View File

@@ -61,9 +61,9 @@ inline void VariantData::clear(ResourceManager* resources) {
if (type_ & VariantTypeBits::OwnedStringBit) if (type_ & VariantTypeBits::OwnedStringBit)
resources->dereferenceString(content_.asOwnedString->data); resources->dereferenceString(content_.asOwnedString->data);
#if ARDUINOJSON_USE_EXTENSIONS #if ARDUINOJSON_USE_EIGHT_BYTE_VALUES
if (type_ & VariantTypeBits::ExtensionBit) if (type_ & VariantTypeBits::EightByteBit)
resources->freeExtension(content_.asSlotId); resources->freeEightByte(content_.asSlotId);
#endif #endif
auto collection = asCollection(); auto collection = asCollection();
@@ -73,12 +73,12 @@ inline void VariantData::clear(ResourceManager* resources) {
type_ = VariantType::Null; type_ = VariantType::Null;
} }
#if ARDUINOJSON_USE_EXTENSIONS #if ARDUINOJSON_USE_EIGHT_BYTE_VALUES
inline const VariantExtension* VariantData::getExtension( inline const EightByteValue* VariantData::getEightByteValue(
const ResourceManager* resources) const { const ResourceManager* resources) const {
return type_ & VariantTypeBits::ExtensionBit return type_ & VariantTypeBits::EightByteBit
? resources->getExtension(content_.asSlotId) ? resources->getEightByteValue(content_.asSlotId)
: nullptr; : 0;
} }
#endif #endif
@@ -101,12 +101,12 @@ enable_if_t<sizeof(T) == 8, bool> VariantData::setFloat(
type_ = VariantType::Float; type_ = VariantType::Float;
content_.asFloat = valueAsFloat; content_.asFloat = valueAsFloat;
} else { } else {
auto extension = resources->allocExtension(); auto slot = resources->allocEightByte();
if (!extension) if (!slot)
return false; return false;
type_ = VariantType::Double; type_ = VariantType::Double;
content_.asSlotId = extension.id(); content_.asSlotId = slot.id();
extension->asDouble = value; slot->asDouble = value;
} }
#else #else
type_ = VariantType::Float; type_ = VariantType::Float;
@@ -127,12 +127,12 @@ enable_if_t<is_signed<T>::value, bool> VariantData::setInteger(
} }
#if ARDUINOJSON_USE_LONG_LONG #if ARDUINOJSON_USE_LONG_LONG
else { else {
auto extension = resources->allocExtension(); auto slot = resources->allocEightByte();
if (!extension) if (!slot)
return false; return false;
type_ = VariantType::Int64; type_ = VariantType::Int64;
content_.asSlotId = extension.id(); content_.asSlotId = slot.id();
extension->asInt64 = value; slot->asInt64 = value;
} }
#endif #endif
return true; return true;
@@ -150,12 +150,12 @@ enable_if_t<is_unsigned<T>::value, bool> VariantData::setInteger(
} }
#if ARDUINOJSON_USE_LONG_LONG #if ARDUINOJSON_USE_LONG_LONG
else { else {
auto extension = resources->allocExtension(); auto slot = resources->allocEightByte();
if (!extension) if (!slot)
return false; return false;
type_ = VariantType::Uint64; type_ = VariantType::Uint64;
content_.asSlotId = extension.id(); content_.asSlotId = slot.id();
extension->asUint64 = value; slot->asUint64 = value;
} }
#endif #endif
return true; return true;