summaryrefslogtreecommitdiff
path: root/src/kitringbuffer.c
blob: 1711d521d6baaad78b578f1286e2925a21bab36f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/*
 * Ringbuffer
 *
 * Copyright (c) 2016, Tuomas Virtanen
 * license: MIT; see LICENSE for details.
*/

#include "kitchensink/internal/kitringbuffer.h"

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>

/**
  * Creates a new ringbuffer with the given size.
  * @param size Size for the new ringbuffer
  * @return Ringbuffer handle
  */
Kit_RingBuffer* Kit_CreateRingBuffer(unsigned int size) {
    Kit_RingBuffer *rb = calloc(1, sizeof(Kit_RingBuffer));
    if(rb == NULL) return NULL;
    rb->size = size;
    rb->data = malloc(size);
    if(rb->data == NULL) {
        free(rb);
        return NULL;
    }
    return rb;
}

/**
  * Deletes the given ringbuffer.
  * @param rb Ringbuffer to be deleted.
  */
void Kit_DestroyRingBuffer(Kit_RingBuffer* rb) {
    if(rb == NULL) return;
    free(rb->data);
    free(rb);
}

/**
  * Writes to the given ringbuffer. If given length is larger than the amount
  * the ringbuffer can fit, only the data that fits will be written.
  * @param rb Ringbuffer to write to.
  * @param data Data to write
  * @param len Data length
  * @return Amount of data that was actually written.
  */
int Kit_WriteRingBuffer(Kit_RingBuffer *rb, const char* data, int len) {
    int k;
    len = (len > (rb->size - rb->len)) ? (rb->size - rb->len) : len;
    if(rb->len < rb->size) {
        if(len + rb->wpos > rb->size) {
            k = (len + rb->wpos) % rb->size;
            memcpy((rb->data + rb->wpos), data, len - k);
            memcpy(rb->data, data+(len-k), k);
        } else {
            memcpy((rb->data + rb->wpos), data, len);
        }
        rb->len += len;
        rb->wpos += len;
        if(rb->wpos >= rb->size) {
            rb->wpos = rb->wpos % rb->size;
        }
        return len;
    }
    return 0;
}

/**
  * Reads data from ringbuffer. If ringbuffer has less data than was requested,
  * only the available data will be read.
  * @param rb Ringbuffer to read from.
  * @param data Buffer to read into.
  * @param len How much data do we want
  * @return Amount of data that was actually read.
  */
int Kit_ReadRingBuffer(Kit_RingBuffer *rb, char* data, int len) {
    int k;
    len = (len > rb->len) ? rb->len : len;
    if(rb->len > 0) {
        if(len + rb->rpos > rb->size) {
            k = (len + rb->rpos) % rb->size;
            memcpy(data, (rb->data + rb->rpos), len-k);
            memcpy(data+(len-k), (rb->data), k);
        } else {
            memcpy(data, (rb->data + rb->rpos), len);
        }
        rb->len -= len;
        rb->rpos += len;
        if(rb->rpos >= rb->size) {
            rb->rpos = rb->rpos % rb->size;
        }
        return len;
    }
    return 0;
}

/**
  * Peeks into the given ringbuffer. Technically same as rb_read, but does not advance
  * the internal position pointer. In other words, you may peek as many times as you wish,
  * and will always get the same data.
  * @param rb Ringbuffer to peek into.
  * @param data Buffer to read into
  * @param len How much data do we need
  * @return Amount of data actually read
  */
int Kit_PeekRingBuffer(const Kit_RingBuffer *rb, char* data, int len) {
    int k;
    len = (len > rb->len) ? rb->len : len;
    if(rb->len > 0) {
        if(len + rb->rpos > rb->size) {
            k = (len + rb->rpos) % rb->size;
            memcpy(data, (rb->data + rb->rpos), len-k);
            memcpy(data+(len-k), (rb->data), k);
        } else {
            memcpy(data, (rb->data + rb->rpos), len);
        }
        return len;
    }
    return 0;
}

/**
  * Advances the internal position counter by given amount. Note that counter can only be
  * advanced by the amount of unreadable data in ringbuffer.
  * @param rb Ringbuffer to handle
  * @param len How much should the position counter be increased
  * @return How much the position counter was actually increased.
  */
int Kit_AdvanceRingBuffer(Kit_RingBuffer *rb, int len) {
    len = (len > rb->len) ? rb->len : len;
    if(rb->len > 0) {
        rb->len -= len;
        rb->rpos += len;
        if(rb->rpos >= rb->size) {
            rb->rpos = rb->rpos % rb->size;
        }
        return len;
    }
    return 0;
}

/**
  * Returns the current length of the Ringbuffer. In other words, how much data
  * the ringbuffer contains
  * @param rb Ringbuffer to handle
  * @return Data in ringbuffer (in bytes).
  */
int Kit_GetRingBufferLength(const Kit_RingBuffer *rb) {
    return rb->len;
}

/**
  * Returns the size of the ringbuffer. In other words, the maximum amount of data
  * the ringbuffer can hold.
  * @param rb Ringbuffer to handle
  * @return Size of the ringbuffer
  */
int Kit_GetRingBufferSize(const Kit_RingBuffer *rb) {
    return rb->size;
}

/**
  * Returns the free size of the ringbuffer.
  * @param rb Ringbuffer to handle
  * @return Free size in the ringbuffer
  */
int Kit_GetRingBufferFree(const Kit_RingBuffer *rb) {
    return rb->size - rb->len;
}