//// Copyright (c) 2014-2015, Pacific Biosciences of California, Inc.
////
//// All rights reserved.
////
//// Redistribution and use in source and binary forms, with or without
//// modification, are permitted (subject to the limitations in the
//// disclaimer below) provided that the following conditions are met:
////
////  * Redistributions of source code must retain the above copyright
////    notice, this list of conditions and the following disclaimer.
////
////  * Redistributions in binary form must reproduce the above
////    copyright notice, this list of conditions and the following
////    disclaimer in the documentation and/or other materials provided
////    with the distribution.
////
////  * Neither the name of Pacific Biosciences nor the names of its
////    contributors may be used to endorse or promote products derived
////    from this software without specific prior written permission.
////
//// NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
//// GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY PACIFIC
//// BIOSCIENCES AND ITS CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
//// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
//// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
//// DISCLAIMED. IN NO EVENT SHALL PACIFIC BIOSCIENCES OR ITS
//// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
//// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
//// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
//// USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
//// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
//// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
//// SUCH DAMAGE.
////
//// Author: Derek Barnett

//#ifndef PBIINDEX_P_H
//#define PBIINDEX_P_H

//#include "pbbam/BamRecord.h"
//#include "pbbam/PbiFile.h"
//#include "pbbam/PbiIndex.h"
//#include "pbbam/PbiRawData.h"

//#include <algorithm>
//#include <map>
//#include <memory>
//#include <unordered_map>
//#include <utility>
//#include <vector>
//#include <cassert>

//namespace PacBio {
//namespace BAM {
//namespace internal {

//// --------------------------
//// Ordered Lookup Container (e.g. map)
//// --------------------------

//template<typename T>
//class OrderedLookup
//{
//public:
//    typedef T         KeyType;
//    typedef IndexList ValueType;
//    typedef std::map<KeyType, ValueType> ContainerType;
//    typedef typename ContainerType::const_iterator IterType;

//public:
//    OrderedLookup(void);
//    OrderedLookup(size_t n);
//    OrderedLookup(const ContainerType& data);
//    OrderedLookup(ContainerType&& data);
//    OrderedLookup(const std::vector<T>& rawData);
//    OrderedLookup(std::vector<T>&& rawData);

//public:
//    bool operator==(const OrderedLookup<T>& other) const;
//    bool operator!=(const OrderedLookup<T>& other) const;

//public:
//    IndexList LookupIndices(const KeyType& key,
//                            const CompareType& compare) const;

//private:
//    IndexList LookupInclusiveRange(const IterType& begin,
//                                   const IterType& end) const;

//    IndexList LookupExclusiveRange(const IterType& begin,
//                                   const IterType& end,
//                                   const KeyType& key) const;

//private:
//    ContainerType data_;
//};

//// --------------------------
//// Unordered Lookup Container (e.g. hash)
//// --------------------------

//template<typename T>
//class UnorderedLookup
//{
//public:
//    typedef T         KeyType;
//    typedef IndexList ValueType;
//    typedef std::unordered_map<KeyType, ValueType> ContainerType;

//public:
//    UnorderedLookup(void);
//    UnorderedLookup(size_t n);
//    UnorderedLookup(const ContainerType& data);
//    UnorderedLookup(ContainerType&& data);
//    UnorderedLookup(const std::vector<T>& rawData);
//    UnorderedLookup(std::vector<T>&& rawData);

//public:
//    bool operator==(const UnorderedLookup<T>& other) const;
//    bool operator!=(const UnorderedLookup<T>& other) const;

//public:
//    IndexList LookupIndices(const KeyType& key,
//                            const CompareType& compare) const;

//private:
//    template<typename Compare>
//    IndexList LookupHelper(const KeyType& key, const Compare& cmp) const;

//private:
//    ContainerType data_;
//};

//// ----------------
//// Subread Data
//// ----------------

