As discussed with @kitaisreal 
class IMergeTreeReader : private boost::noncopyable
{
public:
    using ValueSizeMap = std::map<std::string, double>;
    using DeserializeBinaryBulkStateMap = std::map<std::string, ISerialization::DeserializeBinaryBulkStatePtr>;
    IMergeTreeReader(
        const MergeTreeData::DataPartPtr & data_part_,
        const NamesAndTypesList & columns_,
        const StorageMetadataPtr & metadata_snapshot_,
        UncompressedCache * uncompressed_cache_,
        MarkCache * mark_cache_,
        const MarkRanges & all_mark_ranges_,
        const MergeTreeReaderSettings & settings_,
        const ValueSizeMap & avg_value_size_hints_ = ValueSizeMap{});
    
    
    virtual size_t readRows(size_t from_mark, bool continue_reading, size_t max_rows_to_read, Columns & res_columns) = 0;
    virtual bool canReadIncompleteGranules() const = 0;
    virtual ~IMergeTreeReader();
    const ValueSizeMap & getAvgValueSizeHints() const;
    
    
    
    void fillMissingColumns(Columns & res_columns, bool & should_evaluate_missing_defaults, size_t num_rows);
    
    void evaluateMissingDefaults(Block additional_columns, Columns & res_columns);
    
    
    void performRequiredConversions(Columns & res_columns);
    const NamesAndTypesList & getColumns() const { return columns; }