1/*
2 * Copyright (c) 2012, ETH Zurich.
3 * All rights reserved.
4 *
5 * This file is distributed under the terms in the attached LICENSE file.
6 * If you do not find this file, copies can be found by writing to:
7 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
8 */
9
10#include <collections/flipbuffer.h>
11
12#include <assert.h>
13#include <stdlib.h>
14#include <string.h>
15
16/**
17 * \brief Append data to front buffer.
18 *
19 * \param fbuf   Flip buffer to append data to.
20 * \param data   Data to append. Don't have to be \0-terminated.
21 * \param length Length of data to append.
22 */
23void collections_fbuf_append(struct collections_fbuf *fbuf, const void *data,
24                             size_t length)
25{
26    if (data == NULL || length == 0) {
27        return;
28    }
29
30    if (fbuf->front == NULL) {
31        // allocate a new front buffer
32        fbuf->front = malloc(length);
33        assert(fbuf->front != NULL);
34        memcpy(fbuf->front, data, length);
35        fbuf->frontlen = length;
36    } else {
37        // append to existing buffer
38        fbuf->front = realloc(fbuf->front, fbuf->frontlen + length);
39        assert(fbuf->front != NULL);
40        memcpy(fbuf->front + fbuf->frontlen, data, length);
41        fbuf->frontlen += length;
42    }
43}
44
45/**
46 * \brief Create a new flip buffer.
47 *
48 * \param fbuf   Pointer to a pointer to a flip buffer. Filled-in by function.
49 */
50void collections_fbuf_create(struct collections_fbuf **fbuf)
51{
52    *fbuf = malloc(sizeof(struct collections_fbuf));
53    assert(*fbuf != NULL);
54
55    (*fbuf)->front = NULL;
56    (*fbuf)->frontlen = 0;
57    (*fbuf)->back = NULL;
58    (*fbuf)->backlen = 0;
59}
60
61/**
62 * \brief Flip the buffer, i.e. change the role of the front and back buffer.
63 *
64 * \param fbuf   Flip buffer to flip.
65 */
66void collections_fbuf_flip(struct collections_fbuf *fbuf)
67{
68    char *tmpbuf;
69    size_t tmplen;
70
71    tmpbuf = fbuf->front;
72    tmplen = fbuf->frontlen;
73
74    fbuf->front = fbuf->back;
75    fbuf->frontlen = fbuf->backlen;
76
77    fbuf->back = tmpbuf;
78    fbuf->backlen = tmplen;
79}
80
81/**
82 * \brief Empty the front buffer
83 *
84 * \param fbuf   Flip buffer to operate on.
85 */
86void collections_fbuf_free(struct collections_fbuf *fbuf)
87{
88    if (fbuf->front != NULL) {
89        free(fbuf->front);
90        fbuf->front = NULL;
91    }
92    fbuf->frontlen = 0;
93}
94
95/**
96 * \brief Retrieve the data from the front buffer.
97 *
98 * \param fbuf   Flip buffer to get data from.
99 * \return       Content of the front buffer. Not \0 terminated.
100 */
101void *collections_fbuf_get_data(struct collections_fbuf *fbuf)
102{
103    return fbuf->front;
104}
105
106/**
107 * \brief Retrieve the length of the data of the front buffer.
108 *
109 * \param fbuf   Flip buffer to get length of data from.
110 * \return       Length of the data in the front buffer.
111 */
112size_t collections_fbuf_get_length(struct collections_fbuf *fbuf)
113{
114    return fbuf->frontlen;
115}
116
117/**
118 * \brief Is the front buffer empty?
119 *
120 * \param fbuf   Flip buffer to check.
121 * \return       Whether or not the front buffer contains any data?
122 */
123bool collections_fbuf_is_empty(struct collections_fbuf *fbuf)
124{
125    if (fbuf->front == NULL || fbuf->frontlen == 0) {
126        return true;
127    } else {
128        return false;
129    }
130}
131
132/**
133 * \brief Is the back buffer empty?
134 *
135 * \param fbuf   Flip buffer to check.
136 * \return       Whether or not the back buffer contains any data?
137 */
138bool collections_fbuf_other_is_empty(struct collections_fbuf *fbuf)
139{
140    if (fbuf->back == NULL || fbuf->backlen == 0) {
141        return true;
142    } else {
143        return false;
144    }
145}
146
147
148/**
149 * \brief Empty the back buffer
150 *
151 * \param fbuf   Flip buffer to operate on.
152 */
153void collections_fbuf_other_free(struct collections_fbuf *fbuf)
154{
155    if (fbuf->back != NULL) {
156        free(fbuf->back);
157        fbuf->back = NULL;
158    }
159    fbuf->backlen = 0;
160}
161
162/**
163 * \brief Free all memory associated with the flip buffer.
164 */
165void collections_fbuf_release(struct collections_fbuf *fbuf)
166{
167    if (fbuf == NULL) {
168        return;
169    }
170
171    collections_fbuf_free(fbuf);
172    collections_fbuf_other_free(fbuf);
173
174    free(fbuf);
175}
176