//===--- Interval.swift.gyb -----------------------------------*- swift -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// /// An interval over a `Comparable` type. public protocol Interval { /// The type of the `Interval`'s endpoints. associatedtype Bound : Comparable /// Returns `true` iff the interval contains `value`. @warn_unused_result func contains(value: Bound) -> Bool /// Returns `rhs` clamped to `self`. The bounds of the result, even /// if it is empty, are always within the bounds of `self`. @warn_unused_result func clamp(intervalToClamp: Self) -> Self /// `true` iff `self` is empty. var isEmpty: Bool { get } /// The `Interval`'s lower bound. /// /// Invariant: `start` <= `end`. var start: Bound { get } /// The `Interval`'s upper bound. /// /// Invariant: `start` <= `end`. var end: Bound { get } } % for Kind, rangeOperator, upperBoundCompare in [ % ('HalfOpen', '..<', '<'), % ('Closed', '...', '<=') % ]: % Self = Kind + 'Interval' %{ selfDocComment = """ /// A half-open `Interval`, which contains its `start` but not its /// `end`. Can represent an empty interval.""" if Kind == 'HalfOpen' else """ /// A closed `Interval`, which contains both its `start` and its /// `end`. Cannot represent an empty interval.""" selfDocComment += """ /// /// - parameter Bound: The type of the endpoints.""" }% ${selfDocComment} public struct ${Self} : Interval, Equatable, CustomStringConvertible, CustomDebugStringConvertible, CustomReflectable, CustomPlaygroundQuickLookable { /// Construct a copy of `x`. public init(_ x: ${Self}) { // This initializer exists only so that we can have a descriptive // debugDescription that actually constructs the right type. self = x } /// Construct an interval with the given bounds. /// /// - Precondition: `start <= end`. internal init(_start: Bound, end: Bound) { _precondition(end >= _start, "Invalid ${Self} bounds (end < start)") self._start = _start self._end = end } /// The `Interval`'s lower bound. /// /// Invariant: `start` <= `end`. public var start: Bound { return _start } /// The `Interval`'s upper bound. /// /// Invariant: `start` <= `end`. public var end: Bound { return _end } /// A textual representation of `self`. public var description: String { return "\(start)${rangeOperator}\(end)" } /// A textual representation of `self`, suitable for debugging. public var debugDescription: String { return "${Self}(\(String(reflecting: start))${rangeOperator}\(String(reflecting: end)))" } /// Returns `true` iff the `Interval` contains `x`. @warn_unused_result public func contains(x: Bound) -> Bool { return x >= start && x ${upperBoundCompare} end } /// Returns `intervalToClamp` clamped to `self`. /// /// The bounds of the result, even if it is empty, are always limited to the bounds of /// `self`. @warn_unused_result public func clamp(intervalToClamp: ${Self}) -> ${Self} { return ${Self}( _start: self.start > intervalToClamp.start ? self.start : self.end < intervalToClamp.start ? self.end : intervalToClamp.start, end: self.end < intervalToClamp.end ? self.end : self.start > intervalToClamp.end ? self.start : intervalToClamp.end ) } /// Returns a mirror that reflects `self`. public var customMirror: Mirror { return Mirror(self, children: ["start": _start, "end": _end]) } public var customPlaygroundQuickLook: PlaygroundQuickLook { return .text(description) } internal var _start: Bound internal var _end: Bound } /// Two `${Self}`s are equal if their `start` and `end` are equal. @warn_unused_result public func == ( lhs: ${Self}, rhs: ${Self} ) -> Bool { return lhs.start == rhs.start && lhs.end == rhs.end } %end extension HalfOpenInterval { /// `true` iff the `Interval` is empty. public var isEmpty: Bool { return end <= start } } extension ClosedInterval { /// `true` iff the `Interval` is empty. In the case of /// `ClosedInterval`, always returns `false`. public var isEmpty: Bool { return false } } extension Interval { /// Returns `true` iff `lhs` and `rhs` have a non-empty intersection. @warn_unused_result public func overlaps< I: Interval where I.Bound == Bound >(other: I) -> Bool { return (!other.isEmpty && contains(other.start)) || (!isEmpty && other.contains(start)) } } /// Returns a half-open interval from `start` to `end`. @warn_unused_result public func ..< ( start: Bound, end: Bound ) -> HalfOpenInterval { return HalfOpenInterval(_start: start, end: end) } /// Returns a closed interval from `start` through `end`. @warn_unused_result public func ... ( start: Bound, end: Bound ) -> ClosedInterval { return ClosedInterval(_start: start, end: end) } /// Returns `true` iff `pattern` contains `value`. @warn_unused_result public func ~= (pattern: I, value: I.Bound) -> Bool { return pattern.contains(value) } @available(*, unavailable, renamed="Interval") public typealias IntervalType = Interval extension HalfOpenInterval { @available(*, unavailable, message="Please use the '..<' operator instead.") public init(_ start: Bound, _ end: Bound) { fatalError("unavailable function can't be called") } } extension ClosedInterval { @available(*, unavailable, message="Please use the '...' operator instead.") public init(_ start: Bound, _ end: Bound) { fatalError("unavailable function can't be called") } }