Skip to content

Instantly share code, notes, and snippets.

@hosackm
Last active August 8, 2019 01:56
Show Gist options
  • Save hosackm/cb3ad68f9275764b9b7a0a9398fbf801 to your computer and use it in GitHub Desktop.
Save hosackm/cb3ad68f9275764b9b7a0a9398fbf801 to your computer and use it in GitHub Desktop.
Dumb ringbuffer
CC=clang
CXX=clang++
SOURCES=ringbuffer.c
INCLUDES=-I.
test:test.cpp $(SOURCES)
$(CXX) -std=c++11 -o runtests $(INCLUDES) `pkg-config --cflags --libs gtest` $^
./runtests
#include "ringbuffer.h"
#include <string.h>
ringbuffer ringbuffer_create(size_t max_buffer_size)
{
if(max_buffer_size == 0)
{
return NULL;
}
else
{
ringbuffer r;
const size_t buffer_size = max_buffer_size * 2;
r = (ringbuffer) malloc(sizeof(ringbuffer_s));
r->read = r->write = r->buffer = (char *) malloc(max_buffer_size * 2);
r->max_buffer_size = buffer_size;
return r;
}
}
ringbuffer_result ringbuffer_get_size(ringbuffer r, size_t *size)
{
size_t diff;
if(r == NULL || size == NULL)
{
return ringbuffer_result_bad_pointer;
}
if(r->read > r->write)
{
return ringbuffer_result_underflow;
}
*size = r->write - r->read;
return ringbuffer_result_ok;
}
ringbuffer_result ringbuffer_write(ringbuffer r, char const *bytes, size_t n)
{
if(r == NULL || bytes == NULL)
{
return ringbuffer_result_bad_pointer;
}
if(r->write + n > r->buffer + r->max_buffer_size)
{
return ringbuffer_result_overflow;
}
// copy the bytes
memcpy(r->write, bytes, n);
r->write += n;
return ringbuffer_result_ok;
}
ringbuffer_result ringbuffer_read(ringbuffer r, size_t n, char *output)
{
if(r == NULL || output == NULL)
{
return ringbuffer_result_bad_pointer;
}
if(r->read + n > r->write)
{
return ringbuffer_result_underflow;
}
// copy the bytes
memcpy(output, r->read, n);
r->read += n;
return ringbuffer_result_ok;
}
#ifndef _RINGBUFFER_H_
#define _RINGBUFFER_H_
#include <stdlib.h>
#ifdef _cplusplus
extern "C" {
#endif
typedef enum
{
ringbuffer_result_ok = 0,
ringbuffer_result_overflow = 1,
ringbuffer_result_underflow = 2,
ringbuffer_result_bad_pointer = 3
} ringbuffer_result;
typedef struct
{
char *buffer;
size_t max_buffer_size;
char *read;
char *write;
} ringbuffer_s;
typedef ringbuffer_s *ringbuffer;
ringbuffer ringbuffer_create(size_t max_buffer_size);
ringbuffer_result ringbuffer_destroy(ringbuffer r);
ringbuffer_result ringbuffer_get_size(ringbuffer r, size_t *sz);
ringbuffer_result ringbuffer_write(ringbuffer r, char const * bytes, size_t n);
ringbuffer_result ringbuffer_read(ringbuffer r, size_t n, char *output);
#ifdef _cplusplus
}
#endif
#endif // _RINGBUFFER_H_
#include "gtest/gtest.h"
#include "ringbuffer.h"
TEST(RingbufferTests, CreateWithZeroReturnsNull)
{
EXPECT_EQ(ringbuffer_create(0), nullptr);
}
TEST(RingbufferTests, CreateReturnsNonNull)
{
EXPECT_NE(ringbuffer_create(10), nullptr);
}
TEST(RingbufferTests, NullPointersRejected)
{
ringbuffer_result res;
size_t size;
const size_t nbytes = 16;
char bytes[nbytes];
ringbuffer r = ringbuffer_create(10);
EXPECT_EQ(ringbuffer_get_size(NULL, NULL), ringbuffer_result_bad_pointer);
EXPECT_EQ(ringbuffer_get_size(NULL, &size), ringbuffer_result_bad_pointer);
EXPECT_EQ(ringbuffer_get_size(r, NULL), ringbuffer_result_bad_pointer);
EXPECT_EQ(ringbuffer_get_size(NULL, NULL), ringbuffer_result_bad_pointer);
EXPECT_EQ(ringbuffer_write(NULL, bytes, nbytes), ringbuffer_result_bad_pointer);
EXPECT_EQ(ringbuffer_write(r, NULL, nbytes), ringbuffer_result_bad_pointer);
EXPECT_EQ(ringbuffer_write(NULL, NULL, nbytes), ringbuffer_result_bad_pointer);
EXPECT_EQ(ringbuffer_read(NULL, nbytes, bytes), ringbuffer_result_bad_pointer);
EXPECT_EQ(ringbuffer_read(r, nbytes, NULL), ringbuffer_result_bad_pointer);
}
TEST(RingbufferTests, CreateReturnsSizeZero)
{
ringbuffer r = ringbuffer_create(10);
size_t size;
const ringbuffer_result res = ringbuffer_get_size(r, &size);
EXPECT_EQ(res, ringbuffer_result_ok);
EXPECT_EQ(size, 0);
}
TEST(RingbufferTests, WriteIncreasesSize)
{
const size_t size = 16;
char bytes[size] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
ringbuffer r = ringbuffer_create(size);
ringbuffer_result res;
size_t new_size;
res = ringbuffer_write(r, bytes, size);
EXPECT_EQ(res, ringbuffer_result_ok);
res = ringbuffer_get_size(r, &new_size);
EXPECT_EQ(res, ringbuffer_result_ok);
EXPECT_EQ(new_size, size);
}
TEST(RingbufferTests, WriteGreaterThanSizeReturnsOverflowError)
{
const size_t size = 16;
char bytes[size] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
const size_t under_alloc_size = 16/2-1; // this will create a max_buffer_size of 14 which will overflow
ringbuffer r = ringbuffer_create(under_alloc_size);
ringbuffer_result res;
size_t new_size;
res = ringbuffer_write(r, bytes, size);
EXPECT_EQ(res, ringbuffer_result_overflow);
}
TEST(RingbufferTests, WriteOfTwiceTheAskedSizeReturnsNoError)
{
const size_t size = 16;
char bytes[size] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
const size_t exact_alloc_size = 16/2; // this will create a max_buffer_size of 14 which will overflow
ringbuffer r = ringbuffer_create(exact_alloc_size);
ringbuffer_result res;
size_t new_size;
res = ringbuffer_write(r, bytes, size);
EXPECT_EQ(res, ringbuffer_result_ok);
}
TEST(RingbufferTests, ReadOfLargerThanWhatsInBufferReturnsUnderflow)
{
ringbuffer_result res;
const size_t size = 16;
char bytes[size] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
char outputbytes[size+1];
ringbuffer r = ringbuffer_create(size);
EXPECT_EQ(ringbuffer_read(r, size, bytes), ringbuffer_result_underflow);
res = ringbuffer_write(r, bytes, size);
EXPECT_EQ(res, ringbuffer_result_ok);
EXPECT_EQ(ringbuffer_read(r, size+1, bytes), ringbuffer_result_underflow);
}
TEST(RingbufferTests, ReadReturnsLastWrittenBytes)
{
ringbuffer_result res;
const size_t size = 4;
char bytes[size] = {0, 1, 2, 3};
char returned[size];
ringbuffer r = ringbuffer_create(size);
ringbuffer_write(r, bytes, size);
ringbuffer_read(r, size, returned);
for(int i = 0; i < (int)size; ++i)
{
EXPECT_EQ(bytes[i], returned[i]);
}
}
int main(int argc, char **argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment