// SPDX-License-Identifier: GPL-3.0-or-later

#include "../libnetdata.h"

#ifndef NETDATA_ADAPTIVE_RESORTABLE_LIST_H
#define NETDATA_ADAPTIVE_RESORTABLE_LIST_H 1

#define ARL_ENTRY_FLAG_FOUND    0x01    // the entry has been found in the source data
#define ARL_ENTRY_FLAG_EXPECTED 0x02    // the entry is expected by the program
#define ARL_ENTRY_FLAG_DYNAMIC  0x04    // the entry was dynamically allocated, from source data

typedef struct arl_entry {
    char *name;             // the keywords
    uint32_t hash;          // the hash of the keyword

    void *dst;              // the dst to pass to the processor

    uint8_t flags;          // ARL_ENTRY_FLAG_*

    // the processor to do the job
    void (*processor)(const char *name, uint32_t hash, const char *value, void *dst);

    // double linked list for fast re-linkings
    struct arl_entry *prev, *next;
} ARL_ENTRY;

typedef struct arl_base {
    char *name;

    size_t iteration;   // incremented on each iteration (arl_begin())
    size_t found;       // the number of expected keywords found in this iteration
    size_t expected;    // the number of expected keywords
    size_t wanted;      // the number of wanted keywords
                        // i.e. the number of keywords found and expected

    size_t relinkings;  // the number of relinkings we have made so far

    size_t allocated;   // the number of keywords allocated
    size_t fred;        // the number of keywords cleaned up

    size_t rechecks;    // the number of iterations between re-checks of the
                        // wanted number of keywords
                        // this is only needed in cases where the source
                        // is having less lines over time.

    size_t added;       // it is non-zero if new keywords have been added
                        // this is only needed to detect new lines have
                        // been added to the file, over time.

#ifdef NETDATA_INTERNAL_CHECKS
    size_t fast;        // the number of times we have taken the fast path
    size_t slow;        // the number of times we have taken the slow path
#endif

    // the processor to do the job
    void (*processor)(const char *name, uint32_t hash, const char *value, void *dst);

    // the linked list of the keywords
    ARL_ENTRY *head;

    // since we keep the list of keywords sorted (as found in the source data)
    // this is next keyword that we expect to find in the source data.
    ARL_ENTRY *next_keyword;
} ARL_BASE;

// create a new ARL
ARL_BASE *arl_create(const char *name, void (*processor)(const char *, uint32_t, const char *, void *), size_t rechecks);

// free an ARL
void arl_free(ARL_BASE *arl_base);

// register an expected keyword to the ARL
// together with its destination ( i.e. the output of the processor() )
ARL_ENTRY *arl_expect_custom(ARL_BASE *base, const char *keyword, void (*processor)(const char *name, uint32_t hash, const char *value, void *dst), void *dst);
#define arl_expect(base, keyword, dst) arl_expect_custom(base, keyword, NULL, dst)

// an internal call to complete the check() call
int arl_find_or_create_and_relink(ARL_BASE *base, const char *s, const char *value);

// begin an ARL iteration
void arl_begin(ARL_BASE *base);

void arl_callback_str2ull(const char *name, uint32_t hash, const char *value, void *dst);
void arl_callback_str2kernel_uint_t(const char *name, uint32_t hash, const char *value, void *dst);
void arl_callback_ssize_t(const char *name, uint32_t hash, const char *value, void *dst);

int arl_check(ARL_BASE *base, const char *keyword, const char *value);

#endif //NETDATA_ADAPTIVE_RESORTABLE_LIST_H
