def bucketIterator(elements, buckets):
  def check_sorted(current, previous):
    if (previous is not None) and \
       ((previous.chrom > current.chrom) or
        ((previous.chrom == current.chrom) and
         (previous.start > current.start))):
      raise GenomicIntervalError("elements not sorted. Saw " +
                                 str(previous) + " before " + str(current))
  def updateOpen(openHeap, elementIterator, bucketChrom,
                 bucketStart, bucketEnd):
    while len(openHeap) > 0 and ((openHeap[0].chrom < bucketChrom) or
                                 ((openHeap[0].chrom == bucketChrom) and
                                 (openHeap[0].end <= bucketStart))):
      heappop(openHeap)
    while (elementIterator.peek() is not None) and \
          ((elementIterator.peek().chrom < bucketChrom) or
           ((elementIterator.peek().chrom == bucketChrom) and
            (elementIterator.peek().start < bucketEnd))):
      e = elementIterator.__next__()
      if (e.chrom < bucketChrom) or \
         (e.chrom == bucketChrom and e.end <= bucketStart):
         continue
      heappush(openHeap, e)
  openElems = []
  prevBucket = None
  elementIter = AutoApplyIterator(elements, check_sorted)
  for bucket in buckets:
    if prevBucket is not None and ((bucket.chrom < prevBucket.chrom) or
                                   (bucket.chrom == prevBucket.chrom and
                                    bucket.start < prevBucket.start)):
      raise GenomicIntervalError("regions-of-interest are not sorted. Saw " +
                                 str(prevBucket) + " before " + str(bucket))
    updateOpen(openElems, elementIter, bucket.chrom, bucket. start, bucket.end)
    yield bucket, [x for x in openElems if x.start < bucket.end]
    prevBucket = bucket