From 8f5e8256cf9d6053fbe482e73869a6b35685beec Mon Sep 17 00:00:00 2001 From: David Capello Date: Wed, 22 Feb 2023 15:58:47 -0300 Subject: [PATCH] Replace INT/UINT_COMPATIBLE/IS_REDUCIBLE_INT macros w/templates --- src/app/file/ase_format.cpp | 21 ++++++++---- src/doc/user_data.cpp | 65 +++++++++++++++++++------------------ src/doc/user_data.h | 24 +++++++------- 3 files changed, 61 insertions(+), 49 deletions(-) diff --git a/src/app/file/ase_format.cpp b/src/app/file/ase_format.cpp index 221f95517..dde2bd184 100644 --- a/src/app/file/ase_format.cpp +++ b/src/app/file/ase_format.cpp @@ -1566,20 +1566,26 @@ static void ase_file_write_property_value(FILE* f, case USER_DATA_PROPERTY_TYPE_VECTOR: { auto& vector = *std::get_if(&value); fputl(vector.size(), f); + const uint16_t type = doc::all_elements_of_same_type(vector); fputw(type, f); + for (const auto& elem : vector) { UserData::Variant v = elem; + + // Reduce each element if possible, because each element has + // its own type. if (type == 0) { - if (IS_REDUCIBLE_INT(v.type())) { + if (is_reducible_int(v)) { v = reduce_int_type_size(v); } fputw(v.type(), f); } - else if (IS_REDUCIBLE_INT(v.type()) && type < v.type()) { - // We need to cast each value to the common type. + // Reduce to the smaller/common int type. + else if (is_reducible_int(v) && type < v.type()) { v = cast_to_smaller_int_type(v, type); } + ase_file_write_property_value(f, v); } break; @@ -1587,13 +1593,14 @@ static void ase_file_write_property_value(FILE* f, case USER_DATA_PROPERTY_TYPE_PROPERTIES: { auto& properties = *std::get_if(&value); ASSERT(properties.size() > 0); - fputl(properties.size(), f); - for (auto property : properties) { + + for (const auto& property : properties) { const std::string& name = property.first; ase_file_write_string(f, name); + UserData::Variant v = property.second; - if (IS_REDUCIBLE_INT(v.type())) { + if (is_reducible_int(v)) { v = reduce_int_type_size(v); } fputw(v.type(), f); @@ -1619,7 +1626,7 @@ static void ase_file_write_properties_maps(FILE* f, FileOp* fop, fputl(0, f); fputl(nmaps, f); - for (auto propertiesMap : propertiesMaps) { + for (const auto& propertiesMap : propertiesMaps) { const UserData::Properties& properties = propertiesMap.second; // Skip properties map if it doesn't have any property if (properties.empty()) diff --git a/src/doc/user_data.cpp b/src/doc/user_data.cpp index 025e15c37..7064a96eb 100644 --- a/src/doc/user_data.cpp +++ b/src/doc/user_data.cpp @@ -49,14 +49,15 @@ uint16_t all_elements_of_same_type(const UserData::Vector& vector) uint16_t type = vector.empty() ? 0 : vector.front().type(); uint16_t commonReducedType = 0; bool hasNegativeNumbers = false; - for (auto value : vector) { + + for (const auto& value : vector) { if (type != value.type()) { return 0; } - else if (IS_REDUCIBLE_INT(value.type())) { + else if (is_reducible_int(value)) { auto t = reduce_int_type_size(value).type(); hasNegativeNumbers |= is_negative(value); - if (t > commonReducedType) { + if (commonReducedType < t) { commonReducedType = t; } } @@ -69,14 +70,16 @@ uint16_t all_elements_of_same_type(const UserData::Vector& vector) // If our common reduced type is unsigned and we have negative numbers // in our vector we should select the next signed type that includes it. if (commonReducedType != 0 && - (commonReducedType & 1) && + (commonReducedType & 1) && // TODO fix this assumption about USER_DATA_PROPERTY_TYPE_* values hasNegativeNumbers) { commonReducedType++; - // We couldn't find one type that satisfies all the integers. This shouldn't ever happen. - if (commonReducedType >= USER_DATA_PROPERTY_TYPE_UINT64) commonReducedType = 0; + // We couldn't find one type that satisfies all the integers. This + // shouldn't ever happen. + if (commonReducedType >= USER_DATA_PROPERTY_TYPE_UINT64) + commonReducedType = 0; } - return commonReducedType ? commonReducedType : type; + return (commonReducedType ? commonReducedType : type); } UserData::Variant cast_to_smaller_int_type(const UserData::Variant& value, uint16_t type) @@ -164,50 +167,50 @@ UserData::Variant reduce_int_type_size(const UserData::Variant& value) switch (value.type()) { case USER_DATA_PROPERTY_TYPE_INT16: { auto v = get_value(value); - if (INT8_COMPATIBLE(v)) return static_cast(v); - else if (UINT8_COMPATIBLE(v)) return static_cast(v); + if (is_compatible_int(v)) return static_cast(v); + else if (is_compatible_int(v)) return static_cast(v); return v; } case USER_DATA_PROPERTY_TYPE_UINT16: { auto v = get_value(value); - if (INT8_COMPATIBLE(v)) return static_cast(v); - else if (UINT8_COMPATIBLE(v)) return static_cast(v); + if (is_compatible_int(v)) return static_cast(v); + else if (is_compatible_int(v)) return static_cast(v); return v; } case USER_DATA_PROPERTY_TYPE_INT32: { auto v = get_value(value); - if (INT8_COMPATIBLE(v)) return static_cast(v); - else if (UINT8_COMPATIBLE(v)) return static_cast(v); - else if (INT16_COMPATIBLE(v)) return static_cast(v); - else if (UINT16_COMPATIBLE(v)) return static_cast(v); + if (is_compatible_int(v)) return static_cast(v); + else if (is_compatible_int(v)) return static_cast(v); + else if (is_compatible_int(v)) return static_cast(v); + else if (is_compatible_int(v)) return static_cast(v); return v; } case USER_DATA_PROPERTY_TYPE_UINT32: { auto v = get_value(value); - if (INT8_COMPATIBLE(v)) return static_cast(v); - else if (UINT8_COMPATIBLE(v)) return static_cast(v); - else if (INT16_COMPATIBLE(v)) return static_cast(v); - else if (UINT16_COMPATIBLE(v)) return static_cast(v); + if (is_compatible_int(v)) return static_cast(v); + else if (is_compatible_int(v)) return static_cast(v); + else if (is_compatible_int(v)) return static_cast(v); + else if (is_compatible_int(v)) return static_cast(v); return v; } case USER_DATA_PROPERTY_TYPE_INT64: { auto v = get_value(value); - if (INT8_COMPATIBLE(v)) return static_cast(v); - else if (UINT8_COMPATIBLE(v)) return static_cast(v); - else if (INT16_COMPATIBLE(v)) return static_cast(v); - else if (UINT16_COMPATIBLE(v)) return static_cast(v); - else if (INT32_COMPATIBLE(v)) return static_cast(v); - else if (UINT32_COMPATIBLE(v)) return static_cast(v); + if (is_compatible_int(v)) return static_cast(v); + else if (is_compatible_int(v)) return static_cast(v); + else if (is_compatible_int(v)) return static_cast(v); + else if (is_compatible_int(v)) return static_cast(v); + else if (is_compatible_int(v)) return static_cast(v); + else if (is_compatible_int(v)) return static_cast(v); return v; } case USER_DATA_PROPERTY_TYPE_UINT64: { auto v = get_value(value); - if (INT8_COMPATIBLE(v)) return static_cast(v); - else if (UINT8_COMPATIBLE(v)) return static_cast(v); - else if (INT16_COMPATIBLE(v)) return static_cast(v); - else if (UINT16_COMPATIBLE(v)) return static_cast(v); - else if (INT32_COMPATIBLE(v)) return static_cast(v); - else if (UINT32_COMPATIBLE(v)) return static_cast(v); + if (is_compatible_int(v)) return static_cast(v); + else if (is_compatible_int(v)) return static_cast(v); + else if (is_compatible_int(v)) return static_cast(v); + else if (is_compatible_int(v)) return static_cast(v); + else if (is_compatible_int(v)) return static_cast(v); + else if (is_compatible_int(v)) return static_cast(v); return v; } default: diff --git a/src/doc/user_data.h b/src/doc/user_data.h index b55e17b1a..3132c990f 100644 --- a/src/doc/user_data.h +++ b/src/doc/user_data.h @@ -16,6 +16,7 @@ #include "gfx/rect.h" #include +#include #include #include #include @@ -42,17 +43,6 @@ #define USER_DATA_PROPERTY_TYPE_VECTOR 0x0011 #define USER_DATA_PROPERTY_TYPE_PROPERTIES 0x0012 -#define INT8_COMPATIBLE(i) i >= -128 && i <= 127 -#define UINT8_COMPATIBLE(i) i >= 128 && i <= 255 -#define INT16_COMPATIBLE(i) i >= -32768 && i <= 32767 -#define UINT16_COMPATIBLE(i) i >= 32768 && i <= 65535 -// The (int) cast is to make MSVC happy. If we remove it, the condition could -// be jumped. -#define INT32_COMPATIBLE(i) i >= ((int)-2147483648) && i <= 2147483647 -#define UINT32_COMPATIBLE(i) i >= 2147483648 && i <= 4294967295 - -#define IS_REDUCIBLE_INT(variantType) variantType >= USER_DATA_PROPERTY_TYPE_INT16 && variantType <= USER_DATA_PROPERTY_TYPE_UINT64 - namespace doc { class UserData { @@ -158,6 +148,18 @@ namespace doc { return *value; } + template + inline bool is_compatible_int(const U u) { + static_assert(sizeof(U) > sizeof(T), "T type must be smaller than U type"); + return (u >= std::numeric_limits::min() && + u <= std::numeric_limits::max()); + } + + inline bool is_reducible_int(const UserData::Variant& variant) { + return (variant.type() >= USER_DATA_PROPERTY_TYPE_INT16 && + variant.type() <= USER_DATA_PROPERTY_TYPE_UINT64); + } + size_t count_nonempty_properties_maps(const UserData::PropertiesMaps& propertiesMaps); // If all the elements of vector have the same type, returns that type, also