/* * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. */ #import #ifdef __cplusplus #import #import namespace executorch::extension::utils { using namespace aten; using namespace runtime; /** * Deduces the scalar type for a given NSNumber based on its type encoding. * * @param number The NSNumber instance whose scalar type is to be deduced. * @return The corresponding ScalarType. */ ScalarType deduceType(NSNumber *number); /** * Converts the value held in the NSNumber to the specified C++ type T. * * @tparam T The target C++ numeric type. * @param number The NSNumber instance to extract the value from. * @return The value converted to type T. */ template T extractValue(NSNumber *number) { ET_CHECK_MSG(!(isFloatingType(deduceType(number)) && isIntegralType(CppTypeToScalarType::value, true)), "Cannot convert floating point to integral type"); T value; if constexpr (std::is_same_v) { value = number.unsignedCharValue; } else if constexpr (std::is_same_v) { value = number.charValue; } else if constexpr (std::is_same_v) { value = number.shortValue; } else if constexpr (std::is_same_v) { value = number.intValue; } else if constexpr (std::is_same_v) { value = number.longLongValue; } else if constexpr (std::is_same_v) { value = number.floatValue; } else if constexpr (std::is_same_v) { value = number.doubleValue; } else if constexpr (std::is_same_v) { value = number.boolValue; } else if constexpr (std::is_same_v) { value = number.unsignedShortValue; } else if constexpr (std::is_same_v) { value = number.unsignedIntValue; } else if constexpr (std::is_same_v) { value = number.unsignedLongLongValue; } else if constexpr (std::is_same_v) { value = number.integerValue; } else if constexpr (std::is_same_v) { value = number.unsignedIntegerValue; } else if constexpr (std::is_same_v || std::is_same_v) { value = T(number.floatValue); } else { static_assert(sizeof(T) == 0, "Unsupported type"); } ET_DCHECK_MSG(std::numeric_limits::lowest() <= value && value <= std::numeric_limits::max(), "Value out of range"); return value; } /** * Converts an NSArray of NSNumber objects to a std::vector of type T. * * @tparam T The target C++ numeric type. * @param array The NSArray containing NSNumber objects. * @return A std::vector with the values extracted as type T. */ template std::vector toVector(NSArray *array) { std::vector vector; vector.reserve(array.count); for (NSNumber *number in array) { vector.push_back(extractValue(number)); } return vector; } // Trait for types that can be wrapped into an NSNumber. template constexpr bool isNSNumberWrapable = std::is_arithmetic_v || std::is_same_v || std::is_same_v || std::is_same_v; /** * Converts a generic container of numeric values to an NSArray of NSNumber objects. * * @tparam Container The container type holding numeric values. * @param container The container whose items are to be converted. * @return An NSArray populated with NSNumber objects representing the container's items. */ template NSArray *toNSArray(const Container &container) { static_assert(isNSNumberWrapable, "Invalid container value type"); const NSUInteger count = std::distance(std::begin(container), std::end(container)); NSMutableArray *array = [NSMutableArray arrayWithCapacity:count]; for (const auto &item : container) { [array addObject:@(item)]; } return array; } } // namespace executorch::extension::utils #endif // __cplusplus