void SequentialHeapMerger::mergeValues(const std::vector<c_atable_ptr_t > &input_tables,
                                       size_t source_column_index,
                                       atable_ptr_t merged_table,
                                       size_t destination_column_index,
                                       value_id_mapping_t &value_id_mapping,
                                       bool useValid,
                                       const std::vector<bool>& valid) {

  std::vector<AbstractTable::SharedDictionaryPtr > value_id_maps;
  AbstractTable::SharedDictionaryPtr new_dict;

  // shortcut for dicts
  value_id_maps.reserve(input_tables.size());

  for (size_t table = 0; table < input_tables.size(); table++) {
    if (!types::isCompatible(merged_table->metadataAt(destination_column_index).getType(),
         input_tables[table]->metadataAt(source_column_index).getType())) {
      throw std::runtime_error("Dictionary types don't match");
    }
    auto dict = std::dynamic_pointer_cast<BaseDictionary<T>>(input_tables[table]->dictionaryAt(source_column_index));
    value_id_maps.push_back(dict);
  }

  // Create new BaseDictionary - shrink when merge finished?
  new_dict = createNewDict<T>(input_tables, value_id_maps, value_id_mapping, source_column_index, useValid, valid);
  // set new value id map for column
  merged_table->setDictionaryAt(new_dict, destination_column_index);
}
void SequentialHeapMerger::mergeValues(const std::vector<c_atable_ptr_t > &input_tables,
                                       atable_ptr_t merged_table,
                                       const column_mapping_t &column_mapping,
                                       const uint64_t newSize,
                                       bool useValid,
                                       const std::vector<bool>& valid) {

  //if (input_tables.size () != 2)
  //  throw std::runtime_error("Merging more than 2 tables is not supported with this merger...");

  std::vector<value_id_mapping_t> mappingPerAtrtibute(input_tables[0]->columnCount());

  for (const auto & kv: column_mapping) {
    const auto &source = kv.first;
    const auto &destination = kv.second;
    switch (merged_table->metadataAt(destination).getType()) {
    case IntegerType:
    case IntegerTypeDelta:
    case IntegerTypeDeltaConcurrent:
      mergeValues<hyrise_int_t>(input_tables, source, merged_table, destination, mappingPerAtrtibute[source], useValid, valid);
    break;
    
    case FloatType:
    case FloatTypeDelta:
    case FloatTypeDeltaConcurrent:
      mergeValues<hyrise_float_t>(input_tables, source, merged_table, destination, mappingPerAtrtibute[source], useValid, valid);
      break;
      
    case StringType:
    case StringTypeDelta:
    case StringTypeDeltaConcurrent:
      mergeValues<hyrise_string_t>(input_tables, source, merged_table, destination, mappingPerAtrtibute[source], useValid, valid);
      break;
    case IntegerNoDictType:
    case FloatNoDictType:
      merged_table->setDictionaryAt(makeDictionary(merged_table->typeOfColumn(destination)), destination);
    default:
      break;
    }
  }

  merged_table->resize(newSize);

  // Only after the dictionaries are merged copy the values
  for (const auto & kv: column_mapping) {
    const auto &source = kv.first;
    const auto &destination = kv.second;
    // copy the actual values and apply mapping
    copyValues(input_tables, source, merged_table, destination, mappingPerAtrtibute[source], useValid, valid);
  }
}