//struct SubreadLookupData
//{
//    // ctors
//    SubreadLookupData(void);
//    SubreadLookupData(const PbiRawSubreadData& rawData);
////    SubreadLookupData(PbiRawSubreadData&& rawData);

//    // add offset data to index result blocks
//    void ApplyOffsets(IndexResultBlocks& blocks) const;

//    template<typename T>
//    IndexList Indices(const SubreadField& field,
//                      const T& value,
//                      const CompareType& compareType) const;

//    template<typename T>
//    IndexList IndicesMulti(const SubreadField& field,
//                           const std::vector<T>& values) const;

//    // map ordering doesn't make sense, optimize for direct lookup
//    UnorderedLookup<int32_t> rgId_;

//    // numeric comparisons make sense, keep key ordering preserved
//    OrderedLookup<int32_t>  qStart_;
//    OrderedLookup<int32_t>  qEnd_;
//    OrderedLookup<int32_t>  holeNumber_;
//    OrderedLookup<uint16_t> readQual_;

//    // offsets
//    std::vector<int64_t> fileOffset_;
//};

//// -----------------
//// Mapped Data
//// -----------------

//struct MappedLookupData
//{
//    // ctors
//    MappedLookupData(void);
//    MappedLookupData(const PbiRawMappedData& rawData);
////    MappedLookupData(PbiRawMappedData&& rawData);

//    template<typename T>
//    IndexList Indices(const MappedField& field,
//                      const T& value,
//                      const CompareType& compareType) const;

//    template<typename T>
//    IndexList IndicesMulti(const MappedField& field,
//                           const std::vector<T>& values) const;

//    // numeric comparisons make sense, keep key ordering preserved
//    OrderedLookup<int32_t>  tId_;
//    OrderedLookup<uint32_t> tStart_;
//    OrderedLookup<uint32_t> tEnd_;
//    OrderedLookup<uint32_t> aStart_;
//    OrderedLookup<uint32_t> aEnd_;
//    OrderedLookup<uint32_t> nM_;
//    OrderedLookup<uint32_t> nMM_;
//    OrderedLookup<uint8_t>  mapQV_;

//    // generated, not stored in PBI
//    OrderedLookup<uint32_t> nIns_;
//    OrderedLookup<uint32_t> nDel_;

//    // no need for map overhead, just store direct indices
//    IndexList reverseStrand_;
//    IndexList forwardStrand_;
//};

//// ------------------
//// Reference Data
//// ------------------

//struct ReferenceLookupData
//{
//    // ctors
//    ReferenceLookupData(void);
//    ReferenceLookupData(const PbiRawReferenceData& rawData);
////    ReferenceLookupData(PbiRawReferenceData&& rawData);

//    IndexRange Indices(const int32_t tId) const;

//    // references_[tId] = (begin, end) indices
//    // into SubreadLookupData::fileOffset_
//    std::unordered_map<int32_t, IndexRange> references_;
//};

//// ---------------
//// Barcode Data
//// ---------------

//struct BarcodeLookupData
//{
//    // ctors
//    BarcodeLookupData(void);
//    BarcodeLookupData(const PbiRawBarcodeData& rawData);
////    BarcodeLookupData(PbiRawBarcodeData&& rawData);

//    template<typename T>
//    IndexList Indices(const BarcodeField& field,
//                      const T& value,
//                      const CompareType& compareType) const;

//    template<typename T>
//    IndexList IndicesMulti(const BarcodeField& field,
//                           const std::vector<T>& values) const;

//    // numeric comparisons make sense, keep key ordering preserved
//    OrderedLookup<uint16_t> bcLeft_;
//    OrderedLookup<uint16_t> bcRight_;
//    OrderedLookup<uint8_t>  bcQual_;

//    // see if this works, or if can use unordered, 'direct' query
//    OrderedLookup<uint8_t> ctxtFlag_;
//};

//// --------------------------
//// Pbi Lookup Aggregate
//// --------------------------

