<commit_before>/*
 * Objects in stock.  May be used for connection pooling.
 *
 * author: <NAME> <<EMAIL>>
 */

#include "stock.h"
#include "async.h"

#include <assert.h>

struct stock {
    pool_t pool;
    const struct stock_class *class;
    void *class_ctx;
    const char *uri;

    unsigned num_idle;
    struct list_head idle;
};

struct stock *
stock_new(pool_t pool, const struct stock_class *class,
          void *class_ctx, const char *uri)
{
    struct stock *stock;

    assert(pool != NULL);
    assert(class != NULL);
    assert(class->item_size > sizeof(struct stock_item));
    assert(class->create != NULL);
    assert(class->validate != NULL);
    assert(class->destroy != NULL);

    pool = pool_new_linear(pool, "stock", 1024);
    stock = p_malloc(pool, sizeof(*stock));
    stock->pool = pool;
    stock->class = class;
    stock->class_ctx = class_ctx;
    stock->uri = uri == NULL ? NULL : p_strdup(pool, uri);
    stock->num_idle = 0;
    list_init(&stock->idle);

    return stock;
}

void
stock_free(struct stock **stock_r)
{
    struct stock *stock;

    assert(stock_r != NULL);
    assert(*stock_r != NULL);

    stock = *stock_r;
    *stock_r = NULL;

    while (stock->num_idle > 0) {
        struct stock_item *item = (struct stock_item *)stock->idle.next;

        assert(!list_empty(&stock->idle));

        list_remove(&item->list_head);
        --stock->num_idle;

        stock->class->destroy(stock->class_ctx, item);

        if (item->pool != stock->pool)
            pool_unref(item->pool);
    }

    pool_unref(stock->pool);
}

static void
destroy_item(struct stock *stock, struct stock_item *item)
{
    assert(pool_contains(item->pool, item, stock->class->item_size));

    stock->class->destroy(stock->class_ctx, item);

    if (item->pool == stock->pool)
        p_free(stock->pool, item);
    else
        pool_unref(item->pool);
}

void
stock_get(struct stock *stock, stock_callback_t callback, void *callback_ctx,
          struct async_operation_ref *async_ref)
{
    pool_t pool;
    struct stock_item *item;

    assert(stock != NULL);
    assert(!async_ref_defined(async_ref));

    while (stock->num_idle > 0) {
        assert(!list_empty(&stock->idle));

        item = (struct stock_item *)stock->idle.next;
        list_remove(&item->list_head);
        --stock->num_idle;

        assert(item->is_idle);

        if (stock->class->validate(stock->class_ctx, item)) {
            item->is_idle = 0;
            callback(callback_ctx, item);
            return;
        }

        destroy_item(stock, item);
    }

    if (stock->class->pool == NULL)
        pool = stock->pool;
    else
        pool = stock->class->pool(stock->class_ctx, stock->pool, stock->uri);

    item = p_malloc(pool, stock->class->item_size);
    item->stock = stock;
    item->pool = pool;
    item->is_idle = 0;<commit_msg>allow async_ref==NULL if the stock class supports it<commit_after>/*
 * Objects in stock.  May be used for connection pooling.
 *
 * author: <NAME> <<EMAIL>>
 */

#include "stock.h"
#include "async.h"

#include <assert.h>

struct stock {
    pool_t pool;
    const struct stock_class *class;
    void *class_ctx;
    const char *uri;

    unsigned num_idle;
    struct list_head idle;
};

struct stock *
stock_new(pool_t pool, const struct stock_class *class,
          void *class_ctx, const char *uri)
{
    struct stock *stock;

    assert(pool != NULL);
    assert(class != NULL);
    assert(class->item_size > sizeof(struct stock_item));
    assert(class->create != NULL);
    assert(class->validate != NULL);
    assert(class->destroy != NULL);

    pool = pool_new_linear(pool, "stock", 1024);
    stock = p_malloc(pool, sizeof(*stock));
    stock->pool = pool;
    stock->class = class;
    stock->class_ctx = class_ctx;
    stock->uri = uri == NULL ? NULL : p_strdup(pool, uri);
    stock->num_idle = 0;
    list_init(&stock->idle);

    return stock;
}

void
stock_free(struct stock **stock_r)
{
    struct stock *stock;

    assert(stock_r != NULL);
    assert(*stock_r != NULL);

    stock = *stock_r;
    *stock_r = NULL;

    while (stock->num_idle > 0) {
        struct stock_item *item = (struct stock_item *)stock->idle.next;

        assert(!list_empty(&stock->idle));

        list_remove(&item->list_head);
        --stock->num_idle;

        stock->class->destroy(stock->class_ctx, item);

        if (item->pool != stock->pool)
            pool_unref(item->pool);
    }

    pool_unref(stock->pool);
}

static void
destroy_item(struct stock *stock, struct stock_item *item)
{
    assert(pool_contains(item->pool, item, stock->class->item_size));

    stock->class->destroy(stock->class_ctx, item);

    if (item->pool == stock->pool)
        p_free(stock->pool, item);
    else
        pool_unref(item->pool);
}

void
stock_get(struct stock *stock, stock_callback_t callback, void *callback_ctx,
          struct async_operation_ref *async_ref)
{
    pool_t pool;
    struct stock_item *item;

    assert(stock != NULL);
    assert(async_ref == NULL || !async_ref_defined(async_ref));

    while (stock->num_idle > 0) {
        assert(!list_empty(&stock->idle));

        item = (struct stock_item *)stock->idle.next;
        list_remove(&item->list_head);
        --stock->num_idle;

        assert(item->is_idle);

        if (stock->class->validate(stock->class_ctx, item)) {
            item->is_idle = 0;
            callback(callback_ctx, item);
            return;
        }

        destroy_item(stock, item);
    }

    if (stock->class->pool == NULL)
        pool = stock->pool;
    else
        pool = stock->class->pool(stock->class_ctx, stock->pool, stock->uri);

    item = p_malloc(pool, stock->class->item_size);
    item->stock = stock;
    item->pool = pool;
    item->is_idle = 0;
{'fraction_non_alphanumeric': 0.14666205465236942, 'fraction_numerical': 0.003113109650639917, 'mean_word_length': 2.799605781865966, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 127, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '593789', 'n_tokens_mistral': 1923, 'n_tokens_neox': 1883, 'n_words': 414}