Skip to content
Authors

File prod_weighted.c

File List > prod_weighted > src > prod_weighted.c

Go to the documentation of this file

#include "prod_weighted.h"
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <pdgl_defs.h>

/*************************************************************************************************/
/************************** Defines **************************************************************/
/*************************************************************************************************/

#define IMAX_BITS(m)    ((m) / ((m) % 255 + 1) / 255 % 255 * 8 + 7 - 86 / ((m) % 255 + 12))

#define RAND_MAX_WIDTH    IMAX_BITS(RAND_MAX)

/*************************************************************************************************/
/************************** Private Function Declarations ****************************************/
/*************************************************************************************************/

STATIC_INLINE uint64_t  prod_weighted_sum(prod_weighted_pair_t *pairs, size_t pairs_len);
STATIC_INLINE const char *prod_weighted_select(prod_weighted_pair_t *pairs, size_t pairs_len);
STATIC_INLINE uint64_t rand_uint64(void);

/*************************************************************************************************/
/************************** Local Variables ******************************************************/
/*************************************************************************************************/

/*************************************************************************************************/
/************************** Public Function Definitions ******************************************/
/*************************************************************************************************/

/* Docstring in header */
const char * prod_weighted_resolve(const void *config)
{
    const char *retval = NULL;

    if (NULL != config)
    {
        const prod_weighted_config_t *typed_cfg = (const prod_weighted_config_t *)config;

        if ((0 < typed_cfg->repl_len) && (NULL != typed_cfg->repl_list))
        {
            retval = prod_weighted_select(typed_cfg->repl_list, typed_cfg->repl_len);
        }
    }
    return retval;
}

/* Docstring in header */
const char * prod_weighted_terminate(const void *config)
{
    const char *retval = NULL;

    if (NULL != config)
    {
        const prod_weighted_config_t *typed_cfg = (const prod_weighted_config_t *)config;

        if ((0 < typed_cfg->term_len) && (NULL != typed_cfg->term_list))
        {
            retval = prod_weighted_select(typed_cfg->term_list, typed_cfg->term_len);
        }
    }
    return retval;
}

/*************************************************************************************************/
/************************** Private Function Definitions *****************************************/
/*************************************************************************************************/

STATIC_INLINE uint64_t prod_weighted_sum(prod_weighted_pair_t *pairs, size_t pairs_len)
{
    size_t   i;
    uint64_t retval = 0u;

    for (i = 0u; i < pairs_len; i++)
    {
        if (retval < (UINT64_MAX - pairs[i].weight))
        {
            retval += pairs[i].weight;
        }
        else
        {
            return 0u;
        }
    }
    return retval;
}

STATIC_INLINE const char *prod_weighted_select(prod_weighted_pair_t *pairs, size_t pairs_len)
{
    const char *retval = NULL;

    uint64_t sum = prod_weighted_sum(pairs, pairs_len);

    if (sum != 0)
    {
        size_t   i;
        uint64_t idx = rand_uint64();
        idx %= sum;

        uint64_t part_sum = 0;
        for (i = 0; i < pairs_len; i++)
        {
            part_sum += pairs[i].weight;
            if (idx < part_sum)
            {
                retval = pairs[i].string;
                break;
            }
        }
    }
    return retval;
}

STATIC_INLINE uint64_t rand_uint64(void)
{
    uint64_t retval = 0;
    size_t   i;

    for (i = 0; i < 64; i += RAND_MAX_WIDTH)
    {
        retval <<= RAND_MAX_WIDTH;
        retval  ^= (unsigned)rand();
    }
    return retval;
}