//class PbiIndexPrivate
//{
//public:
//    PbiIndexPrivate(void);
//    PbiIndexPrivate(const PbiRawData& rawIndex);
//    PbiIndexPrivate(PbiRawData&& rawIndex);

//    std::unique_ptr<PbiIndexPrivate> DeepCopy(void) const;

//public:
//    bool HasSection(const PbiFile::Section flag) const;
//    void SetSection(const PbiFile::Section flag, bool ok = true);

//public:

//    template<typename T>
//    IndexList Indices(const SubreadField& field,
//                      const T& value,
//                      const CompareType& compareType) const;

//    template<typename T>
//    IndexList Indices(const MappedField& field,
//                      const T& value,
//                      const CompareType& compareType) const;

//    template<typename T>
//    IndexList Indices(const BarcodeField& field,
//                      const T& value,
//                      const CompareType& compareType) const;

//    template<typename T>
//    IndexList IndicesMulti(const SubreadField& field,
//                           const T& value) const;

//    template<typename T>
//    IndexList IndicesMulti(const MappedField& field,
//                           const T& value) const;

//    template<typename T>
//    IndexList IndicesMulti(const BarcodeField& field,
//                           const T& value) const;

//    template<typename T>
//    IndexResultBlocks Lookup(const SubreadField& field,
//                             const T& value,
//                             const CompareType& compareType) const;

//    template<typename T>
//    IndexResultBlocks Lookup(const MappedField& field,
//                             const T& value,
//                             const CompareType& compareType) const;

//    template<typename T>
//    IndexResultBlocks Lookup(const BarcodeField& field,
//                             const T& value,
//                             const CompareType& compareType) const;

//    template<typename T>
//    IndexResultBlocks LookupMulti(const SubreadField& field,
//                                  const std::vector<T>& values) const;

//    template<typename T>
//    IndexResultBlocks LookupMulti(const MappedField& field,
//                                  const std::vector<T>& values) const;

//    template<typename T>
//    IndexResultBlocks LookupMulti(const BarcodeField& field,
//                                  const std::vector<T>& values) const;

//    IndexResultBlocks LookupReference(const int32_t tId) const;

//private:
//    IndexResultBlocks MergeBlocksWithOffsets(const IndexList& indices) const;

//public:
//    PbiFile::VersionEnum version_;
//    PbiFile::Sections sections_;
//    uint32_t numReads_;

//    // lookup structures
//    SubreadLookupData   subreadData_;
//    MappedLookupData    mappedData_;
//    ReferenceLookupData referenceData_;
//    BarcodeLookupData   barcodeData_;

//private:
//    // not-implemented - ensure no copy
//    PbiIndexPrivate(const PbiIndexPrivate& other);
//    PbiIndexPrivate& operator=(const PbiIndexPrivate& other);
//};

//// ----------------
//// helper methods
//// ----------------

//inline IndexResultBlocks mergedIndexBlocks(IndexList&& indices)
//{
//    if (indices.empty())
//        return IndexResultBlocks();
//    std::sort(indices.begin(), indices.end());

//    IndexResultBlocks result;
//    result.push_back(IndexResultBlock(indices.at(0), 1));
//    const size_t numIndices = indices.size();
//    for (size_t i = 1; i < numIndices; ++i) {
//        if (indices.at(i) == indices.at(i-1)+1)
//            ++result.back().numReads_;
//        else
//            result.push_back(IndexResultBlock(indices.at(i), 1));
//    }
//    return result;
//}

//inline IndexResultBlocks mergedIndexBlocks(const IndexList& indices)
//{
//    IndexList copy = indices;
//    return mergedIndexBlocks(std::move(copy));
//}

//inline size_t nullIndex(void)
//{ return static_cast<size_t>(-1); }

//inline
//void pushBackIndices(IndexList& result,
//                     const IndexList& toAppend)
//{
//    result.reserve(result.size() + toAppend.size());
//    for (auto element : toAppend)
//        result.push_back(element);
//}

