diff options
author | John Firebaugh <john.firebaugh@gmail.com> | 2017-09-26 14:14:44 -0700 |
---|---|---|
committer | John Firebaugh <john.firebaugh@gmail.com> | 2017-10-23 09:56:43 -0700 |
commit | 4b2e1cddb4645fb6d2c5f9634dbeb7c21516cede (patch) | |
tree | f11bd97ea5abf17bc6956f254796f1e8cf4a96f9 /platform/darwin | |
parent | bb58ddaea8c2d9da9551601318944d9d143ee247 (diff) | |
download | qtlocation-mapboxgl-4b2e1cddb4645fb6d2c5f9634dbeb7c21516cede.tar.gz |
Replace compile-time polymorphism with runtime polymorphism in the conversion system
Diffstat (limited to 'platform/darwin')
-rw-r--r-- | platform/darwin/src/MGLConversion.h | 223 | ||||
-rw-r--r-- | platform/darwin/src/MGLStyleValue_Private.h | 4 |
2 files changed, 120 insertions, 107 deletions
diff --git a/platform/darwin/src/MGLConversion.h b/platform/darwin/src/MGLConversion.h index d6363b28eb..0d18d4e716 100644 --- a/platform/darwin/src/MGLConversion.h +++ b/platform/darwin/src/MGLConversion.h @@ -1,9 +1,4 @@ -#import <Foundation/Foundation.h> - -#include <mbgl/util/logging.hpp> #include <mbgl/style/conversion.hpp> -#include <mbgl/util/feature.hpp> -#include <mbgl/util/optional.hpp> NS_ASSUME_NONNULL_BEGIN @@ -11,128 +6,147 @@ namespace mbgl { namespace style { namespace conversion { -/** - A minimal wrapper class conforming to the requirements for `objectMember(v, name)` (see mbgl/style/conversion.hpp) - This is necessary because using `NSObject*` as the value type in `optional<NSObject*>` causes problems for the ARC, - due to things like `optional(const value_type& __v)` - */ -class OptionalNSObjectValue { +// A wrapper class for `id`, so as not to confuse ARC. +class Holder { public: - OptionalNSObjectValue(NSObject * _Nullable _value) : value(_value) {} - - explicit operator bool() const { - return value; + Holder(const id v) : value(v) {} + const id value; +}; + +template <> +class ConversionTraits<Holder> { +public: + static bool isUndefined(const Holder& holder) { + const id value = holder.value; + return !value || value == [NSNull null]; } - - NSObject * _Nullable operator*() { - NSCAssert(this, @"Expected non-null value."); - return value; + + static bool isArray(const Holder& holder) { + const id value = holder.value; + return [value isKindOfClass:[NSArray class]]; } -private: - NSObject * _Nullable value; -}; -inline bool isUndefined(const id value) { - return !value || value == [NSNull null]; -} + static bool isObject(const Holder& holder) { + const id value = holder.value; + return [value isKindOfClass:[NSDictionary class]]; + } -inline bool isArray(const id value) { - return [value isKindOfClass:[NSArray class]]; -} + static std::size_t arrayLength(const Holder& holder) { + const id value = holder.value; + NSCAssert([value isKindOfClass:[NSArray class]], @"Value must be an NSArray for getLength()."); + NSArray *array = value; + auto length = [array count]; + NSCAssert(length <= std::numeric_limits<size_t>::max(), @"Array length out of bounds."); + return length; + } -inline bool isObject(const id value) { - return [value isKindOfClass:[NSDictionary class]]; -} + static Holder arrayMember(const Holder& holder, std::size_t i) { + const id value = holder.value; + NSCAssert([value isKindOfClass:[NSArray class]], @"Value must be an NSArray for get(int)."); + NSCAssert(i < NSUIntegerMax, @"Index must be less than NSUIntegerMax"); + return {[value objectAtIndex: i]}; + } -inline std::size_t arrayLength(const id value) { - NSCAssert([value isKindOfClass:[NSArray class]], @"Value must be an NSArray for getLength()."); - NSArray *array = value; - auto length = [array count]; - NSCAssert(length <= std::numeric_limits<size_t>::max(), @"Array length out of bounds."); - return length; -} + static optional<Holder> objectMember(const Holder& holder, const char *key) { + const id value = holder.value; + NSCAssert([value isKindOfClass:[NSDictionary class]], @"Value must be an NSDictionary for get(string)."); + NSObject *member = [value objectForKey: @(key)]; + if (member && member != [NSNull null]) { + return {member}; + } else { + return {}; + } + } -inline NSObject *arrayMember(const id value, std::size_t i) { - NSCAssert([value isKindOfClass:[NSArray class]], @"Value must be an NSArray for get(int)."); - NSCAssert(i < NSUIntegerMax, @"Index must be less than NSUIntegerMax"); - return [value objectAtIndex: i]; -} +// Compiler is wrong about `Fn` parameter missing a nullability specifier. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnullability-completeness" + template <class Fn> + static optional<Error> eachMember(const Holder&, Fn&&) { +#pragma clang diagnostic pop + // Not implemented (unneeded for MGLStyleFunction conversion). + NSCAssert(NO, @"eachMember not implemented"); + return {}; + } -inline OptionalNSObjectValue objectMember(const id value, const char *key) { - NSCAssert([value isKindOfClass:[NSDictionary class]], @"Value must be an NSDictionary for get(string)."); - NSObject *member = [value objectForKey: @(key)]; - if (member && member != [NSNull null]) { - return { member }; - } else { - return { nullptr }; + static optional<bool> toBool(const Holder& holder) { + const id value = holder.value; + if (_isBool(value)) { + return ((NSNumber *)value).boolValue; + } else { + return {}; + } } -} -// Not implemented (unneeded for MGLStyleFunction conversion): -// optional<Error> eachMember(const NSObject*, Fn&&) + static optional<float> toNumber(const Holder& holder) { + const id value = holder.value; + if (_isNumber(value)) { + return ((NSNumber *)value).floatValue; + } else { + return {}; + } + } -inline bool _isBool(const id value) { - if (![value isKindOfClass:[NSNumber class]]) return false; - // char: 32-bit boolean - // BOOL: 64-bit boolean - NSNumber *number = value; - return ((strcmp([number objCType], @encode(char)) == 0) || - (strcmp([number objCType], @encode(BOOL)) == 0)); -} - -inline bool _isNumber(const id value) { - return [value isKindOfClass:[NSNumber class]] && !_isBool(value); -} - -inline bool _isString(const id value) { - return [value isKindOfClass:[NSString class]]; -} + static optional<double> toDouble(const Holder& holder) { + const id value = holder.value; + if (_isNumber(value)) { + return ((NSNumber *)value).doubleValue; + } else { + return {}; + } + } -inline optional<bool> toBool(const id value) { - if (_isBool(value)) { - return ((NSNumber *)value).boolValue; - } else { - return {}; + static optional<std::string> toString(const Holder& holder) { + const id value = holder.value; + if (_isString(value)) { + return std::string(static_cast<const char *>([value UTF8String])); + } else { + return {}; + } } -} -inline optional<float> toNumber(const id value) { - if (_isNumber(value)) { - return ((NSNumber *)value).floatValue; - } else { - return {}; + static optional<mbgl::Value> toValue(const Holder& holder) { + const id value = holder.value; + if (isUndefined(value)) { + return {}; + } else if (_isBool(value)) { + return { *toBool(holder) }; + } else if ( _isString(value)) { + return { *toString(holder) }; + } else if (_isNumber(value)) { + // Need to cast to a double here as the float is otherwise considered a bool... + return { static_cast<double>(*toNumber(holder)) }; + } else { + return {}; + } } -} -inline optional<double> toDouble(const id value) { - if (_isNumber(value)) { - return ((NSNumber *)value).doubleValue; - } else { + static optional<GeoJSON> toGeoJSON(const Holder& holder, Error& error) { + error = { "toGeoJSON not implemented" }; return {}; } -} -inline optional<std::string> toString(const id value) { - if (_isString(value)) { - return std::string(static_cast<const char *>([value UTF8String])); - } else { - return {}; +private: + static bool _isBool(const id value) { + if (![value isKindOfClass:[NSNumber class]]) return false; + // char: 32-bit boolean + // BOOL: 64-bit boolean + NSNumber *number = value; + return ((strcmp([number objCType], @encode(char)) == 0) || + (strcmp([number objCType], @encode(BOOL)) == 0)); } -} -inline optional<mbgl::Value> toValue(const id value) { - if (isUndefined(value)) { - return {}; - } else if (_isBool(value)) { - return { *toBool(value) }; - } else if ( _isString(value)) { - return { *toString(value) }; - } else if (_isNumber(value)) { - // Need to cast to a double here as the float is otherwise considered a bool... - return { static_cast<double>(*toNumber(value)) }; - } else { - return {}; + static bool _isNumber(const id value) { + return [value isKindOfClass:[NSNumber class]] && !_isBool(value); } + + static bool _isString(const id value) { + return [value isKindOfClass:[NSString class]]; + } +}; + +inline Convertible makeConvertible(const id value) { + return Convertible(Holder(value)); } } // namespace conversion @@ -140,4 +154,3 @@ inline optional<mbgl::Value> toValue(const id value) { } // namespace mbgl NS_ASSUME_NONNULL_END - diff --git a/platform/darwin/src/MGLStyleValue_Private.h b/platform/darwin/src/MGLStyleValue_Private.h index 2155c657bd..5914e0a2aa 100644 --- a/platform/darwin/src/MGLStyleValue_Private.h +++ b/platform/darwin/src/MGLStyleValue_Private.h @@ -124,9 +124,9 @@ public: if ([value isKindOfClass:[MGLConstantStyleValue class]]) { return toMBGLConstantValue((MGLConstantStyleValue<ObjCType> *)value); } else if ([value isKindOfClass:[MGLStyleFunction class]]) { - auto rawValue = toRawStyleSpecValue((MGLStyleFunction<ObjCType> *) value); mbgl::style::conversion::Error error; - auto result = mbgl::style::conversion::convert<mbgl::style::DataDrivenPropertyValue<MBGLType>>(rawValue, error); + auto result = mbgl::style::conversion::convert<mbgl::style::DataDrivenPropertyValue<MBGLType>>( + mbgl::style::conversion::makeConvertible(toRawStyleSpecValue((MGLStyleFunction<ObjCType> *) value)), error); NSCAssert(result, @(error.message.c_str())); return *result; } else { |