mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
216 lines
6.0 KiB
Swift
216 lines
6.0 KiB
Swift
//===--- 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}<Bound : Comparable>
|
|
: 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 == <Bound : Comparable> (
|
|
lhs: ${Self}<Bound>, rhs: ${Self}<Bound>
|
|
) -> 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 ..< <Bound : Comparable>(
|
|
start: Bound, end: Bound
|
|
) -> HalfOpenInterval<Bound> {
|
|
return HalfOpenInterval(_start: start, end: end)
|
|
}
|
|
|
|
/// Returns a closed interval from `start` through `end`.
|
|
@warn_unused_result
|
|
public func ... <Bound : Comparable>(
|
|
start: Bound, end: Bound
|
|
) -> ClosedInterval<Bound> {
|
|
return ClosedInterval(_start: start, end: end)
|
|
}
|
|
|
|
/// Returns `true` iff `pattern` contains `value`.
|
|
@warn_unused_result
|
|
public func ~= <I: Interval>(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")
|
|
}
|
|
}
|
|
|