RenderCore/Geometry/CKSizeRange.mm (76 lines of code) (raw):

/* * Copyright (c) 2014-present, Facebook, Inc. * 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. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * */ #import "CKSizeRange.h" #import <functional> #import <RenderCore/RCDimension.h> #import <RenderCore/RCEqualityHelpers.h> #import <RenderCore/CKMacros.h> #define RCCAssertPositiveReal(description, num) \ RCCAssert(num >= 0 && num < CGFLOAT_MAX, @"%@ (%f) must be a real positive integer.", description, num) #define RCCAssertInfOrPositiveReal(description, num) \ RCCAssert(isinf(num) || (num >= 0 && num < CGFLOAT_MAX), @"%@ (%f) must be infinite or a real positive integer.", description, num) #define RCCAssertWidth(min, max) \ RCCAssert(min.width <= max.width, @"Range min width (%f) must not be larger than max width (%f).", min.width, max.width) #define RCCAssertHeight(min, max) \ RCCAssert(min.height <= max.height, @"Range min height (%f) must not be larger than max height (%f).", min.height, max.height) CKSizeRange::CKSizeRange(const CGSize &_min, const CGSize &_max) : min(_min), max(_max) { RCCAssertPositiveReal(@"Range min width", min.width); RCCAssertPositiveReal(@"Range min height", min.height); RCCAssertInfOrPositiveReal(@"Range max width", max.width); RCCAssertInfOrPositiveReal(@"Range max height", max.height); RCCAssertWidth(min, max); RCCAssertHeight(min, max); } CGSize CKSizeRange::clamp(const CGSize &size) const { return { MAX(min.width, MIN(max.width, size.width)), MAX(min.height, MIN(max.height, size.height)) }; } struct _Range { CGFloat min; CGFloat max; /** Intersects another dimension range. If the other range does not overlap, this size range "wins" by returning a single point within its own range that is closest to the non-overlapping range. */ _Range intersect(const _Range &other) const { CGFloat newMin = MAX(min, other.min); CGFloat newMax = MIN(max, other.max); if (!(newMin > newMax)) { return {newMin, newMax}; } else { // No intersection. If we're before the other range, return our max; otherwise our min. if (min < other.min) { return {max, max}; } else { return {min, min}; } } } }; CKSizeRange CKSizeRange::intersect(const CKSizeRange &other) const { auto w = _Range({min.width, max.width}).intersect({other.min.width, other.max.width}); auto h = _Range({min.height, max.height}).intersect({other.min.height, other.max.height}); return {{w.min, h.min}, {w.max, h.max}}; } bool CKSizeRange::operator==(const CKSizeRange &other) const { return CGSizeEqualToSize(min, other.min) && CGSizeEqualToSize(max, other.max); } NSString *CKSizeRange::description() const { return [NSString stringWithFormat:@"<CKSizeRange: min=%@, max=%@>", NSStringFromCGSize(min), NSStringFromCGSize(max)]; } size_t CKSizeRange::hash() const { std::hash<CGFloat> hasher; NSUInteger subhashes[] = { hasher(min.width), hasher(min.height), hasher(max.width), hasher(max.height) }; return RCIntegerArrayHash(subhashes, CK_ARRAY_COUNT(subhashes)); } size_t std::hash<CKSizeRange>::operator()(const CKSizeRange &s) noexcept { return s.hash(); };