Replace INT/UINT_COMPATIBLE/IS_REDUCIBLE_INT macros w/templates

This commit is contained in:
David Capello 2023-02-22 15:58:47 -03:00
parent 70a388177d
commit 8f5e8256cf
3 changed files with 61 additions and 49 deletions

View File

@ -1566,20 +1566,26 @@ static void ase_file_write_property_value(FILE* f,
case USER_DATA_PROPERTY_TYPE_VECTOR: {
auto& vector = *std::get_if<UserData::Vector>(&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<UserData::Properties>(&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())

View File

@ -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<int16_t>(value);
if (INT8_COMPATIBLE(v)) return static_cast<int8_t>(v);
else if (UINT8_COMPATIBLE(v)) return static_cast<uint8_t>(v);
if (is_compatible_int<int8_t>(v)) return static_cast<int8_t>(v);
else if (is_compatible_int<uint8_t>(v)) return static_cast<uint8_t>(v);
return v;
}
case USER_DATA_PROPERTY_TYPE_UINT16: {
auto v = get_value<uint16_t>(value);
if (INT8_COMPATIBLE(v)) return static_cast<int8_t>(v);
else if (UINT8_COMPATIBLE(v)) return static_cast<uint8_t>(v);
if (is_compatible_int<int8_t>(v)) return static_cast<int8_t>(v);
else if (is_compatible_int<uint8_t>(v)) return static_cast<uint8_t>(v);
return v;
}
case USER_DATA_PROPERTY_TYPE_INT32: {
auto v = get_value<int32_t>(value);
if (INT8_COMPATIBLE(v)) return static_cast<int8_t>(v);
else if (UINT8_COMPATIBLE(v)) return static_cast<uint8_t>(v);
else if (INT16_COMPATIBLE(v)) return static_cast<int16_t>(v);
else if (UINT16_COMPATIBLE(v)) return static_cast<uint16_t>(v);
if (is_compatible_int<int8_t>(v)) return static_cast<int8_t>(v);
else if (is_compatible_int<uint8_t>(v)) return static_cast<uint8_t>(v);
else if (is_compatible_int<int16_t>(v)) return static_cast<int16_t>(v);
else if (is_compatible_int<uint16_t>(v)) return static_cast<uint16_t>(v);
return v;
}
case USER_DATA_PROPERTY_TYPE_UINT32: {
auto v = get_value<uint32_t>(value);
if (INT8_COMPATIBLE(v)) return static_cast<int8_t>(v);
else if (UINT8_COMPATIBLE(v)) return static_cast<uint8_t>(v);
else if (INT16_COMPATIBLE(v)) return static_cast<int16_t>(v);
else if (UINT16_COMPATIBLE(v)) return static_cast<uint16_t>(v);
if (is_compatible_int<int8_t>(v)) return static_cast<int8_t>(v);
else if (is_compatible_int<uint8_t>(v)) return static_cast<uint8_t>(v);
else if (is_compatible_int<int16_t>(v)) return static_cast<int16_t>(v);
else if (is_compatible_int<uint16_t>(v)) return static_cast<uint16_t>(v);
return v;
}
case USER_DATA_PROPERTY_TYPE_INT64: {
auto v = get_value<int64_t>(value);
if (INT8_COMPATIBLE(v)) return static_cast<int8_t>(v);
else if (UINT8_COMPATIBLE(v)) return static_cast<uint8_t>(v);
else if (INT16_COMPATIBLE(v)) return static_cast<int16_t>(v);
else if (UINT16_COMPATIBLE(v)) return static_cast<uint16_t>(v);
else if (INT32_COMPATIBLE(v)) return static_cast<int32_t>(v);
else if (UINT32_COMPATIBLE(v)) return static_cast<uint32_t>(v);
if (is_compatible_int<int8_t>(v)) return static_cast<int8_t>(v);
else if (is_compatible_int<uint8_t>(v)) return static_cast<uint8_t>(v);
else if (is_compatible_int<int16_t>(v)) return static_cast<int16_t>(v);
else if (is_compatible_int<uint16_t>(v)) return static_cast<uint16_t>(v);
else if (is_compatible_int<int32_t>(v)) return static_cast<int32_t>(v);
else if (is_compatible_int<uint32_t>(v)) return static_cast<uint32_t>(v);
return v;
}
case USER_DATA_PROPERTY_TYPE_UINT64: {
auto v = get_value<uint64_t>(value);
if (INT8_COMPATIBLE(v)) return static_cast<int8_t>(v);
else if (UINT8_COMPATIBLE(v)) return static_cast<uint8_t>(v);
else if (INT16_COMPATIBLE(v)) return static_cast<int16_t>(v);
else if (UINT16_COMPATIBLE(v)) return static_cast<uint16_t>(v);
else if (INT32_COMPATIBLE(v)) return static_cast<int32_t>(v);
else if (UINT32_COMPATIBLE(v)) return static_cast<uint32_t>(v);
if (is_compatible_int<int8_t>(v)) return static_cast<int8_t>(v);
else if (is_compatible_int<uint8_t>(v)) return static_cast<uint8_t>(v);
else if (is_compatible_int<int16_t>(v)) return static_cast<int16_t>(v);
else if (is_compatible_int<uint16_t>(v)) return static_cast<uint16_t>(v);
else if (is_compatible_int<int32_t>(v)) return static_cast<int32_t>(v);
else if (is_compatible_int<uint32_t>(v)) return static_cast<uint32_t>(v);
return v;
}
default:

View File

@ -16,6 +16,7 @@
#include "gfx/rect.h"
#include <cstddef>
#include <limits>
#include <map>
#include <stdexcept>
#include <string>
@ -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<typename T, typename U>
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<T>::min() &&
u <= std::numeric_limits<T>::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