//// -----------------
//// OrderedLookup
//// -----------------

//template<typename T>
//inline OrderedLookup<T>::OrderedLookup(void) { }

//template<typename T>
//inline OrderedLookup<T>::OrderedLookup(size_t n)
//{ data_.reserve(n); }

//template<typename T>
//inline OrderedLookup<T>::OrderedLookup(const ContainerType& data)
//    : data_(data)
//{ }

//template<typename T>
//inline OrderedLookup<T>::OrderedLookup(ContainerType&& data)
//    : data_(std::move(data))
//{ }

//template<typename T>
//inline OrderedLookup<T>::OrderedLookup(const std::vector<T>& rawData)
//{
//    const size_t numElements = rawData.size();
//    for (size_t i = 0; i < numElements; ++i)
//        data_[ rawData.at(i) ].push_back(i);
//}

//template<typename T>
//inline OrderedLookup<T>::OrderedLookup(std::vector<T>&& rawData)
//{
//    const size_t numElements = rawData.size();
//    for (size_t i = 0; i < numElements; ++i)
//        data_[ rawData.at(i) ].push_back(i);
//}

//template<typename T>
//inline bool OrderedLookup<T>::operator==(const OrderedLookup<T>& other) const
//{ return data_ == other.data_; }

//template<typename T>
//inline bool OrderedLookup<T>::operator!=(const OrderedLookup<T>& other) const
//{ return !(*this == other); }

//template<typename T>
//inline IndexList
//OrderedLookup<T>::LookupInclusiveRange(const IterType& begin,
//                                       const IterType& end) const
//{
//    IndexList result;
//    for ( auto iter = begin; iter != end; ++iter )
//        pushBackIndices(result, iter->second);
//    std::sort(result.begin(), result.end());
//    return result;
//}

//template<typename T>
//inline IndexList
//OrderedLookup<T>::LookupExclusiveRange(const IterType& begin,
//                                       const IterType& end,
//                                       const KeyType& key) const
//{
//    IndexList result;
//    for ( auto iter = begin; iter != end; ++iter ) {
//        if (iter->first != key)
//            pushBackIndices(result, iter->second);
//    }
//    std::sort(result.begin(), result.end());
//    return result;
//}

//template<typename T>
//inline IndexList
//OrderedLookup<T>::LookupIndices(const OrderedLookup::KeyType& key,
//                                const CompareType& compare) const
//{
//    const IterType begin = data_.cbegin();
//    const IterType end   = data_.cend();
//    switch(compare)
//    {
//        case CompareType::EQUAL:
//        {
//            const auto found = data_.find(key);
//            if (found != end)
//                return found->second;
//            return IndexList();
//        }
//        case CompareType::LESS_THAN:          return LookupExclusiveRange(begin, data_.upper_bound(key), key);
//        case CompareType::LESS_THAN_EQUAL:    return LookupInclusiveRange(begin, data_.upper_bound(key));
//        case CompareType::GREATER_THAN:       return LookupExclusiveRange(data_.lower_bound(key), end, key);
//        case CompareType::GREATER_THAN_EQUAL: return LookupInclusiveRange(data_.lower_bound(key), end);
//        case CompareType::NOT_EQUAL:          return LookupExclusiveRange(begin, end, key);
//        default:
//            assert(false);
//    }
//    return IndexList();
//}

//// -----------------
//// UnorderedLookup
//// -----------------

//template<typename T>
//inline UnorderedLookup<T>::UnorderedLookup(void) { }

//template<typename T>
//inline UnorderedLookup<T>::UnorderedLookup(size_t n)
//{ data_.reserve(n); }

//template<typename T>
//inline UnorderedLookup<T>::UnorderedLookup(const ContainerType& data)
//    : data_(data)
//{ }

//template<typename T>
//inline UnorderedLookup<T>::UnorderedLookup(ContainerType&& data)
//    : data_(std::move(data))
//{ }

