friend std::ostream& operator<<(std::ostream& ostr, const self_t& pc)
  {
    typedef typename self_t::iterator local_it;
    local_it begin_it(pc.begin());
    local_it end_it(pc.end());

    ostr << "list of (cached) primes follows:" << std::endl;
    for (; begin_it != end_it; begin_it++)
      {
	ostr << *begin_it << " ";
      }
    return ostr;
  }
 static decltype(auto) deduce() {
     return deduce_impl(begin_it(), 0);
 }
TupleIdSequence* SortColumnPredicateEvaluator::EvaluatePredicateForUncompressedSortColumn(
    const Predicate &predicate,
    const CatalogRelation &relation,
    const attribute_id sort_attribute_id,
    void *sort_attribute_stripe,
    const tuple_id num_tuples) {
  // Determine if the predicate is a comparison of the sort column with a literal.
  if (predicate.isAttributeLiteralComparisonPredicate()) {
    const ComparisonPredicate &comparison_predicate = static_cast<const ComparisonPredicate&>(predicate);

    const CatalogAttribute *comparison_attribute = NULL;
    bool left_literal = false;
    if (comparison_predicate.getLeftOperand().hasStaticValue()) {
      DEBUG_ASSERT(comparison_predicate.getRightOperand().getDataSource() == Scalar::kAttribute);
      comparison_attribute
          = &(static_cast<const ScalarAttribute&>(comparison_predicate.getRightOperand()).getAttribute());
      left_literal = true;
    } else {
      DEBUG_ASSERT(comparison_predicate.getLeftOperand().getDataSource() == Scalar::kAttribute);
      comparison_attribute
          = &(static_cast<const ScalarAttribute&>(comparison_predicate.getLeftOperand()).getAttribute());
      left_literal = false;
    }

    DEBUG_ASSERT(comparison_attribute->getParent().getID() == relation.getID());
    if (comparison_attribute->getID() == sort_attribute_id) {
      const LiteralTypeInstance* comparison_literal;
      if (left_literal) {
        comparison_literal = &(comparison_predicate.getLeftOperand().getStaticValue());
      } else {
        comparison_literal = &(comparison_predicate.getRightOperand().getStaticValue());
      }

      // NOTE(chasseur): A standards-compliant implementation of lower_bound
      // always compares the iterator on the left with the literal on the right,
      // while upper_bound compares the literal on the left with the iterator
      // on the right. These will work even if comparison_attribute and
      // comparison_literal are different types.
      const Comparison &less_comparison = Comparison::GetComparison(Comparison::kLess);
      ScopedPtr<UncheckedComparator> fast_comparator_lower(
          less_comparison.makeUncheckedComparatorForTypes(comparison_attribute->getType(),
                                                          comparison_literal->getType()));
      STLUncheckedComparatorWrapper comp_lower(*fast_comparator_lower);
      ScopedPtr<UncheckedComparator> fast_comparator_upper(
          less_comparison.makeUncheckedComparatorForTypes(comparison_literal->getType(),
                                                          comparison_attribute->getType()));
      STLUncheckedComparatorWrapper comp_upper(*fast_comparator_upper);

      // Find the bounds on the range of matching tuples.
      tuple_id min_match = 0;
      tuple_id max_match_bound = num_tuples;
      ColumnStripeIterator begin_it(sort_attribute_stripe,
                                    relation.getAttributeById(sort_attribute_id).getType().maximumByteLength(),
                                    0);
      ColumnStripeIterator end_it(sort_attribute_stripe,
                                  relation.getAttributeById(sort_attribute_id).getType().maximumByteLength(),
                                  num_tuples);

      switch (comparison_predicate.getComparison().getComparisonID()) {
        case Comparison::kEqual:
        // Note: There is a special branch below for kNotEqual which takes the
        // complement of the matched range.
        case Comparison::kNotEqual:
          min_match = lower_bound(begin_it,
                                  end_it,
                                  comparison_literal->getDataPtr(),
                                  comp_lower).getTuplePosition();
          max_match_bound = upper_bound(begin_it,
                                        end_it,
                                        comparison_literal->getDataPtr(),
                                        comp_upper).getTuplePosition();
          break;
        case Comparison::kLess:
          if (left_literal) {
            min_match = upper_bound(begin_it,
                                    end_it,
                                    comparison_literal->getDataPtr(),
                                    comp_upper).getTuplePosition();
          } else {
            max_match_bound = lower_bound(begin_it,
                                          end_it,
                                          comparison_literal->getDataPtr(),
                                          comp_lower).getTuplePosition();
          }
          break;
        case Comparison::kLessOrEqual:
          if (left_literal) {
            min_match = lower_bound(begin_it,
                                    end_it,
                                    comparison_literal->getDataPtr(),
                                    comp_lower).getTuplePosition();
          } else {
            max_match_bound = upper_bound(begin_it,
                                          end_it,
                                          comparison_literal->getDataPtr(),
                                          comp_upper).getTuplePosition();
          }
          break;
        case Comparison::kGreater:
          if (left_literal) {
            max_match_bound = lower_bound(begin_it,
                                          end_it,
                                          comparison_literal->getDataPtr(),
                                          comp_lower).getTuplePosition();
          } else {
            min_match = upper_bound(begin_it,
                                    end_it,
                                    comparison_literal->getDataPtr(),
                                    comp_upper).getTuplePosition();
          }
          break;
        case Comparison::kGreaterOrEqual:
          if (left_literal) {
            max_match_bound = upper_bound(begin_it,
                                          end_it,
                                          comparison_literal->getDataPtr(),
                                          comp_upper).getTuplePosition();
          } else {
            min_match = lower_bound(begin_it,
                                    end_it,
                                    comparison_literal->getDataPtr(),
                                    comp_lower).getTuplePosition();
          }
          break;
        default:
          FATAL_ERROR("Unknown Comparison in SortColumnPredicateEvaluator::"
                      "EvaluatePredicateForUncompressedSortColumn()");
      }

      // Create and return the sequence of matches.
      TupleIdSequence *matches = new TupleIdSequence();
      if (comparison_predicate.getComparison().getComparisonID() == Comparison::kNotEqual) {
        // Special case: return all tuples NOT in the range for kEqual.
        for (tuple_id tid = 0; tid < min_match; ++tid) {
          matches->append(tid);
        }
        for (tuple_id tid = max_match_bound; tid < num_tuples; ++tid) {
          matches->append(tid);
        }
      } else {
        for (tuple_id tid = min_match; tid < max_match_bound; ++tid) {
          matches->append(tid);
        }
      }

      return matches;
    } else {
      return NULL;
    }
  } else {
    // Can not evaluate a non-comparison predicate, so pass through.
    return NULL;
  }
}