Skip to content

Instantly share code, notes, and snippets.

@a-voronov
Last active November 8, 2019 00:39

Revisions

  1. a-voronov revised this gist Nov 8, 2019. 1 changed file with 8 additions and 0 deletions.
    8 changes: 8 additions & 0 deletions one-or-more.swift
    Original file line number Diff line number Diff line change
    @@ -66,6 +66,14 @@ public extension OneOrMore where T: Hashable {
    extension OneOrMore: Equatable where T: Equatable {}
    extension OneOrMore: Hashable where T: Hashable {}

    // MARK: Debugging

    extension OneOrMore: CustomDebugStringConvertible {
    public var debugDescription: String {
    array.debugDescription
    }
    }

    // MARK: Decompose collection to map into OneOrMore

    extension Collection {
  2. a-voronov created this gist Nov 8, 2019.
    77 changes: 77 additions & 0 deletions one-or-more.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,77 @@
    public indirect enum OneOrMore<T> {
    case one(T)
    case more(T, Self)
    }

    // MARK: Creation simplified

    public extension OneOrMore {
    static func few(_ head: T, _ tail: T...) -> OneOrMore {
    few(head, tail)
    }

    static func few<S>(_ head: T, _ tail: S) -> OneOrMore where S: Sequence, S.Element == T {
    var many: OneOrMore = .one(head)
    for value in tail {
    many = .more(value, many)
    }
    return many
    }
    }

    // MARK: Adding elements

    public extension OneOrMore {
    mutating func add(_ other: T) {
    self = adding(other)
    }

    func adding(_ other: T) -> Self {
    .more(other, self)
    }
    }

    // MARK: Array representation

    public extension OneOrMore {
    var array: [T] {
    switch self {
    case let .one(value):
    return [value]
    case let .more(value, other):
    var copy = other.array
    copy.append(value)
    return copy
    }
    }
    }

    // MARK: Set representation

    public extension OneOrMore where T: Hashable {
    var set: Set<T> {
    switch self {
    case let .one(value):
    return [value]
    case let .more(value, other):
    var copy = other.set
    copy.insert(value)
    return copy
    }
    }
    }

    // MARK: Equatable & Hashable

    extension OneOrMore: Equatable where T: Equatable {}
    extension OneOrMore: Hashable where T: Hashable {}

    // MARK: Decompose collection to map into OneOrMore

    extension Collection {
    func decompose() -> (head: Element, tail: [Element])? {
    first.map { head in
    (head: head, tail: Array(dropFirst()))
    }
    }
    }