Skip to content

Instantly share code, notes, and snippets.

@kazk
Last active August 29, 2015 14:15
Show Gist options
  • Save kazk/44a9afcdac392b44b7fc to your computer and use it in GitHub Desktop.
Save kazk/44a9afcdac392b44b7fc to your computer and use it in GitHub Desktop.
Defines zipping functions for types conforming to `SequenceType`.
// Defines zipping functions for types conforming to `SequenceType`.
// - zip (overloaded up to zip7)
// - unzip (overloaded up to unzip7)
// - zipLongest (overloaded up to zipLongest4)
//
// References:
// - [Convolution (computer science)]: http://en.wikipedia.org/wiki/Convolution_(computer_science)
// MARK: - zip (shortest)
// MARK: zip2. ([A], [B]) -> [(A, B)]
/// Generalized zip2, zipping with the given function instead of a tupling function.
///
/// :param: fn A function which combines 2 elements.
/// :returns: A sequence of values fn(a, b)
public func zip<A : SequenceType, B : SequenceType, R>
(sequenceA: A, sequenceB: B, with fn: (A.Generator.Element, B.Generator.Element)->R)
-> SequenceOf<R>
{
return SequenceOf {_ -> GeneratorOf<R> in
var aG = sequenceA.generate(), bG = sequenceB.generate()
return GeneratorOf {
switch (aG.next(), bG.next()) {
case let (.Some(a), .Some(b)): return fn(a, b)
default: return nil
}
}
}
}
/// zip2 with tupling function.
///
/// :returns: A sequence of pairs.
public func zip<A : SequenceType, B : SequenceType>(sequenceA: A, sequenceB: B)
-> SequenceOf<(A.Generator.Element, B.Generator.Element)>
{
return zip(sequenceA, sequenceB) { ($0, $1) }
}
// MARK: zip3. ([A], [B], [C]) -> [(A, B, C)]
/// Generalized zip3, zipping with the given function instead of a tupling function.
///
/// :param: fn A function which combines 3 elements.
/// :returns: A sequence of values fn(a, b, c).
public func zip<A : SequenceType, B : SequenceType, C : SequenceType, R>
(sequenceA: A, sequenceB: B, sequenceC: C,
with fn: (A.Generator.Element, B.Generator.Element, C.Generator.Element)->R)
-> SequenceOf<R>
{
return SequenceOf {_ -> GeneratorOf<R> in
var aG = sequenceA.generate(), bG = sequenceB.generate()
var cG = sequenceC.generate()
return GeneratorOf {
switch (aG.next(), bG.next(), cG.next()) {
case let (.Some(a), .Some(b), .Some(c)): return fn(a, b, c)
default: return nil
}
}
}
}
/// zip3 with tupling function.
///
/// :returns: A sequence of triples.
public func zip<A : SequenceType, B : SequenceType, C : SequenceType>
(sequenceA: A, sequenceB: B, sequenceC: C)
-> SequenceOf<(A.Generator.Element, B.Generator.Element, C.Generator.Element)>
{
return zip(sequenceA, sequenceB, sequenceC) { ($0, $1, $2) }
}
// MARK: zip4. ([A], [B], [C], [D]) -> [(A, B, C, D)]
/// Generalized zip4, zipping with the given function instead of a tupling function.
///
/// :param: fn A function which combines 4 elements.
/// :returns: A sequence of values fn(a, b, c, d).
public func zip<A : SequenceType, B : SequenceType, C : SequenceType, D : SequenceType, R>
(sequenceA: A, sequenceB: B, sequenceC: C, sequenceD: D,
with fn: (A.Generator.Element, B.Generator.Element, C.Generator.Element, D.Generator.Element)->R)
-> SequenceOf<R>
{
return SequenceOf {_ -> GeneratorOf<R> in
var aG = sequenceA.generate(), bG = sequenceB.generate()
var cG = sequenceC.generate(), dG = sequenceD.generate()
return GeneratorOf {
switch (aG.next(), bG.next(), cG.next(), dG.next()) {
case let (.Some(a), .Some(b), .Some(c), .Some(d)): return fn(a, b, c, d)
default: return nil
}
}
}
}
/// zip4 with tupling function.
///
/// :returns: Sequence of quadruples.
public func zip<A : SequenceType, B : SequenceType, C : SequenceType, D : SequenceType>
(sequenceA: A, sequenceB: B, sequenceC: C, sequenceD: D)
-> SequenceOf<(A.Generator.Element, B.Generator.Element, C.Generator.Element, D.Generator.Element)>
{
return zip(sequenceA, sequenceB, sequenceC, sequenceD) { ($0, $1, $2, $3) }
}
// MARK: zip5. ([A], [B], [C], [D], [E]) -> [(A, B, C, D, E)]
/// Generalized zip5, zipping with the given function instead of a tupling function.
///
/// :param: fn A function which combines 5 elements.
/// :returns: A sequence of values fn(a, b, c, d, e).
public func zip<A : SequenceType, B : SequenceType, C : SequenceType, D : SequenceType, E : SequenceType, R>
(sequenceA: A, sequenceB: B, sequenceC: C, sequenceD: D, sequenceE: E,
with fn: (A.Generator.Element, B.Generator.Element, C.Generator.Element, D.Generator.Element, E.Generator.Element)->R)
-> SequenceOf<R>
{
return SequenceOf {_ -> GeneratorOf<R> in
var aG = sequenceA.generate(), bG = sequenceB.generate()
var cG = sequenceC.generate(), dG = sequenceD.generate()
var eG = sequenceE.generate()
return GeneratorOf {
switch (aG.next(), bG.next(), cG.next(), dG.next(), eG.next()) {
case let (.Some(a), .Some(b), .Some(c), .Some(d), .Some(e)): return fn(a, b, c, d, e)
default: return nil
}
}
}
}
/// zip5 with tupling function.
///
/// :returns: Sequence of 5-Tuples.
public func zip<A : SequenceType, B : SequenceType, C : SequenceType, D : SequenceType, E : SequenceType>
(sequenceA: A, sequenceB: B, sequenceC: C, sequenceD: D, sequenceE: E)
-> SequenceOf<(A.Generator.Element, B.Generator.Element, C.Generator.Element, D.Generator.Element, E.Generator.Element)>
{
return zip(sequenceA, sequenceB, sequenceC, sequenceD, sequenceE) { ($0, $1, $2, $3, $4) }
}
// MARK: zip6. ([A], [B], [C], [D], [E], [F]) -> [(A, B, C, D, E, F)]
/// Generalized zip6, zipping with the given function instead of a tupling function.
///
/// :param: fn A function which combines 6 elements.
/// :returns: A sequence of values fn(a, b, c, d, e, f).
public func zip<A : SequenceType, B : SequenceType, C : SequenceType, D : SequenceType, E : SequenceType, F : SequenceType, R>
(sequenceA: A, sequenceB: B, sequenceC: C, sequenceD: D, sequenceE: E, sequenceF: F,
with fn: (A.Generator.Element, B.Generator.Element, C.Generator.Element, D.Generator.Element, E.Generator.Element, F.Generator.Element)->R)
-> SequenceOf<R>
{
return SequenceOf {_ -> GeneratorOf<R> in
var aG = sequenceA.generate(), bG = sequenceB.generate()
var cG = sequenceC.generate(), dG = sequenceD.generate()
var eG = sequenceE.generate(), fG = sequenceF.generate()
return GeneratorOf {
switch (aG.next(), bG.next(), cG.next(), dG.next(), eG.next(), fG.next()) {
case let (.Some(a), .Some(b), .Some(c), .Some(d), .Some(e), .Some(f)): return fn(a, b, c, d, e, f)
default: return nil
}
}
}
}
/// zip6 with tupling function.
///
/// :returns: Sequence of 6-Tuples.
public func zip<A : SequenceType, B : SequenceType, C : SequenceType, D : SequenceType, E : SequenceType, F : SequenceType>
(sequenceA: A, sequenceB: B, sequenceC: C, sequenceD: D, sequenceE: E, sequenceF: F)
-> SequenceOf<(A.Generator.Element, B.Generator.Element, C.Generator.Element, D.Generator.Element, E.Generator.Element, F.Generator.Element)>
{
return zip(sequenceA, sequenceB, sequenceC, sequenceD, sequenceE, sequenceF) { ($0, $1, $2, $3, $4, $5) }
}
// MARK: zip7. ([A], [B], [C], [D], [E], [F], [G]) -> [(A, B, C, D, E, F, G)]
/// Generalized zip7, zipping with the given function instead of a tupling function.
///
/// :param: fn A function which combines 7 elements.
/// :returns: A sequence of values fn(a, b, c, d, e, f, g).
public func zip<A : SequenceType, B : SequenceType, C : SequenceType, D : SequenceType, E : SequenceType, F : SequenceType, G : SequenceType, R>
(sequenceA: A, sequenceB: B, sequenceC: C, sequenceD: D, sequenceE: E, sequenceF: F, sequenceG: G,
with fn: (A.Generator.Element, B.Generator.Element, C.Generator.Element, D.Generator.Element, E.Generator.Element, F.Generator.Element, G.Generator.Element)->R)
-> SequenceOf<R>
{
return SequenceOf {_ -> GeneratorOf<R> in
var aG = sequenceA.generate(), bG = sequenceB.generate()
var cG = sequenceC.generate(), dG = sequenceD.generate()
var eG = sequenceE.generate(), fG = sequenceF.generate()
var gG = sequenceG.generate()
return GeneratorOf {
switch (aG.next(), bG.next(), cG.next(), dG.next(), eG.next(), fG.next(), gG.next()) {
case let (.Some(a), .Some(b), .Some(c), .Some(d), .Some(e), .Some(f), .Some(g)): return fn(a, b, c, d, e, f, g)
default: return nil
}
}
}
}
/// zip7 with tupling function.
///
/// :returns: Sequence of 7-Tuples.
public func zip<A : SequenceType, B : SequenceType, C : SequenceType, D : SequenceType, E : SequenceType, F : SequenceType, G : SequenceType>
(sequenceA: A, sequenceB: B, sequenceC: C, sequenceD: D, sequenceE: E, sequenceF: F, sequenceG: G)
-> SequenceOf<(A.Generator.Element, B.Generator.Element, C.Generator.Element, D.Generator.Element, E.Generator.Element, F.Generator.Element, G.Generator.Element)>
{
return zip(sequenceA, sequenceB, sequenceC, sequenceD, sequenceE, sequenceF, sequenceG) {
($0, $1, $2, $3, $4, $5, $6)
}
}
// MARK: - unzip
//func unzip<S : SequenceType, A, B where S.Generator.Element == (A, B)>(s: S) -> ([A], [B]) {
//}
// MARK: unzip2. [(A, B)] -> ([A], [B])
/// Transforms an array of N-Tuple into N arrays.
/// Elements of each tuple are collected into corresponding array in returned tuple.
///
/// :param: array An array of pairs (2-Tuple).
/// :returns: A tuple of 2 arrays.
public func unzip<A, B>(array: [(A, B)]) -> ([A], [B]) {
let N = array.count
var aa: [A] = []; aa.reserveCapacity(N)
var bb: [B] = []; bb.reserveCapacity(N)
for (a, b) in array {
aa.append(a)
bb.append(b)
}
return (aa, bb)
}
/// :param: sequence A sequence of pairs (2-Tuple).
/// :returns: A tuple of 2 arrays.
public func unzip<A, B>(sequence: SequenceOf<(A, B)>) -> ([A], [B]) {
return unzip(Array(sequence))
}
// MARK: unzip3. [(A, B, C)] -> ([A], [B], [C])
/// Transforms an array of N-Tuple into N arrays.
/// Elements of each tuple are collected into corresponding array in returned tuple.
///
/// :param: array An array of triples (3-Tuple).
/// :returns: A tuple of 3 arrays.
public func unzip<A, B, C>(array: [(A, B, C)]) -> ([A], [B], [C]) {
let N = array.count
var aa: [A] = []; aa.reserveCapacity(N)
var bb: [B] = []; bb.reserveCapacity(N)
var cc: [C] = []; cc.reserveCapacity(N)
for (a, b, c) in array {
aa.append(a)
bb.append(b)
cc.append(c)
}
return (aa, bb, cc)
}
/// :param: sequence A sequence of triples (3-Tuple).
/// :returns: A tuple of 3 arrays.
public func unzip<A, B, C>(sequence: SequenceOf<(A, B, C)>) -> ([A], [B], [C]) {
return unzip(Array(sequence))
}
// MARK: unzip4. [(A, B, C, D)] -> ([A], [B], [C], [D])
/// Transforms an array of N-Tuple into N arrays.
/// Elements of each tuple are collected into corresponding array in returned tuple.
///
/// :param: array An array of quadruples (4-Tuple).
/// :returns: A tuple of 4 arrays.
public func unzip<A, B, C, D>(array: [(A, B, C, D)]) -> ([A], [B], [C], [D]) {
let N = array.count
var aa: [A] = []; aa.reserveCapacity(N)
var bb: [B] = []; bb.reserveCapacity(N)
var cc: [C] = []; cc.reserveCapacity(N)
var dd: [D] = []; dd.reserveCapacity(N)
for (a, b, c, d) in array {
aa.append(a)
bb.append(b)
cc.append(c)
dd.append(d)
}
return (aa, bb, cc, dd)
}
/// :param: sequence A sequence of quadruples (4-Tuple).
/// :returns: A tuple of 4 arrays.
public func unzip<A, B, C, D>(sequence: SequenceOf<(A, B, C, D)>) -> ([A], [B], [C], [D]) {
return unzip(Array(sequence))
}
// MARK: unzip5. [(A, B, C, D, E)] -> ([A], [B], [C], [D], [E])
/// Transforms an array of N-Tuple into N arrays.
/// Elements of each tuple are collected into corresponding array in returned tuple.
///
/// :param: array An array of 5-Tuples.
/// :returns: A tuple of 5 arrays.
public func unzip<A, B, C, D, E>(array: [(A, B, C, D, E)])
-> ([A], [B], [C], [D], [E])
{
let N = array.count
var aa: [A] = []; aa.reserveCapacity(N)
var bb: [B] = []; bb.reserveCapacity(N)
var cc: [C] = []; cc.reserveCapacity(N)
var dd: [D] = []; dd.reserveCapacity(N)
var ee: [E] = []; ee.reserveCapacity(N)
for (a, b, c, d, e) in array {
aa.append(a)
bb.append(b)
cc.append(c)
dd.append(d)
ee.append(e)
}
return (aa, bb, cc, dd, ee)
}
/// :param: sequence A sequence of 5-Tuples.
/// :returns: A tuple of 5 arrays.
public func unzip<A, B, C, D, E>(sequence: SequenceOf<(A, B, C, D, E)>)
-> ([A], [B], [C], [D], [E])
{
return unzip(Array(sequence))
}
// MARK: unzip6. [(A, B, C, D, E, F)] -> ([A], [B], [C], [D], [E], [F])
/// Transforms an array of N-Tuple into N arrays.
/// Elements of each tuple are collected into corresponding array in returned tuple.
///
/// :param: array An array of 6-Tuples.
/// :returns: A tuple of 6 arrays.
public func unzip<A, B, C, D, E, F>(array: [(A, B, C, D, E, F)])
-> ([A], [B], [C], [D], [E], [F])
{
let N = array.count
var aa: [A] = []; aa.reserveCapacity(N)
var bb: [B] = []; bb.reserveCapacity(N)
var cc: [C] = []; cc.reserveCapacity(N)
var dd: [D] = []; dd.reserveCapacity(N)
var ee: [E] = []; ee.reserveCapacity(N)
var ff: [F] = []; ff.reserveCapacity(N)
for (a, b, c, d, e, f) in array {
aa.append(a)
bb.append(b)
cc.append(c)
dd.append(d)
ee.append(e)
ff.append(f)
}
return (aa, bb, cc, dd, ee, ff)
}
/// :param: sequence A sequence of 6-Tuples.
/// :returns: A tuple of 6 arrays.
public func unzip<A, B, C, D, E, F>(sequence: SequenceOf<(A, B, C, D, E, F)>)
-> ([A], [B], [C], [D], [E], [F])
{
return unzip(Array(sequence))
}
// MARK: unzip7. [(A, B, C, D, E, F, G)] -> ([A], [B], [C], [D], [E], [F], [G])
/// Transforms an array of N-Tuple into N arrays.
/// Elements of each tuple are collected into corresponding array in returned tuple.
///
/// :param: array An array of 7-Tuples.
/// :returns: A tuple of 7 arrays.
public func unzip<A, B, C, D, E, F, G>(array: [(A, B, C, D, E, F, G)])
-> ([A], [B], [C], [D], [E], [F], [G])
{
let N = array.count
var aa: [A] = []; aa.reserveCapacity(N)
var bb: [B] = []; bb.reserveCapacity(N)
var cc: [C] = []; cc.reserveCapacity(N)
var dd: [D] = []; dd.reserveCapacity(N)
var ee: [E] = []; ee.reserveCapacity(N)
var ff: [F] = []; ff.reserveCapacity(N)
var gg: [G] = []; gg.reserveCapacity(N)
for (a, b, c, d, e, f, g) in array {
aa.append(a)
bb.append(b)
cc.append(c)
dd.append(d)
ee.append(e)
ff.append(f)
gg.append(g)
}
return (aa, bb, cc, dd, ee, ff, gg)
}
/// :param: sequence A sequence of 7-Tuples.
/// :returns: A tuple of 7 arrays.
public func unzip<A, B, C, D, E, F, G>(sequence: SequenceOf<(A, B, C, D, E, F, G)>)
-> ([A], [B], [C], [D], [E], [F], [G])
{
return unzip(Array(sequence))
}
// MARK: - zip (longest)
// Zip sequences together, stops when all generators are exhausted.
// Exausted generators are `nil`ed out, returning `nil` for any further accesss.
// MARK: ([A], [B]) -> [(A?, B?)]
/// Generalized zip2 longest, zipping with the given function instead of a tupling function.
///
/// :returns: A sequence of values f(a?, b?)
public func zipLongest<A : SequenceType, B : SequenceType, R>
(sequenceA: A, sequenceB: B, with f: (A.Generator.Element?, B.Generator.Element?)->R)
-> SequenceOf<R>
{
// Wrap function to accept single tuple argument. `(A, B)->R` --> `((A, B))->R`
let ft = { f($0) }
return SequenceOf {_ -> GeneratorOf<R> in
var aG: A.Generator? = sequenceA.generate()
var bG: B.Generator? = sequenceB.generate()
return GeneratorOf {
let nexts = (aG?.next(), bG?.next())
// `nil` out the exhausted generator to prevent any further call to `.next()`
switch nexts { // 2² = 4
case (.None, .None): return nil // ..
case (.Some(_), .Some(_)): break // 11
case (.Some(_), .None): bG = nil // 1.
case (.None, .Some(_)): aG = nil // .1
}
return ft(nexts)
}
}
}
/// zip2 longest with tupling function.
///
/// :returns: A sequence of pairs.
public func zipLongest<A : SequenceType, B : SequenceType>
(sequenceA: A, sequenceB: B)
-> SequenceOf<(A.Generator.Element?, B.Generator.Element?)>
{
return zipLongest(sequenceA, sequenceB) { ($0, $1) }
}
// MARK: ([A], [B], [C]) -> [(A?, B?, C?)]
/// Generalized zip3 longest, zipping with the given function instead of a tupling function.
///
/// :returns: A sequence of values f(a?, b?, c?)
public func zipLongest<A : SequenceType, B : SequenceType, C : SequenceType, R>
(sequenceA: A, sequenceB: B, sequenceC: C,
with f: (A.Generator.Element?, B.Generator.Element?, C.Generator.Element?)->R)
-> SequenceOf<R>
{
// Wrap function to accept single tuple argument. `(A, B)->R` --> `((A, B))->R`
let ft = { f($0) }
return SequenceOf {_ -> GeneratorOf<R> in
var aG: A.Generator? = sequenceA.generate()
var bG: B.Generator? = sequenceB.generate()
var cG: C.Generator? = sequenceC.generate()
return GeneratorOf {
let nexts = (aG?.next(), bG?.next(), cG?.next())
// `nil` out the exhausted generator to prevent any further call to `.next()`
switch nexts { // 2³ = 8
case (.None, .None, .None): return nil // ...
case (.Some(_), .Some(_), .Some(_)): break // 111
case (.Some(_), .None, .None): (bG, cG) = (nil, nil) // 1..
case (.None, .Some(_), .None): (aG, cG) = (nil, nil) // .1.
case (.None, .None, .Some(_)): (aG, bG) = (nil, nil) // ..1
case (.None, .Some(_), .Some(_)): aG = nil // .11
case (.Some(_), .None, .Some(_)): bG = nil // 1.1
case (.Some(_), .Some(_), .None): cG = nil // 11.
}
return ft(nexts)
}
}
}
/// zip3 longest with tupling function.
///
/// :returns: A sequence of triples.
public func zipLongest<A : SequenceType, B : SequenceType, C : SequenceType>
(sequenceA: A, sequenceB: B, sequenceC: C)
-> SequenceOf<(A.Generator.Element?, B.Generator.Element?, C.Generator.Element?)>
{
return zipLongest(sequenceA, sequenceB, sequenceC) { ($0, $1, $2) }
}
// MARK: ([A], [B], [C], [D]) -> [(A?, B?, C?, D?)]
/// Generalized zip4 longest, zipping with the given function instead of a tupling function.
///
/// :returns: A sequence of values f(a?, b?, c?, d?)
public func zipLongest<A : SequenceType, B : SequenceType, C : SequenceType, D : SequenceType, R>
(sequenceA: A, sequenceB: B, sequenceC: C, sequenceD: D,
with f: (A.Generator.Element?, B.Generator.Element?, C.Generator.Element?, D.Generator.Element?)->R)
-> SequenceOf<R>
{
// Wrap function to accept single tuple argument. `(A, B)->R` --> `((A, B))->R`
let ft = { f($0) }
return SequenceOf {_ -> GeneratorOf<R> in
var aG: A.Generator? = sequenceA.generate()
var bG: B.Generator? = sequenceB.generate()
var cG: C.Generator? = sequenceC.generate()
var dG: D.Generator? = sequenceD.generate()
return GeneratorOf {
let nexts = (aG?.next(), bG?.next(), cG?.next(), dG?.next())
// `nil` out the exhausted generator to prevent any further call to `.next()`
switch nexts { // 2⁴ = 16
case (.None, .None, .None, .None): return nil // ....
case (.Some(_), .Some(_), .Some(_), .Some(_)): break // 1111
case (.Some(_), .None, .None, .None): (bG, cG, dG) = (nil, nil, nil) // 1...
case (.None, .Some(_), .None, .None): (aG, cG, dG) = (nil, nil, nil) // .1..
case (.None, .None, .Some(_), .None): (aG, bG, dG) = (nil, nil, nil) // ..1.
case (.None, .None, .None, .Some(_)): (aG, bG, cG) = (nil, nil, nil) // ...1
case (.Some(_), .Some(_), .None, .None): (cG, dG) = (nil, nil) // 11..
case (.Some(_), .None, .Some(_), .None): (bG, dG) = (nil, nil) // 1.1.
case (.Some(_), .None, .None, .Some(_)): (bG, cG) = (nil, nil) // 1..1
case (.None, .Some(_), .None, .Some(_)): (aG, cG) = (nil, nil) // .1.1
case (.None, .None, .Some(_), .Some(_)): (aG, bG) = (nil, nil) // ..11
case (.None, .Some(_), .Some(_), .None): (aG, dG) = (nil, nil) // .11.
case (.Some(_), .Some(_), .Some(_), .None): dG = nil // 111.
case (.Some(_), .Some(_), .None, .Some(_)): cG = nil // 11.1
case (.Some(_), .None, .Some(_), .Some(_)): bG = nil // 1.11
case (.None, .Some(_), .Some(_), .Some(_)): aG = nil // .111
}
return ft(nexts) // f <| nexts
}
}
}
/// zip4 longest with tupling function.
///
/// :returns: A sequence of quadruples.
public func zipLongest<A : SequenceType, B : SequenceType, C : SequenceType, D : SequenceType>
(sequenceA: A, sequenceB: B, sequenceC: C, sequenceD: D)
-> SequenceOf<(A.Generator.Element?, B.Generator.Element?, C.Generator.Element?, D.Generator.Element?)>
{
return zipLongest(sequenceA, sequenceB, sequenceC, sequenceD) { ($0, $1, $2, $3) }
}
// MARK: -
// Example use of `zipLongest` to implement equality of sequences with different element types.
/*
func equal<A : SequenceType, B : SequenceType>
(a: A, b: B, isEquivalent: (A.Generator.Element, B.Generator.Element)->Bool)
-> Bool
{
for pair in zipLongest(a, b) {
switch pair {
case (.None, .None): preconditionFailure("(.None, .None)")
case (.None, .Some(_)), (.Some(_), .None): return false
case let (.Some(x), .Some(y)):
if !isEquivalent(x, y) { return false }
break
}
}
return true
}
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment