Move code related to UserData::Variants to doc/user_data.cpp

Only code that is related to <iostream> IO is in _io.cpp files.
This commit is contained in:
David Capello 2023-02-22 15:22:35 -03:00
parent a7b5ab24bb
commit 70a388177d
4 changed files with 255 additions and 246 deletions

View File

@ -1,5 +1,5 @@
# Aseprite Document Library
# Copyright (C) 2019-2022 Igara Studio S.A.
# Copyright (C) 2019-2023 Igara Studio S.A.
# Copyright (C) 2001-2018 David Capello
if(WIN32)
@ -74,6 +74,7 @@ add_library(doc-lib
tileset.cpp
tileset_io.cpp
tilesets.cpp
user_data.cpp
user_data_io.cpp
util.cpp)

218
src/doc/user_data.cpp Normal file
View File

@ -0,0 +1,218 @@
// Aseprite Document Library
// Copyright (c) 2023 Igara Studio S.A.
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "doc/user_data.h"
namespace doc {
size_t count_nonempty_properties_maps(const UserData::PropertiesMaps& propertiesMaps)
{
size_t i = 0;
for (const auto& it : propertiesMaps)
if (!it.second.empty())
++i;
return i;
}
static bool is_negative(const UserData::Variant& value)
{
switch (value.type()) {
case USER_DATA_PROPERTY_TYPE_INT8: {
auto v = get_value<int8_t>(value);
return v < 0;
}
case USER_DATA_PROPERTY_TYPE_INT16: {
auto v = get_value<int16_t>(value);
return v < 0;
}
case USER_DATA_PROPERTY_TYPE_INT32: {
auto v = get_value<int32_t>(value);
return v < 0;
}
case USER_DATA_PROPERTY_TYPE_INT64: {
auto v = get_value<int64_t>(value);
return v < 0;
}
}
return false;
}
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) {
if (type != value.type()) {
return 0;
}
else if (IS_REDUCIBLE_INT(value.type())) {
auto t = reduce_int_type_size(value).type();
hasNegativeNumbers |= is_negative(value);
if (t > commonReducedType) {
commonReducedType = t;
}
}
}
// TODO: The following check probably is not useful right now, I believe this could
// become useful if at some point we want to try to find a common integer type for vectors
// that contains elements of different integer types only.
// 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) &&
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;
}
return commonReducedType ? commonReducedType : type;
}
UserData::Variant cast_to_smaller_int_type(const UserData::Variant& value, uint16_t type)
{
ASSERT(type < value.type());
switch (value.type()) {
case USER_DATA_PROPERTY_TYPE_INT16: {
auto v = get_value<int16_t>(value);
if (type == USER_DATA_PROPERTY_TYPE_INT8)
return static_cast<int8_t>(v);
else if (type == USER_DATA_PROPERTY_TYPE_UINT8)
return static_cast<uint8_t>(v);
break;
}
case USER_DATA_PROPERTY_TYPE_UINT16: {
auto v = get_value<uint16_t>(value);
if (type == USER_DATA_PROPERTY_TYPE_INT8)
return static_cast<int8_t>(v);
else if (type == USER_DATA_PROPERTY_TYPE_UINT8)
return static_cast<uint8_t>(v);
break;
}
case USER_DATA_PROPERTY_TYPE_INT32: {
auto v = get_value<int32_t>(value);
if (type == USER_DATA_PROPERTY_TYPE_INT8)
return static_cast<int8_t>(v);
else if (type == USER_DATA_PROPERTY_TYPE_UINT8)
return static_cast<uint8_t>(v);
else if (type == USER_DATA_PROPERTY_TYPE_INT16)
return static_cast<int16_t>(v);
else if (type == USER_DATA_PROPERTY_TYPE_UINT16)
return static_cast<uint16_t>(v);
break;
}
case USER_DATA_PROPERTY_TYPE_UINT32: {
auto v = get_value<uint32_t>(value);
if (type == USER_DATA_PROPERTY_TYPE_INT8)
return static_cast<int8_t>(v);
else if (type == USER_DATA_PROPERTY_TYPE_UINT8)
return static_cast<uint8_t>(v);
else if (type == USER_DATA_PROPERTY_TYPE_INT16)
return static_cast<int16_t>(v);
else if (type == USER_DATA_PROPERTY_TYPE_UINT16)
return static_cast<uint16_t>(v);
break;
}
case USER_DATA_PROPERTY_TYPE_INT64: {
auto v = get_value<int64_t>(value);
if (type == USER_DATA_PROPERTY_TYPE_INT8)
return static_cast<int8_t>(v);
else if (type == USER_DATA_PROPERTY_TYPE_UINT8)
return static_cast<uint8_t>(v);
else if (type == USER_DATA_PROPERTY_TYPE_INT16)
return static_cast<int16_t>(v);
else if (type == USER_DATA_PROPERTY_TYPE_UINT16)
return static_cast<uint16_t>(v);
else if (type == USER_DATA_PROPERTY_TYPE_INT32)
return static_cast<int32_t>(v);
else if (type == USER_DATA_PROPERTY_TYPE_UINT32)
return static_cast<uint32_t>(v);
break;
}
case USER_DATA_PROPERTY_TYPE_UINT64: {
auto v = get_value<uint64_t>(value);
if (type == USER_DATA_PROPERTY_TYPE_INT8)
return static_cast<int8_t>(v);
else if (type == USER_DATA_PROPERTY_TYPE_UINT8)
return static_cast<uint8_t>(v);
else if (type == USER_DATA_PROPERTY_TYPE_INT16)
return static_cast<int16_t>(v);
else if (type == USER_DATA_PROPERTY_TYPE_UINT16)
return static_cast<uint16_t>(v);
else if (type == USER_DATA_PROPERTY_TYPE_INT32)
return static_cast<int32_t>(v);
else if (type == USER_DATA_PROPERTY_TYPE_UINT32)
return static_cast<uint32_t>(v);
break;
}
}
return value;
}
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);
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);
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);
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);
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);
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);
return v;
}
default:
return value;
}
}
}

