blob: a6804ffa11557db759304bd1f9d72c7ec4a732db [file] [log] [blame]
//===--- GenericDispatch.swift - Demonstrate "partial specialization" -----===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// Do stuff in Swift that we didn't think was possible. This file
// will ensure that the capability doesn't regress and give us a
// prototype to which we can refer when building the standard library.
//
//===----------------------------------------------------------------------===//
// RUN: %target-run-simple-swift | %FileCheck %s
// REQUIRES: executable_test
// CHECK: testing...
print("testing...")
//===----------------------------------------------------------------------===//
//===--- Think of this code as being "in the library" ---------------------===//
//===----------------------------------------------------------------------===//
//===--- F "base" protocol (like ForwardIndex) ----------------------------===//
protocol F {
func successor() -> Self
// This requirement allows generic distance() to find default
// implementations. Only the author of F and the author of a
// refinement of F having a non-default distance implementation need
// to know about it. These refinements are expected to be rare
// (which is why defaulted requirements are a win)
static func ~> (_: Self, _: (_Distance, (Self))) -> Int
}
// Operation tag for distance
//
// Operation tags allow us to use a single operator (~>) for
// dispatching every generic function with a default implementation.
// Only authors of specialized distance implementations need to touch
// this tag.
struct _Distance {}
// This function cleans up the syntax of invocations
func _distance<I>(_ other: I) -> (_Distance, (I)) {
return (_Distance(), (other))
}
// Default Implementation of distance for F's
func ~> <I: F>(self_:I, _: (_Distance, (I))) -> Int {
self_.successor() // Use an F-specific operation
print("F")
return 0
}
//===--- Dispatching distance() function ----------------------------------===//
// This generic function is for user consumption; it dispatches to the
// appropriate implementation for T.
func distance<T: F>(_ x: T, _ y: T) -> Int {
return x~>_distance(y)
}
//===--- R refined protocol (like RandomAccessIndex) ----------------------===//
protocol R : F {
// Non-defaulted requirements of R go here, e.g. something to
// measure the distance in O(1)
static func sub(_ x: Self, y: Self)
}
// R has its own default implementation of distance, which is O(1).
// Only the author of R needs to see this implementation.
func ~> <I: R>(x: I, args: (_Distance, (I))) -> Int {
let other = args.1
I.sub(other, y: x)
print("R")
return 1
}
//===--- D refined protocol (like R, but with a custom distance) ----------===//
// Users who want to provide a custom distance function will use this protocol
protocol D : R {
func distance(_ y: Self) -> Int
}
// Dispatch to D's distance() requirement
// Only the author of D needs to see this implementation.
func ~> <I: D>(x: I, args: (_Distance, (I))) -> Int {
let other = args.1
return x.distance(other)
}
//===----------------------------------------------------------------------===//
//===--- Think of this as being "user code" -------------------------------===//
//===----------------------------------------------------------------------===//
// This model of F automatically gets F's default implementation of distance
struct SlowIndex : F {
func successor() -> SlowIndex { return self }
}
// This model of R automatically gets R's default implementation of distance
struct FastIndex : R {
func successor() -> FastIndex { return self }
static func sub(_ x: FastIndex, y: FastIndex) {}
}
struct X : D {
// Customized distance implementation
func distance(_ y: X) -> Int {
print("X")
return 3
}
// Inherited requirements
func successor() -> X { return self }
static func sub(_ x: X, y: X) {}
}
// Here's a generic function that uses our dispatching distance
func sort<T: F>(_ x: T) {
// In here, we don't know whether T is an R or just a plain F, or
// whether it has its own specialized implementation of
distance(x, x)
}
// CHECK-NEXT: F
sort(SlowIndex())
// CHECK-NEXT: R
sort(FastIndex())
// CHECK-NEXT: X
sort(X())
// CHECK-NEXT: done
print("done.")