<commit_before>#ifndef _LOCK_FREE_RUNG_BUFFER_H_
#define _LOCK_FREE_RUNG_BUFFER_H_

/*
    Author: <NAME>
    Email: <EMAIL>
    Website: https://github.com/brianwatling
*/

#include <assert.h>
#include <stdint.h>
#include <stddef.h>
#include <malloc.h>

#include "machine_specific.h"

typedef struct lockfree_ring_buffer
{
    //high and low are generally used together; no point putting them on separate cache lines
    volatile uint64_t high;
    char _cache_padding1[CACHE_SIZE - sizeof(uint64_t)];
    volatile uint64_t low;
    char _cache_padding2[CACHE_SIZE - sizeof(uint64_t)];
    size_t size;
    void* buffer[];
} lockfree_ring_buffer_t;

lockfree_ring_buffer_t* lockfree_ring_buffer_create(size_t size)
{
    assert(size);
    const size_t required_size = sizeof(lockfree_ring_buffer_t) + size * sizeof(void*);
    lockfree_ring_buffer_t* const ret = (lockfree_ring_buffer_t*)malloc(required_size);
    if(ret) {
        ret->high = 0;
        ret->low = 0;
        ret->size = size;
    }
    return ret;
}

void lockfree_ring_buffer_destroy(lockfree_ring_buffer_t* rb)
{
    free(rb);
}

void lockfree_ring_buffer_push(lockfree_ring_buffer_t* rb, void* in)
{
    assert(in);//can't store NULLs; we rely on a NULL to indicate a spot in the buffer has not been written yet

    while(1) {
        const uint64_t low = rb->low;
        load_load_barrier();//read low first; this means the buffer will appear larger or equal to its actual size
        const uint64_t high = rb->high;
        const uint64_t index = high % rb->size;
        if(!rb->buffer[index]
           && high - low <= rb->size
           && __sync_bool_compare_and_swap(&rb->high, high, high + 1)) {
            rb->buffer[index] = in;
            return;
        }
    }
}

void* lockfree_ring_buffer_pop(lockfree_ring_buffer_t* rb)
{
    while(1) {
        const uint64_t high = rb->high;
        load_load_barrier();//read high first; this means the buffer will appear smaller or equal to its actual size
        const uint64_t low = rb->low;
        const uint64_t index = low % rb->size;
        void* const ret = rb->buffer[index];
        if(ret
           && high > low
           && __sync_bool_compare_and_swap(&rb->low, low, low + 1)) {
            rb->buffer[index] = 0;
            return ret;
        }
    }
}

size_t lockfree_ring_buffer_size(const lockfree_ring_buffer_t* rb)
{
    const uint64_t high = rb->high;
    load_load_barrier();//read high first; make it look less than or equal to its actual size
    const ssize_t size = high - rb->low;
    return size >= 0 ? size : 0;
}

#endif
<commit_msg>add trypop for lock free ring buffer<commit_after>#ifndef _LOCK_FREE_RUNG_BUFFER_H_
#define _LOCK_FREE_RUNG_BUFFER_H_

/*
    Author: <NAME>
    Email: <EMAIL>
    Website: https://github.com/brianwatling
*/

#include <assert.h>
#include <stdint.h>
#include <stddef.h>
#include <malloc.h>

#include "machine_specific.h"

typedef struct lockfree_ring_buffer
{
    //high and low are generally used together; no point putting them on separate cache lines
    volatile uint64_t high;
    char _cache_padding1[CACHE_SIZE - sizeof(uint64_t)];
    volatile uint64_t low;
    char _cache_padding2[CACHE_SIZE - sizeof(uint64_t)];
    size_t size;
    void* buffer[];
} lockfree_ring_buffer_t;

static inline lockfree_ring_buffer_t* lockfree_ring_buffer_create(size_t size)
{
    assert(size);
    const size_t required_size = sizeof(lockfree_ring_buffer_t) + size * sizeof(void*);
    lockfree_ring_buffer_t* const ret = (lockfree_ring_buffer_t*)malloc(required_size);
    if(ret) {
        ret->high = 0;
        ret->low = 0;
        ret->size = size;
    }
    return ret;
}

static inline void lockfree_ring_buffer_destroy(lockfree_ring_buffer_t* rb)
{
    free(rb);
}

static inline void lockfree_ring_buffer_push(lockfree_ring_buffer_t* rb, void* in)
{
    assert(in);//can't store NULLs; we rely on a NULL to indicate a spot in the buffer has not been written yet

    while(1) {
        const uint64_t low = rb->low;
        load_load_barrier();//read low first; this means the buffer will appear larger or equal to its actual size
        const uint64_t high = rb->high;
        const uint64_t index = high % rb->size;
        if(!rb->buffer[index]
           && high - low <= rb->size
           && __sync_bool_compare_and_swap(&rb->high, high, high + 1)) {
            rb->buffer[index] = in;
            return;
        }
    }
}

static inline void* lockfree_ring_buffer_trypop(lockfree_ring_buffer_t* rb)
{
    const uint64_t high = rb->high;
    load_load_barrier();//read high first; this means the buffer will appear smaller or equal to its actual size
    const uint64_t low = rb->low;
    const uint64_t index = low % rb->size;
    void* const ret = rb->buffer[index];
    if(ret
       && high > low
       && __sync_bool_compare_and_swap(&rb->low, low, low + 1)) {
        rb->buffer[index] = 0;
        return ret;
    }
    return NULL;
}

static inline void* lockfree_ring_buffer_pop(lockfree_ring_buffer_t* rb)
{
    void* ret;
    while(!(ret = lockfree_ring_buffer_trypop(rb))) {};
    return ret;
}

static inline size_t lockfree_ring_buffer_size(const lockfree_ring_buffer_t* rb)
{
    const uint64_t high = rb->high;
    load_load_barrier();//read high first; make it look less than or equal to its actual size
    const ssize_t size = high - rb->low;
    return size >= 0 ? size : 0;
}

#endif

{'fraction_non_alphanumeric': 0.10348644161593802, 'fraction_numerical': 0.011990407673860911, 'mean_word_length': 3.0828313253012047, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 55, 'https://': 2, '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': '219765', 'n_tokens_mistral': 1870, 'n_tokens_neox': 1818, 'n_words': 486}