public struct Eratosthenes: Sequence, IteratorProtocol {
  private let n: Int
  private let limit: Int

  private var i = 2
  private var sieve: [Int]

  public init(upTo: Int) {
    if upTo <= 1 {
      self.n = 0
      self.limit = -1
      self.sieve = []
    } else {
      self.n = upTo
      self.limit = Int(Double(n).squareRoot())
      self.sieve = Array(0...n)
    }
  }

  public mutating func next() -> Int? {
    while i < n {
      defer { i += 1 }

      if sieve[i]!= 0 {
        if i <= limit {
          for notPrime in stride(from: i * i, through: n, by: i) {
            sieve[notPrime] = 0
          }
        }

        return i
      }
    }

    return nil
  }
}

func findPeriod(n: Int) -> Int {
  let r = (1...n+1).reduce(1, {res, _ in (10 * res)% n })
  var rr = r
  var period = 0

  repeat {
    rr = (10 * rr)% n
    period += 1
  } while r!= rr

  return period
}

let longPrimes = Eratosthenes(upTo: 64000).dropFirst().lazy.filter({ findPeriod(n: $0) == $0 - 1 })

print("Long primes less than 500: \(Array(longPrimes.prefix(while: { $0 <= 500 })))")

let counts =
  longPrimes.reduce(into: [500: 0, 1000: 0, 2000: 0, 4000: 0, 8000: 0, 16000: 0, 32000: 0, 64000: 0], {counts, n in
    for key in counts.keys where n < key {
      counts[key]! += 1
    }
  })

for key in counts.keys.sorted() {
  print("There are \(counts[key]!) long primes less than \(key)")
}