View File

@ -160,13 +160,13 @@ namespace doc {
size_t count_nonempty_properties_maps(const UserData::PropertiesMaps& propertiesMaps);
// If all the vector elements are of the same type returns such type.
// Otherwise it returns -1.
// If all the elements of vector have the same type, returns that type, also
// if this type is an integer, it tries to reduce it to the minimum int type
// capable of storing all the vector values.
// If all the elements of vector doesn't have the same type, returns 0.
uint16_t all_elements_of_same_type(const UserData::Vector& vector);
UserData::Variant reduce_int_type_size(const UserData::Variant& value);
UserData::Variant cast_to_smaller_int_type(const UserData::Variant& value, uint16_t type);
UserData::Variant reduce_int_type_size(const UserData::Variant& value);
} // namespace doc

View File

@ -1,4 +1,5 @@
// Aseprite Document Library
// Copyright (c) 2023 Igara Studio S.A.
// Copyright (c) 2001-2015 David Capello
//
// This file is released under the terms of the MIT license.
@ -21,253 +22,19 @@ namespace doc {
using namespace base::serialization;
using namespace base::serialization::little_endian;
void write_properties_maps(std::ostream& os, const UserData::PropertiesMaps& propertiesMaps);
UserData::PropertiesMaps read_properties_maps(std::istream& is);
void write_user_data(std::ostream& os, const UserData& userData)
{
write_string(os, userData.text());
write32(os, userData.color());
write_properties_maps(os, userData.propertiesMaps());
}
UserData read_user_data(std::istream& is)
{
UserData userData;
userData.setText(read_string(is));
// This check is here because we've been restoring sprites from
// old sessions where the color is restored incorrectly if we
// don't check if there is enough space to read from the file
// (e.g. reading a random color or just white, maybe -1 which is
// 0xffffffff in 32-bit).
if (!is.eof()) {
userData.setColor(read32(is));
userData.propertiesMaps() = read_properties_maps(is);
}
return userData;
}
size_t count_nonempty_properties_maps(const UserData::PropertiesMaps& propertiesMaps)
{
size_t i = 0;
for (const auto& it : propertiesMaps)
if (!it.second.empty())
++i;
return i;
}
bool is_negative(const UserData::Variant& value)
{
switch (value.type()) {
case USER_DATA_PROPERTY_TYPE_INT8: {
auto v = get_value<int8_t>(value);
return v < 0;
}
case USER_DATA_PROPERTY_TYPE_INT16: {
auto v = get_value<int16_t>(value);
return v < 0;
}
case USER_DATA_PROPERTY_TYPE_INT32: {
auto v = get_value<int32_t>(value);
return v < 0;
}
case USER_DATA_PROPERTY_TYPE_INT64: {
auto v = get_value<int64_t>(value);
return v < 0;
}
}
return false;
}
// If all the elements of vector have the same type, returns that type, also
// if this type is an integer, it tries to reduce it to the minimum int type
// capable of storing all the vector values.
// If all the elements of vector doesn't have the same type, returns 0.
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) {
if (type != value.type()) {
return 0;
}
else if (IS_REDUCIBLE_INT(value.type())) {
auto t = reduce_int_type_size(value).type();
hasNegativeNumbers |= is_negative(value);
if (t > commonReducedType) {
commonReducedType = t;
}
}
}
// TODO: The following check probably is not useful right now, I believe this could
// become useful if at some point we want to try to find a common integer type for vectors
// that contains elements of different integer types only.
// 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) &&
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;
}
return commonReducedType ? commonReducedType : type;
}
UserData::Variant cast_to_smaller_int_type(const UserData::Variant& value, uint16_t type)
{
ASSERT(type < value.type());
switch (value.type()) {
case USER_DATA_PROPERTY_TYPE_INT16: {
auto v = get_value<int16_t>(value);
if (type == USER_DATA_PROPERTY_TYPE_INT8)
return static_cast<int8_t>(v);
else if (type == USER_DATA_PROPERTY_TYPE_UINT8)
return static_cast<uint8_t>(v);
break;
}
case USER_DATA_PROPERTY_TYPE_UINT16: {
auto v = get_value<uint16_t>(value);
if (type == USER_DATA_PROPERTY_TYPE_INT8)
return static_cast<int8_t>(v);
else if (type == USER_DATA_PROPERTY_TYPE_UINT8)
return static_cast<uint8_t>(v);
break;
}
case USER_DATA_PROPERTY_TYPE_INT32: {
auto v = get_value<int32_t>(value);
if (type == USER_DATA_PROPERTY_TYPE_INT8)
return static_cast<int8_t>(v);
else if (type == USER_DATA_PROPERTY_TYPE_UINT8)
return static_cast<uint8_t>(v);
else if (type == USER_DATA_PROPERTY_TYPE_INT16)
return static_cast<int16_t>(v);
else if (type == USER_DATA_PROPERTY_TYPE_UINT16)
return static_cast<uint16_t>(v);
break;
}
case USER_DATA_PROPERTY_TYPE_UINT32: {
auto v = get_value<uint32_t>(value);
if (type == USER_DATA_PROPERTY_TYPE_INT8)
return static_cast<int8_t>(v);
else if (type == USER_DATA_PROPERTY_TYPE_UINT8)
return static_cast<uint8_t>(v);
else if (type == USER_DATA_PROPERTY_TYPE_INT16)
return static_cast<int16_t>(v);
else if (type == USER_DATA_PROPERTY_TYPE_UINT16)
return static_cast<uint16_t>(v);
break;
}
case USER_DATA_PROPERTY_TYPE_INT64: {
auto v = get_value<int64_t>(value);
if (type == USER_DATA_PROPERTY_TYPE_INT8)
return static_cast<int8_t>(v);
else if (type == USER_DATA_PROPERTY_TYPE_UINT8)
return static_cast<uint8_t>(v);
else if (type == USER_DATA_PROPERTY_TYPE_INT16)
return static_cast<int16_t>(v);
else if (type == USER_DATA_PROPERTY_TYPE_UINT16)
return static_cast<uint16_t>(v);
else if (type == USER_DATA_PROPERTY_TYPE_INT32)
return static_cast<int32_t>(v);
else if (type == USER_DATA_PROPERTY_TYPE_UINT32)
return static_cast<uint32_t>(v);
break;
}
case USER_DATA_PROPERTY_TYPE_UINT64: {
auto v = get_value<uint64_t>(value);
if (type == USER_DATA_PROPERTY_TYPE_INT8)
return static_cast<int8_t>(v);
else if (type == USER_DATA_PROPERTY_TYPE_UINT8)
return static_cast<uint8_t>(v);
else if (type == USER_DATA_PROPERTY_TYPE_INT16)
return static_cast<int16_t>(v);
else if (type == USER_DATA_PROPERTY_TYPE_UINT16)
return static_cast<uint16_t>(v);
else if (type == USER_DATA_PROPERTY_TYPE_INT32)
return static_cast<int32_t>(v);
else if (type == USER_DATA_PROPERTY_TYPE_UINT32)
return static_cast<uint32_t>(v);
break;
}
}
return value;
}
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);
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);
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);
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);
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);
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);
return v;
}
default:
return value;
}
}
void write_point(std::ostream& os, const gfx::Point& point)
static void write_point(std::ostream& os, const gfx::Point& point)
{
write32(os, point.x);
write32(os, point.y);
}
void write_size(std::ostream& os, const gfx::Size& size)
static void write_size(std::ostream& os, const gfx::Size& size)
{
write32(os, size.w);
write32(os, size.h);
}
void write_property_value(std::ostream& os, const UserData::Variant& variant)
static void write_property_value(std::ostream& os, const UserData::Variant& variant)
{
switch (variant.type())
{
@ -348,7 +115,7 @@ void write_property_value(std::ostream& os, const UserData::Variant& variant)
}
}
void write_properties_maps(std::ostream& os, const UserData::PropertiesMaps& propertiesMaps)
static void write_properties_maps(std::ostream& os, const UserData::PropertiesMaps& propertiesMaps)
{
write32(os, propertiesMaps.size());
for (auto propertiesMap : propertiesMaps) {
@ -359,7 +126,14 @@ void write_properties_maps(std::ostream& os, const UserData::PropertiesMaps& pro
}
}
UserData::Variant read_property_value(std::istream& is, uint16_t type)
void write_user_data(std::ostream& os, const UserData& userData)
{
write_string(os, userData.text());
write32(os, userData.color());
write_properties_maps(os, userData.propertiesMaps());
}
static UserData::Variant read_property_value(std::istream& is, uint16_t type)
{
switch (type) {
case USER_DATA_PROPERTY_TYPE_NULLPTR: {
@ -458,7 +232,7 @@ UserData::Variant read_property_value(std::istream& is, uint16_t type)
return doc::UserData::Variant{};
}
UserData::PropertiesMaps read_properties_maps(std::istream& is)
static UserData::PropertiesMaps read_properties_maps(std::istream& is)
{
doc::UserData::PropertiesMaps propertiesMaps;
size_t nmaps = read32(is);
@ -470,4 +244,20 @@ UserData::PropertiesMaps read_properties_maps(std::istream& is)
return propertiesMaps;
}
UserData read_user_data(std::istream& is)
{
UserData userData;
userData.setText(read_string(is));
// This check is here because we've been restoring sprites from
// old sessions where the color is restored incorrectly if we
// don't check if there is enough space to read from the file
// (e.g. reading a random color or just white, maybe -1 which is
// 0xffffffff in 32-bit).
if (!is.eof()) {
userData.setColor(read32(is));
userData.propertiesMaps() = read_properties_maps(is);
}
return userData;
}
}