//template<typename T>
//inline UnorderedLookup<T>::UnorderedLookup(const std::vector<T> &rawData)
//{
//    const size_t numElements = rawData.size();
//    for (size_t i = 0; i < numElements; ++i)
//        data_[ rawData.at(i) ].push_back(i);
//}

//template<typename T>
//inline UnorderedLookup<T>::UnorderedLookup(std::vector<T>&& rawData)
//{
//    const size_t numElements = rawData.size();
//    for (size_t i = 0; i < numElements; ++i)
//        data_[ rawData.at(i) ].push_back(i);
//}

//template<typename T>
//inline bool UnorderedLookup<T>::operator==(const UnorderedLookup<T>& other) const
//{ return data_ == other.data_; }

//template<typename T>
//inline bool UnorderedLookup<T>::operator!=(const UnorderedLookup<T>& other) const
//{ return !(*this == other); }

//template<typename T>
//template<typename Compare>
//inline IndexList
//UnorderedLookup<T>::LookupHelper(const UnorderedLookup::KeyType& key,
//                                 const Compare& cmp) const
//{
//    auto iter = data_.cbegin();
//    const auto end = data_.cend();
//    IndexList result; // init with some avg size ??
//    for ( ; iter != end; ++iter ) {
//        const auto e = (iter->first);
//        if (cmp(e, key))
//            pushBackIndices(result, iter->second);
//    }
//    std::sort(result.begin(), result.end());
//    return result;
//}

//template<typename T>
//inline IndexList
//UnorderedLookup<T>::LookupIndices(const UnorderedLookup::KeyType& key,
//                                  const CompareType& compare) const
//{
//    switch (compare) {
//        case CompareType::EQUAL:
//        {
//            const auto found = data_.find(key);
//            if (found != data_.cend())
//                return found->second;
//            else
//                return IndexList();
//        }
//        case CompareType::LESS_THAN:          return LookupHelper(key, std::less<KeyType>());
//        case CompareType::LESS_THAN_EQUAL:    return LookupHelper(key, std::less_equal<KeyType>());
//        case CompareType::GREATER_THAN:       return LookupHelper(key, std::greater<KeyType>());
//        case CompareType::GREATER_THAN_EQUAL: return LookupHelper(key, std::greater_equal<KeyType>());
//        case CompareType::NOT_EQUAL:          return LookupHelper(key, std::not_equal_to<KeyType>());
//        default:
//            assert(false);
//    }
//    return IndexList();
//}

//// -------------------
//// SubreadLookupData
//// -------------------

//inline
//void SubreadLookupData::ApplyOffsets(IndexResultBlocks& blocks) const
//{
//    for (IndexResultBlock& block : blocks)
//        block.virtualOffset_ = fileOffset_.at(block.firstIndex_);
//}

//template<typename T>
//inline IndexList SubreadLookupData::Indices(const SubreadField& field,
//                                            const T& value,
//                                            const CompareType& compareType) const
//{
//    switch(field) {
//        case SubreadField::RG_ID:        return rgId_.LookupIndices(value, compareType);
//        case SubreadField::Q_START:      return qStart_.LookupIndices(value, compareType);
//        case SubreadField::Q_END:        return qEnd_.LookupIndices(value, compareType);
//        case SubreadField::ZMW:          return holeNumber_.LookupIndices(value, compareType);
//        case SubreadField::READ_QUALITY: return readQual_.LookupIndices(value, compareType);

//        case SubreadField::VIRTUAL_OFFSET : // fall-through, not supported this way
//        default:
//            assert(false);
//    }
//    return IndexList();
//}

//template<typename T>
//inline IndexList SubreadLookupData::IndicesMulti(const SubreadField& field,
//                                                 const std::vector<T>& values) const
//{
//    IndexList result;
//    for (auto value : values) {
//        const IndexList& valueIndices = Indices(field, value, CompareType::EQUAL);
//        result.reserve(result.size() + valueIndices.size());
//        for (auto i : valueIndices)
//            result.push_back(i);
//    }
//    return result;
//}

//// -------------------
//// MappedLookupData
//// -------------------

//template<typename T>
//inline IndexList MappedLookupData::Indices(const MappedField& field,
//                                           const T& value,
//                                           const CompareType& compareType) const
//{
//    switch(field) {
//        case MappedField::T_ID:        return tId_.LookupIndices(value, compareType);
//        case MappedField::T_START:     return tStart_.LookupIndices(value, compareType);
//        case MappedField::T_END:       return tEnd_.LookupIndices(value, compareType);
//        case MappedField::A_START:     return aStart_.LookupIndices(value, compareType);
//        case MappedField::A_END:       return aEnd_.LookupIndices(value, compareType);
//        case MappedField::N_M:         return nM_.LookupIndices(value, compareType);
//        case MappedField::N_MM:        return nM_.LookupIndices(value, compareType);
//        case MappedField::MAP_QUALITY: return mapQV_.LookupIndices(value, compareType);

//        // MappedField::STRAND has its own specialization

//        default:
//            assert(false);
//    }
//    return IndexList();
//}

//template<>
//inline IndexList MappedLookupData::Indices(const MappedField& field,
//                                           const Strand& strand,
//                                           const CompareType& compareType) const
//{
//    assert(field == MappedField::STRAND);

//    if (compareType == CompareType::EQUAL) {
//        if (strand == Strand::FORWARD)
//            return forwardStrand_;
//        else
//            return reverseStrand_;
//    } else if (compareType == CompareType::NOT_EQUAL) {
//        if (strand == Strand::FORWARD)
//            return reverseStrand_;
//        else
//            return forwardStrand_;
//    }

//    // only EQUAL/NOT_EQUAL supported
//    assert(false);
//    return IndexList();
//}

//template<typename T>
//inline IndexList MappedLookupData::IndicesMulti(const MappedField& field,
//                                                const std::vector<T>& values) const
//{
//    IndexList result;
//    for (auto value : values) {
//        const IndexList& valueIndices = Indices(field, value, CompareType::EQUAL);
//        result.reserve(result.size() + valueIndices.size());
//        for (auto i : valueIndices)
//            result.push_back(i);
//    }
//    return result;
//}


//// ---------------------
//// ReferenceLookupData
//// ---------------------

//inline IndexRange ReferenceLookupData::Indices(const int32_t tId) const
//{
//    auto found = references_.find(tId);
//    if (found == references_.cend())
//        return IndexRange(nullIndex(), nullIndex());
//    return found->second;
//}

//// -------------------
//// BarcodeLookupData
//// -------------------

//template<typename T>
//inline IndexList BarcodeLookupData::Indices(const BarcodeField& field,
//                                            const T& value,
//                                            const CompareType& compareType) const
//{
//    switch(field) {
//        case BarcodeField::BC_LEFT:      return bcLeft_.LookupIndices(value, compareType);
//        case BarcodeField::BC_RIGHT:     return bcRight_.LookupIndices(value, compareType);
//        case BarcodeField::BC_QUALITY:   return bcQual_.LookupIndices(value, compareType);
//        case BarcodeField::CONTEXT_FLAG: return ctxtFlag_.LookupIndices(value, compareType);
//        default:
//            assert(false);
//    }
//    return IndexList();
//}

//template<typename T>
//inline IndexList BarcodeLookupData::IndicesMulti(const BarcodeField& field,
//                                                 const std::vector<T>& values) const
//{
//    IndexList result;
//    for (auto value : values) {
//        const IndexList& valueIndices = Indices(field, value, CompareType::EQUAL);
//        result.reserve(result.size() + valueIndices.size());
//        for (auto i : valueIndices)
//            result.push_back(i);
//    }
//    return result;
//}


//// -----------------
//// PbiIndexPrivate
//// -----------------

