/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Copyright by The HDF Group.                                               *
 * All rights reserved.                                                      *
 *                                                                           *
 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
 * terms governing use, modification, and redistribution, is contained in    *
 * the LICENSE file, which can be found at the root of the source code       *
 * distribution tree, or in https://www.hdfgroup.org/licenses.               *
 * If you do not have access to either file, you may request a copy from     *
 * help@hdfgroup.org.                                                        *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#if !(defined H5SM_FRIEND || defined H5SM_MODULE)
#error "Do not include this file outside the H5SM package!"
#endif

#ifndef H5SMpkg_H
#define H5SMpkg_H

#include "H5SMprivate.h" 

#include "H5ACprivate.h" 
#include "H5B2private.h" 
#include "H5HFprivate.h" 
#include "H5FLprivate.h" 

#define H5SM_SIZEOF_CHECKSUM 4

#define H5SM_HEAP_LOC_SIZE                                                                                   \
    ((unsigned)4                                                                        \
     + sizeof(H5O_fheap_id_t)                                                   \
    )

#define H5SM_OH_LOC_SIZE(f)                                                                                  \
    ((unsigned)1                                                             \
     + (unsigned)1                                                                      \
     + (unsigned)2                                                      \
     + H5F_SIZEOF_ADDR(f)                                                                 \
    )

#define H5SM_SOHM_ENTRY_SIZE(f)                                                                              \
    ((unsigned)1                                                                       \
     + (unsigned)4                                                                           \
     + MAX(H5SM_HEAP_LOC_SIZE, H5SM_OH_LOC_SIZE(f))                                               \
    )

#define H5SM_INDEX_HEADER_SIZE(f)                                                                            \
    ((unsigned)1                                                      \
     + (unsigned)1                                                              \
     + (unsigned)2                                                 \
     + (unsigned)4                                                    \
     + (unsigned)(3 * 2)                               \
     + H5F_SIZEOF_ADDR(f)                                                    \
     + H5F_SIZEOF_ADDR(f)                                                               \
    )

#define H5SM_METADATA_PREFIX_SIZE                                                                            \
    (H5_SIZEOF_MAGIC                                                                          \
     + H5SM_SIZEOF_CHECKSUM                                                                    \
    )

#define H5SM_TABLE_SIZE(f)                                                                                   \
    (                                                                           \
     H5SM_METADATA_PREFIX_SIZE                                                                               \
                                                                                                             \
                                                                                                \
     + (H5F_SOHM_NINDEXES(f) * H5SM_INDEX_HEADER_SIZE(f)))

#define H5SM_LIST_SIZE(f, num_mesg)                                                                          \
    (                                                                           \
     H5SM_METADATA_PREFIX_SIZE                                                                               \
                                                                                                             \
                                                                                        \
     + (H5SM_SOHM_ENTRY_SIZE(f) * num_mesg))

#define H5SM_B2_NODE_SIZE     512
#define H5SM_B2_SPLIT_PERCENT 100
#define H5SM_B2_MERGE_PERCENT 40

#define H5SM_LIST_VERSION 0 

typedef enum {
    H5SM_NO_LOC  = -1,
    H5SM_IN_HEAP = 0, 
    H5SM_IN_OH        
} H5SM_storage_loc_t;

typedef struct {
    hsize_t        ref_count; 
    H5O_fheap_id_t fheap_id;  
} H5SM_heap_loc_t;

typedef struct {
    H5SM_storage_loc_t location;    
    uint32_t           hash;        
    unsigned           msg_type_id; 
    union {
        H5O_mesg_loc_t  mesg_loc; 
        H5SM_heap_loc_t heap_loc; 
    } u;
} H5SM_sohm_t;

typedef enum {
    H5SM_BADTYPE = -1,
    H5SM_LIST, 
    H5SM_BTREE 
} H5SM_index_type_t;

typedef struct {
    
    unsigned          mesg_types;    
    size_t            min_mesg_size; 
    size_t            list_max;      
    size_t            btree_min;     
    size_t            num_messages;  
    H5SM_index_type_t index_type;    
    haddr_t           index_addr;    
    haddr_t           heap_addr;     

    
    size_t list_size; 
} H5SM_index_header_t;

typedef struct {
    
    H5AC_info_t cache_info;

    H5SM_index_header_t *header;   
    H5SM_sohm_t         *messages; 
} H5SM_list_t;

struct H5SM_master_table_t {
    
    H5AC_info_t cache_info;

    size_t               table_size;  
    unsigned             num_indexes; 
    H5SM_index_header_t *indexes;     
};

typedef struct {
    H5F_t      *file;          
    H5HF_t     *fheap;         
    void       *encoding;      
    size_t      encoding_size; 
    H5SM_sohm_t message;       
} H5SM_mesg_key_t;

typedef struct H5SM_bt2_ctx_t {
    uint8_t sizeof_addr; 
} H5SM_bt2_ctx_t;

typedef struct H5SM_table_cache_ud_t {
    H5F_t *f; 
} H5SM_table_cache_ud_t;

typedef struct H5SM_list_cache_ud_t {
    H5F_t               *f;      
    H5SM_index_header_t *header; 
} H5SM_list_cache_ud_t;

H5FL_EXTERN(H5SM_master_table_t);
H5FL_ARR_EXTERN(H5SM_index_header_t);
H5FL_EXTERN(H5SM_list_t);
H5FL_ARR_EXTERN(H5SM_sohm_t);

H5_DLLVAR const H5B2_class_t H5SM_INDEX[1];

H5_DLL herr_t H5SM__get_index(const H5SM_master_table_t *table, unsigned type_id, ssize_t *idx);

H5_DLL herr_t H5SM__message_compare(const void *rec1, const void *rec2, int *result);
H5_DLL herr_t H5SM__message_encode(uint8_t *raw, const void *native, void *ctx);
H5_DLL herr_t H5SM__message_decode(const uint8_t *raw, void *native, void *ctx);

H5_DLL herr_t H5SM__table_free(H5SM_master_table_t *table);
H5_DLL herr_t H5SM__list_free(H5SM_list_t *list);

#ifdef H5SM_TESTING
H5_DLL herr_t H5SM__get_mesg_count_test(H5F_t *f, unsigned type_id, size_t *mesg_count);
#endif 

#endif 
