summaryrefslogtreecommitdiff
path: root/inc/sbuf.h
blob: 96775c835e8bc62309020f36ebb443abf13e722c (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
173
174
175
/**
 * Copyright (c) 2019, The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *    * Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *    * Redistributions in binary form must reproduce the above
 *      copyright notice, this list of conditions and the following
 *      disclaimer in the documentation and/or other materials provided
 *      with the distribution.
 *    * Neither the name of The Linux Foundation nor the names of its
 *      contributors may be used to endorse or promote products derived
 *      from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef SBUF_H
#define SBUF_H

#include <string.h>
#include <stdint.h>
#include "AEEstd.h"

/**
 * lightweight serialize/deserialize buffer.

   For example

   struct sbuf;
   //initialize empty buffer;
   sbuf_init(&sbuf, 0, 0, 0);

   //fill it with data
   sbuf_align(&sbuf, 8);
   sbuf_write(&sbuf, ptr1, 10);
   sbuf_align(&sbuf, 8);
   sbuf_write(&sbuf, ptr2, 20);

   //allocate the memory needed
   mem = malloc(sbuf_needed(&sbuf));

   //initialize with the data
   sbuf_init(&sbuf, 0, mem, sbuf_needed(&sbuf));

   //fill it with data, since it has memory, it will actually copy
   sbuf_align(&sbuf, 8);
   sbuf_write(&sbuf, ptr1, 10);
   sbuf_align(&sbuf, 8);
   sbuf_write(&sbuf, ptr2, 20);

   See sbuf_q.c for more examples
 */


struct sbuf {
   uintptr_t buf;      //! start of valid memory
   uintptr_t bufEnd;   //! end of valid memory
   uintptr_t bufStart; //! start with optinal offset from valid mem
   uintptr_t bufCur;   //! current position, could be outside of valid range
};

/**
 * @param buf, the buffer structure instance
 * @param offset, this value indicates how far ahead the data buffer is
 *                start = data - offset
 * @param data, the valid memory
 * @param dataLen, the length ov valid memory
 */
static __inline void sbuf_init(struct sbuf* buf, int offset, void* data, int dataLen) {
   buf->buf = (uintptr_t)data;
   buf->bufStart = buf->bufCur = (uintptr_t)data - offset;
   buf->bufEnd = (uintptr_t)data + dataLen;
}

//! move the current pointer by len
static __inline void sbuf_advance(struct sbuf* buf, int len) {
   buf->bufCur += len;
}

/**
 * @retval, the amount of memory needed for everything from the start (with the offset)
 * to the current position of the buffer
 */
static __inline int sbuf_needed(struct sbuf* buf) {
   return buf->bufCur - buf->bufStart;
}
/**
 * @retval, the space left in the buffer. A negative value indicates overflow.
 *          A positive value includes the offset.
 */
static __inline int sbuf_left(struct sbuf* buf) {
   return buf->bufEnd - buf->bufCur;
}

//! @retval the current head pointer
static __inline void* sbuf_head(struct sbuf* buf) {
   return (void*)buf->bufCur;
}

//! @retval true if the current pointer is valid
static __inline int sbuf_valid(struct sbuf* buf) {
   return buf->bufCur >= buf->buf && buf->bufCur < buf->bufEnd;
}

//! advance the head pointer so the "needed" is aligned to the align value
#define _SBUF_ALIGN(x, y) (((x) + ((y)-1)) & ~((y)-1))
static __inline void sbuf_align(struct sbuf* buf, uint32_t align) {
   sbuf_advance(buf, _SBUF_ALIGN(sbuf_needed(buf), align) - sbuf_needed(buf));
}

/**
 * Write to the buffer.
 * @param src, the memory to read from.  Will write srcLen bytes to buf from src
 *             from the buf's current position.  Only the valid portion of data will
 *             be written.
 * @param srcLen, the length of src.  The buffer will be advanced by srcLen.
 */
static __inline void sbuf_write(struct sbuf* buf, void *psrc, int srcLen) {
   uintptr_t src = (uintptr_t)psrc;
   if(buf->bufCur + srcLen > buf->buf) {
      int writeLen;
      if(buf->bufCur < buf->buf) {
         int len = buf->buf - buf->bufCur;
         srcLen -= len;
         src += len;
         sbuf_advance(buf, len);
      }
      writeLen = STD_MIN(srcLen, sbuf_left(buf));
      if(writeLen > 0) {
         std_memsmove((void*)buf->bufCur, buf->bufEnd - buf->bufCur, (void*)src, writeLen);
      }
   }
   sbuf_advance(buf, srcLen);
}

/**
 * Read from the buffer into dst.
 * @param dst, the data to write to. Will write dstLen to dst from buf
 *             from the current position of buf.  Only valid memory
 *             will be written to dst.  Invalid overlapping memory will
 *             remain untouched.
 * @param dstLen, the length of dst.  buf will be advanced by dstLen
 */
static __inline void sbuf_read(struct sbuf* buf, void *pdst, int dstLen) {
   uintptr_t dst = (uintptr_t)pdst;
   if(buf->bufCur + dstLen > buf->buf) {
      int readLen;
      if(buf->bufCur < buf->buf) {
         int len = buf->buf - buf->bufCur;
         dstLen -= len;
         dst += len;
         sbuf_advance(buf, len);
      }
      readLen = STD_MIN(dstLen, sbuf_left(buf));
      if(readLen > 0) {
         std_memsmove((void*)dst, dstLen, (void*)buf->bufCur, readLen);
      }
   }
   sbuf_advance(buf, dstLen);
}

#endif