/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */


#pragma once

#include <faiss/invlists/InvertedLists.h>
#include <faiss/invlists/InvertedListsIOHook.h>
#include <faiss/utils/AlignedTable.h>
#include <faiss/index_io.h>

namespace faiss {

/** Inverted Lists that are organized by blocks.
 *
 * Different from the regular inverted lists, the codes are organized by blocks
 * of size block_size bytes that reprsent a set of n_per_block. Therefore, code
 * allocations are always rounded up to block_size bytes. The codes are also
 * aligned on 32-byte boundaries for use with SIMD.
 *
 * To avoid misinterpretations, the code_size is set to (size_t)(-1), even if
 * arguably the amount of memory consumed by code is block_size / n_per_block.
 *
 * The writing functions add_entries and update_entries operate on block-aligned
 * data.
 */
struct BlockInvertedLists: InvertedLists {

    size_t n_per_block;   // nb of vectors stored per block
    size_t block_size;    // nb bytes per block

    std::vector<AlignedTable<uint8_t>> codes;
    std::vector<std::vector<idx_t>> ids;


    BlockInvertedLists (
        size_t nlist, size_t vec_per_block,
        size_t block_size
    );

    BlockInvertedLists();

    size_t list_size(size_t list_no) const override;
    const uint8_t * get_codes (size_t list_no) const override;
    const idx_t * get_ids (size_t list_no) const override;

    // works only on empty BlockInvertedLists
    // the codes should be of size ceil(n_entry / n_per_block) * block_size
    // and padded with 0s
    size_t add_entries (
           size_t list_no, size_t n_entry,
           const idx_t* ids, const uint8_t *code) override;

    /// not implemented
    void update_entries (size_t list_no, size_t offset, size_t n_entry,
                         const idx_t *ids, const uint8_t *code) override;

    // also pads new data with 0s
    void resize (size_t list_no, size_t new_size) override;

    ~BlockInvertedLists () override;

};

struct BlockInvertedListsIOHook : InvertedListsIOHook {
    BlockInvertedListsIOHook();
    void write(const InvertedLists *ils, IOWriter *f) const override;
    InvertedLists * read(IOReader *f, int io_flags) const override;
};


} // namespace faiss
