// IWYU pragma: private; include "rlang.h"

#ifndef RLANG_DYN_LIST_OF_H
#define RLANG_DYN_LIST_OF_H

#include "rlang-types.h"
#include "dyn-array.h"

struct r_dyn_list_of {
    r_obj* shelter;
    r_ssize count;
    r_ssize capacity;
    int growth_factor;

    // Contains the addresses and sizes of each element of the
    // list-of. If you copy that pointer, consider it invalid after a
    // push because it might have moved in memory due to a resize.
    struct r_pair_ptr_ssize* v_data;

    // private:
    r_ssize width;
    enum r_type type;
    r_ssize elt_byte_size;

    r_obj* reserve;
    void* v_reserve;

    struct r_dyn_array* p_moved_arr;
    struct r_dyn_array* p_moved_shelter_arr;

    r_obj* arr_locs;
    r_ssize* v_arr_locs;

    struct r_dyn_array* p_arrays;
};

struct r_dyn_list_of* r_new_dyn_list_of(
    enum r_type type,
    r_ssize capacity,
    r_ssize width
);

r_obj* r_lof_unwrap(struct r_dyn_list_of* p_lof);

void r_lof_push_back(struct r_dyn_list_of* p_lof);

void r_lof_arr_push_back(struct r_dyn_list_of* p_lof, r_ssize i, void* p_elt);

static inline void* r_lof_arr_ptr(
    struct r_dyn_list_of* p_lof,
    r_ssize i,
    r_ssize j
) {
    r_ssize offset = j * p_lof->elt_byte_size;
    struct r_pair_ptr_ssize* v_arrays =
        (struct r_pair_ptr_ssize*) r_dyn_pointer(p_lof->p_arrays, i);
    return ((unsigned char*) v_arrays->ptr) + offset;
}
static inline void* r_lof_arr_ptr_front(
    struct r_dyn_list_of* p_lof,
    r_ssize i
) {
    return r_lof_arr_ptr(p_lof, i, 0);
}
static inline void* r_lof_arr_ptr_back(struct r_dyn_list_of* p_lof, r_ssize i) {
    return r_lof_arr_ptr(p_lof, i, p_lof->count - 1);
}

#endif