//inline bool PbiIndexPrivate::HasSection(const PbiFile::Section flag) const
//{ return (sections_ & flag) != 0; }

//inline void PbiIndexPrivate::SetSection(const PbiFile::Section flag, bool ok)
//{ if (ok) sections_ |= flag; else sections_ &= ~flag; }

//template<typename T>
//inline IndexList
//PbiIndexPrivate::Indices(const SubreadField& field,
//                         const T& value,
//                         const CompareType& compareType) const
//{ return subreadData_.Indices(field, value, compareType); }

//template<typename T>
//inline IndexList
//PbiIndexPrivate::Indices(const MappedField& field,
//                         const T& value,
//                         const CompareType& compareType) const
//{ return mappedData_.Indices(field, value, compareType); }

//template<typename T>
//inline IndexList
//PbiIndexPrivate::Indices(const BarcodeField& field,
//                         const T& value,
//                         const CompareType& compareType) const
//{ return barcodeData_.Indices(field, value, compareType); }

//template<typename T>
//inline IndexList
//PbiIndexPrivate::IndicesMulti(const SubreadField& field,
//                              const T& value) const
//{ return subreadData_.IndicesMulti(field, value); }

//template<typename T>
//inline IndexList
//PbiIndexPrivate::IndicesMulti(const MappedField& field,
//                              const T& value) const
//{ return mappedData_.IndicesMulti(field, value); }

//template<typename T>
//inline IndexList
//PbiIndexPrivate::IndicesMulti(const BarcodeField& field,
//                              const T& value) const
//{ return barcodeData_.IndicesMulti(field, value); }

//template<typename T>
//inline IndexResultBlocks
//PbiIndexPrivate::Lookup(const SubreadField& field,
//                        const T& value,
//                        const CompareType& compareType) const
//{ return MergeBlocksWithOffsets(subreadData_.Indices(field, value, compareType)); }

//template<typename T>
//inline IndexResultBlocks
//PbiIndexPrivate::Lookup(const MappedField& field,
//                        const T& value,
//                        const CompareType& compareType) const
//{
//    if (!HasSection(PbiFile::MAPPED))
//        return IndexResultBlocks();
//    return MergeBlocksWithOffsets(mappedData_.Indices(field, value, compareType));
//}

//template<typename T>
//inline IndexResultBlocks
//PbiIndexPrivate::Lookup(const BarcodeField& field,
//                        const T& value,
//                        const CompareType& compareType) const
//{
//    if (!HasSection(PbiFile::BARCODE))
//        return IndexResultBlocks();
//    return MergeBlocksWithOffsets(barcodeData_.Indices(field, value, compareType));
//}

//template<typename T>
//inline IndexResultBlocks
//PbiIndexPrivate::LookupMulti(const SubreadField& field,
//                             const std::vector<T>& values) const
//{ return MergeBlocksWithOffsets(subreadData_.IndicesMulti(field, values)); }

//template<typename T>
//inline IndexResultBlocks
//PbiIndexPrivate::LookupMulti(const MappedField& field,
//                             const std::vector<T>& values) const
//{ return MergeBlocksWithOffsets(mappedData_.IndicesMulti(field, values)); }

//template<typename T>
//inline IndexResultBlocks
//PbiIndexPrivate::LookupMulti(const BarcodeField& field,
//                             const std::vector<T>& values) const
//{ return MergeBlocksWithOffsets(barcodeData_.IndicesMulti(field, values)); }

//inline IndexResultBlocks
//PbiIndexPrivate::LookupReference(const int32_t tId) const
//{
//    if (!HasSection(PbiFile::REFERENCE))
//        return IndexResultBlocks();
//    const IndexRange& indexRange = referenceData_.Indices(tId);
//    if (indexRange.first == nullIndex() && indexRange.second == nullIndex())
//        return IndexResultBlocks();
//    const size_t numReads = indexRange.second - indexRange.first;
//    IndexResultBlocks blocks(1, IndexResultBlock(indexRange.first, numReads));
//    subreadData_.ApplyOffsets(blocks);
//    return blocks;
//}

//inline IndexResultBlocks
//PbiIndexPrivate::MergeBlocksWithOffsets(const IndexList& indices) const
//{
//    IndexResultBlocks blocks = mergedIndexBlocks(indices);
//    subreadData_.ApplyOffsets(blocks);
//    return blocks;
//}

//} // namespace internal

//template<typename FieldType, typename ValueType>
//inline IndexRequestBase<FieldType, ValueType>::IndexRequestBase(const FieldType field,
//                                                                const ValueType& value,
//                                                                const CompareType compareType)
//    : field_(field)
//    , value_(value)
//    , compareType_(compareType)
//{ }

//template<typename FieldType, typename ValueType>
//inline IndexMultiRequestBase<FieldType, ValueType>::IndexMultiRequestBase(const FieldType field,
//                                                                          const std::vector<ValueType>& values)
//    : field_(field)
//    , values_(values)
//{ }

//template<SubreadField field, typename ValueType>
//inline SubreadIndexRequest<field, ValueType>::SubreadIndexRequest(const ValueType& value,
//                                                                  const CompareType& compareType)
//    : IndexRequestBase<SubreadField, ValueType>(field, value, compareType)
//{ }

//template<SubreadField field, typename ValueType>
//inline SubreadIndexMultiRequest<field, ValueType>::SubreadIndexMultiRequest(const std::vector<ValueType>& values)
//    : IndexMultiRequestBase<SubreadField, ValueType>(field, values)
//{ }

//template<MappedField field, typename ValueType>
//inline MappedIndexRequest<field, ValueType>::MappedIndexRequest(const ValueType& value,
//                                                                const CompareType& compareType)
//    : IndexRequestBase<MappedField, ValueType>(field, value, compareType)
//{ }

//template<MappedField field, typename ValueType>
//inline MappedIndexMultiRequest<field, ValueType>::MappedIndexMultiRequest(const std::vector<ValueType>& values)
//    : IndexMultiRequestBase<MappedField, ValueType>(field, values)
//{ }

//template<BarcodeField field, typename ValueType>
//inline BarcodeIndexRequest<field, ValueType>::BarcodeIndexRequest(const ValueType& value,
//                                                                  const CompareType& compareType)
//    : IndexRequestBase<BarcodeField, ValueType>(field, value, compareType)
//{ }

//template<BarcodeField field, typename ValueType>
//inline BarcodeIndexMultiRequest<field, ValueType>::BarcodeIndexMultiRequest(const std::vector<ValueType>& values)
//    : IndexMultiRequestBase<BarcodeField, ValueType>(field, values)
//{ }

//template <typename FieldType, typename ValueType>
//inline IndexList
//PbiIndex::RawIndices(const IndexRequestBase<FieldType, ValueType>& request) const
//{ return d_->Indices(request.field_, request.value_, request.compareType_); }

//template <typename FieldType, typename ValueType>
//inline IndexList
//PbiIndex::RawIndices(const IndexMultiRequestBase<FieldType, ValueType>& request) const
//{ return d_->Indices(request.field_, request.values_); }

//template <typename FieldType, typename ValueType>
//inline IndexResultBlocks
//PbiIndex::Lookup(const IndexRequestBase<FieldType, ValueType>& request) const
//{ return d_->Lookup(request.field_, request.value_, request.compareType_); }

//template <typename FieldType, typename ValueType>
//inline IndexResultBlocks
//PbiIndex::Lookup(const IndexMultiRequestBase<FieldType, ValueType>& request) const
//{ return d_->LookupMulti(request.field_, request.values_); }

//inline IndexResultBlocks PbiIndex::LookupReference(const int32_t tId) const
//{ return d_->LookupReference(tId); }

//} // namespace BAM
//} // namespace PacBio

//#endif // PACBIOINDEX_P_H
