| 
									
										
										
										
											2023-02-23 02:22:35 +08:00
										 |  |  | // 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; | 
					
						
							| 
									
										
										
										
											2023-02-23 02:58:47 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   for (const auto& value : vector) { | 
					
						
							| 
									
										
										
										
											2023-02-23 02:22:35 +08:00
										 |  |  |     if (type != value.type()) { | 
					
						
							|  |  |  |       return 0; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-02-23 02:58:47 +08:00
										 |  |  |     else if (is_reducible_int(value)) { | 
					
						
							| 
									
										
										
										
											2023-02-23 02:22:35 +08:00
										 |  |  |       auto t = reduce_int_type_size(value).type(); | 
					
						
							|  |  |  |       hasNegativeNumbers |= is_negative(value); | 
					
						
							| 
									
										
										
										
											2023-02-23 02:58:47 +08:00
										 |  |  |       if (commonReducedType < t) { | 
					
						
							| 
									
										
										
										
											2023-02-23 02:22:35 +08:00
										 |  |  |         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 && | 
					
						
							| 
									
										
										
										
											2023-02-23 02:58:47 +08:00
										 |  |  |       (commonReducedType & 1) && // TODO fix this assumption about USER_DATA_PROPERTY_TYPE_* values
 | 
					
						
							| 
									
										
										
										
											2023-02-23 02:22:35 +08:00
										 |  |  |       hasNegativeNumbers) { | 
					
						
							|  |  |  |     commonReducedType++; | 
					
						
							| 
									
										
										
										
											2023-02-23 02:58:47 +08:00
										 |  |  |     // 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; | 
					
						
							| 
									
										
										
										
											2023-02-23 02:22:35 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-23 02:58:47 +08:00
										 |  |  |   return (commonReducedType ? commonReducedType : type); | 
					
						
							| 
									
										
										
										
											2023-02-23 02:22:35 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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); | 
					
						
							| 
									
										
										
										
											2023-02-23 02:58:47 +08:00
										 |  |  |       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); | 
					
						
							| 
									
										
										
										
											2023-02-23 02:22:35 +08:00
										 |  |  |       return v; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     case USER_DATA_PROPERTY_TYPE_UINT16: { | 
					
						
							|  |  |  |       auto v = get_value<uint16_t>(value); | 
					
						
							| 
									
										
										
										
											2023-02-23 02:58:47 +08:00
										 |  |  |       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); | 
					
						
							| 
									
										
										
										
											2023-02-23 02:22:35 +08:00
										 |  |  |       return v; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     case USER_DATA_PROPERTY_TYPE_INT32: { | 
					
						
							|  |  |  |       auto v = get_value<int32_t>(value); | 
					
						
							| 
									
										
										
										
											2023-02-23 02:58:47 +08:00
										 |  |  |       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); | 
					
						
							| 
									
										
										
										
											2023-02-23 02:22:35 +08:00
										 |  |  |       return v; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     case USER_DATA_PROPERTY_TYPE_UINT32: { | 
					
						
							|  |  |  |       auto v = get_value<uint32_t>(value); | 
					
						
							| 
									
										
										
										
											2023-02-23 02:58:47 +08:00
										 |  |  |       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); | 
					
						
							| 
									
										
										
										
											2023-02-23 02:22:35 +08:00
										 |  |  |       return v; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     case USER_DATA_PROPERTY_TYPE_INT64: { | 
					
						
							|  |  |  |       auto v = get_value<int64_t>(value); | 
					
						
							| 
									
										
										
										
											2023-02-23 02:58:47 +08:00
										 |  |  |       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); | 
					
						
							| 
									
										
										
										
											2023-02-23 02:22:35 +08:00
										 |  |  |       return v; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     case USER_DATA_PROPERTY_TYPE_UINT64: { | 
					
						
							|  |  |  |       auto v = get_value<uint64_t>(value); | 
					
						
							| 
									
										
										
										
											2023-02-23 02:58:47 +08:00
										 |  |  |       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); | 
					
						
							| 
									
										
										
										
											2023-02-23 02:22:35 +08:00
										 |  |  |       return v; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       return value; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } |