Version 7.0
Copyright © 2021 Lowell D. Thomas
APG
… an ABNF Parser Generator
vector.c
Go to the documentation of this file.
1 /* *************************************************************************************
2  Copyright (c) 2021, Lowell D. Thomas
3  All rights reserved.
4 
5  This file is part of APG Version 7.0.
6  APG Version 7.0 may be used under the terms of the BSD 2-Clause License.
7 
8  Redistribution and use in source and binary forms, with or without
9  modification, are permitted provided that the following conditions are met:
10 
11  1. Redistributions of source code must retain the above copyright notice, this
12  list of conditions and the following disclaimer.
13 
14  2. Redistributions in binary form must reproduce the above copyright notice,
15  this list of conditions and the following disclaimer in the documentation
16  and/or other materials provided with the distribution.
17 
18  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 
29 * *************************************************************************************/
30 #include "./lib.h"
31 
43 static const void* s_vpMagicNumber = (void*)"vector";
44 
45 #if defined APG_VEC_STATS
46 
52 typedef struct {
53  const void* vpValidate;
55  void* vpMem;
56  char* cpData;
65 } vector;
66 static void vStatsPush(vector* spCtx, aint uiPushed);
67 static void vStatsPop(vector* spCtx, aint uiPopped);
68 static void vStatsGrow(vector* spCtx, aint uiAddedElements);
73 
77 #define STATS_PUSH(s, p) vStatsPush((s), (p))
78 
81 #define STATS_POP(s, p) vStatsPop((s), (p))
82 
85 #define STATS_GROW(s, n) vStatsGrow((s), (n))
86 #else
88 typedef struct {
89  const void* vpValidate; // must be equal to s_vpMagicNumber
90  exception* spException;
91  void* vpMem; // context to the underlying memory component
92  char* cpData; // pointer to the vector's data buffer
93  aint uiElementSize; // number of bytes in one element
94  aint uiReserved; // number of elements that have been reserved on the buffer
95  aint uiUsed; // number of the reserved elements that have been used
96 } vector;
97 #define STATS_PUSH(s, p)
98 #define STATS_POP(s, p)
99 #define STATS_GROW(s, n)
100 #endif
101 
102 static void vGrow(vector* spCtx, aint uiElements);
103 
118 void* vpVecCtor(void* vpMem, aint uiElementSize, aint uiInitialAlloc) {
119  vector* spCtx;
120  exception* spEx = NULL;
121  while(APG_TRUE){
122  if (!bMemValidate(vpMem)) {
123  vExContext();
124  break;
125  }
126  spEx = spMemException(vpMem);
127  if (uiElementSize == 0) {
128  XTHROW(spEx, "element size cannot be zero");
129  break;
130  }
131  if (uiInitialAlloc == 0) {
132  XTHROW(spEx, "initial allocation cannot be zero");
133  break;
134  }
135  spCtx = (vector*) vpMemAlloc(vpMem, sizeof(vector));
136  memset((void*) spCtx, 0, sizeof(*spCtx));
137  spCtx->cpData = (char*) vpMemAlloc(vpMem, (uiElementSize * uiInitialAlloc));
138  spCtx->uiElementSize = uiElementSize;
139  spCtx->uiReserved = uiInitialAlloc;
140  spCtx->uiUsed = 0;
141 
142  // success
143  spCtx->vpMem = vpMem;
144  spCtx->spException = spEx;
145  spCtx->vpValidate = s_vpMagicNumber;
146  return (void*) spCtx;
147  }
148  return NULL;
149 }
150 
161 void vVecDtor(void* vpCtx) {
162  vector* spCtx = (vector*) vpCtx;
163  if (vpCtx) {
164  if (spCtx->vpValidate == s_vpMagicNumber) {
165  void* vpMem = spCtx->vpMem;
166  vMemFree(vpMem, (void*) spCtx->cpData);
167  memset(vpCtx, 0, sizeof(vector));
168  vMemFree(vpMem, vpCtx);
169  }else{
170  vExContext();
171  }
172  }
173 }
174 
179 abool bVecValidate(void* vpCtx){
180  vector* spCtx = (vector*) vpCtx;
181  if (vpCtx && (spCtx->vpValidate == s_vpMagicNumber)) {
182  return APG_TRUE;
183  }
184  return APG_FALSE;
185 }
186 
193 void* vpVecPush(void* vpCtx, void* vpElement) {
194  vector* spCtx = (vector*) vpCtx;
195  if(vpCtx && (spCtx->vpValidate == s_vpMagicNumber)){
196  void* vpReturn = NULL;
197  if (spCtx->uiUsed >= spCtx->uiReserved) {
198  vGrow(spCtx, 1);
199  }
200  vpReturn = (void*) (spCtx->cpData + (spCtx->uiUsed * spCtx->uiElementSize));
201  if (vpElement) {
202  // copy new element to vector
203  memcpy(vpReturn, vpElement, spCtx->uiElementSize);
204  }
205  spCtx->uiUsed += 1;
206  STATS_PUSH(spCtx, 1);
207  return vpReturn;
208  }
209  vExContext();
210  return NULL;
211 }
212 
221 void* vpVecPushn(void* vpCtx, void* vpElement, aint uiCount) {
222  vector* spCtx = (vector*) vpCtx;
223  if(vpCtx && (spCtx->vpValidate == s_vpMagicNumber)){
224  if (uiCount) {
225  void* vpReturn = NULL;
226  if ((spCtx->uiUsed + uiCount) > spCtx->uiReserved) {
227  vGrow(spCtx, uiCount);
228  }
229  vpReturn = (void*) (spCtx->cpData + (spCtx->uiUsed * spCtx->uiElementSize));
230  if (vpElement) {
231  memcpy(vpReturn, vpElement, uiCount * spCtx->uiElementSize);
232  }
233  spCtx->uiUsed += uiCount;
234  STATS_PUSH(spCtx, uiCount);
235  return vpReturn;
236  }
237  XTHROW(spCtx->spException, "attempt to push 0 elements on the vector");
238  return NULL;
239  }
240  vExContext();
241  return NULL;
242 }
243 
250 void* vpVecPop(void* vpCtx) {
251  vector* spCtx = (vector*) vpCtx;
252  if(vpCtx && (spCtx->vpValidate == s_vpMagicNumber)){
253  if (spCtx->uiUsed) {
254  spCtx->uiUsed -= 1;
255  STATS_POP(spCtx, 1);
256  return ((void*) (spCtx->cpData + (spCtx->uiUsed * spCtx->uiElementSize)));
257  }
258  return NULL;
259  }
260  vExContext();
261  return NULL;
262 }
263 
271 void* vpVecPopn(void* vpCtx, aint uiCount) {
272  vector* spCtx = (vector*) vpCtx;
273  if(vpCtx && (spCtx->vpValidate == s_vpMagicNumber)){
274  if ((uiCount > 0) && (spCtx->uiUsed > 0)) {
275  if (spCtx->uiUsed > uiCount) {
276  // pop uiCount elements
277  spCtx->uiUsed -= uiCount;
278  STATS_POP(spCtx, uiCount);
279  return (void*) (spCtx->cpData + (spCtx->uiUsed * spCtx->uiElementSize));
280  }
281  // pop all remaining elements
282  STATS_POP(spCtx, spCtx->uiUsed);
283  spCtx->uiUsed = 0;
284  return spCtx->cpData;
285  }
286  return NULL;
287  }
288  vExContext();
289  return NULL;
290 }
291 
306 void* vpVecPopi(void* vpCtx, aint uiIndex) {
307  vector* spCtx = (vector*) vpCtx;
308  if(vpCtx && (spCtx->vpValidate == s_vpMagicNumber)){
309  if(uiIndex >= spCtx->uiUsed){
310  return NULL;
311  }
312  aint uiCount = spCtx->uiUsed - uiIndex; // will always be positive
313  spCtx->uiUsed -= uiCount;
314  STATS_POP(spCtx, uiCount);
315  return ((void*) (spCtx->cpData + (uiIndex * spCtx->uiElementSize)));
316  }
317  vExContext();
318  return NULL;
319 }
320 
326 void* vpVecFirst(void* vpCtx) {
327  vector* spCtx = (vector*) vpCtx;
328  if(vpCtx && (spCtx->vpValidate == s_vpMagicNumber)){
329  if (spCtx->uiUsed) {
330  return ((void*) spCtx->cpData);
331  }
332  return NULL;
333  }
334  vExContext();
335  return NULL;
336 }
337 
343 void* vpVecLast(void* vpCtx) {
344  vector* spCtx = (vector*) vpCtx;
345  if(vpCtx && (spCtx->vpValidate == s_vpMagicNumber)){
346  if (spCtx->uiUsed) {
347  return ((void*) (spCtx->cpData + (spCtx->uiUsed - 1) * spCtx->uiElementSize));
348  }
349  return NULL;
350  }
351  vExContext();
352  return NULL;
353 }
354 
362 void* vpVecAt(void* vpCtx, aint uiIndex) {
363  vector* spCtx = (vector*) vpCtx;
364  if(vpCtx && (spCtx->vpValidate == s_vpMagicNumber)){
365  if(spCtx->uiUsed == 0){
366  return NULL;
367  }
368  if(uiIndex == 0){
369  return ((void*) spCtx->cpData);
370  }
371  if(uiIndex < spCtx->uiUsed){
372  return ((void*) (spCtx->cpData + (uiIndex * spCtx->uiElementSize)));
373  }
374  return NULL;
375  }
376  vExContext();
377  return NULL;
378 }
379 
385 aint uiVecLen(void* vpCtx){
386  vector* spCtx = (vector*) vpCtx;
387  if(vpCtx && (spCtx->vpValidate == s_vpMagicNumber)){
388  return spCtx->uiUsed;
389  }
390  vExContext();
391  return 0;
392 }
393 
402 void* vpVecBuffer(void* vpCtx){
403  vector* spCtx = (vector*) vpCtx;
404  if(vpCtx && (spCtx->vpValidate == s_vpMagicNumber)){
405  return (void*)spCtx->cpData;
406  }
407  vExContext();
408  return NULL;
409 }
410 
420 void vVecClear(void* vpCtx) {
421  vector* spCtx = (vector*) vpCtx;
422  if(vpCtx){
423  if(spCtx->vpValidate == s_vpMagicNumber){
424  STATS_POP(spCtx, spCtx->uiUsed);
425  spCtx->uiUsed = 0;
426  }else{
427  vExContext();
428  }
429  }
430 }
431 
439 static void vGrow(vector* spCtx, aint uiElements) {
440  aint uiNewReserved;
441  uiNewReserved = 2 * (spCtx->uiReserved + uiElements);
442  spCtx->cpData = (char*)vpMemRealloc(spCtx->vpMem, (void*) spCtx->cpData, (spCtx->uiElementSize * uiNewReserved));
443 
444 // XTHROW(spCtx->spException, "pretending that the memory reallocation failed while growing the vector");
445 
446  STATS_GROW(spCtx, (uiNewReserved - spCtx->uiReserved));
447  spCtx->uiReserved = uiNewReserved;
448 }
449 
450 #if defined APG_VEC_STATS
451 
459 void vVecStats(void* vpCtx, vec_stats* spStats){
460  vector* spCtx = (vector*) vpCtx;
461  if(spStats){
462  spStats->uiElementSize = spCtx->uiElementSize;
463  spStats->uiReserved = spCtx->uiReserved;
464  spStats->uiUsed = spCtx->uiUsed;
465  spStats->uiMaxUsed = spCtx->uiMaxUsed;
466  spStats->uiPopped = spCtx->uiPopped;
467  spStats->uiPushed = spCtx->uiPushed;
468  spStats->uiGrownCount = spCtx->uiGrownCount;
469  spStats->uiGrownElements = spCtx->uiGrownElements;
470  spStats->uiGrownBytes = spCtx->uiElementSize * spCtx->uiGrownElements;
471  spStats->uiReservedBytes = spCtx->uiElementSize * spCtx->uiReserved;
472  spStats->uiOriginalBytes = spStats->uiReservedBytes - spStats->uiGrownBytes;
473  spStats->uiOriginalElements = spStats->uiOriginalBytes / spCtx->uiElementSize;
474  spStats->uiUsedBytes = spCtx->uiElementSize * spCtx->uiUsed;
475  spStats->uiMaxUsedBytes = spCtx->uiElementSize * spCtx->uiMaxUsed;
476  }
477 }
478 void vStatsPush(vector* spCtx, aint uiCount){
479  spCtx->uiPushed += uiCount;
480  if(spCtx->uiUsed > spCtx->uiMaxUsed){
481  spCtx->uiMaxUsed = spCtx->uiUsed;
482  }
483 }
484 void vStatsPop(vector* spCtx, aint uiCount){
485  spCtx->uiPopped += uiCount;
486 }
487 void vStatsGrow(vector* spCtx, aint uiAddedElements){
488  spCtx->uiGrownCount += 1;
489  spCtx->uiGrownElements += uiAddedElements;
490 }
491 #else
492 
497 void vVecStats(void* vpCtx, vec_stats* spStats){
498  if(spStats){
499  memset((void*) spStats, 0, sizeof(vec_stats));
500  }
501 }
502 #endif
lib.h
This header "#include"s all publid lib headers and other standard headers needed by most objects.
vec_stats::uiReserved
aint uiReserved
The current number of elements reserved.
Definition: vector.h:50
vpVecBuffer
void * vpVecBuffer(void *vpCtx)
Get a pointer to the vector buffer.
Definition: vector.c:402
vec_stats::uiGrownCount
aint uiGrownCount
The number times the vector was automatically extended.
Definition: vector.h:58
vVecStats
void vVecStats(void *vpCtx, vec_stats *spStats)
Definition: vector.c:459
vVecDtor
void vVecDtor(void *vpCtx)
The vector component destructor.
Definition: vector.c:161
vec_stats::uiGrownBytes
aint uiGrownBytes
The number of bytes automatically added to the vector.
Definition: vector.h:60
vec_stats::uiOriginalBytes
aint uiOriginalBytes
The initial number of bytes allocated to the vector.
Definition: vector.h:49
vExContext
void vExContext()
Handles bad context pointers.
Definition: exception.c:126
vector::uiGrownCount
aint uiGrownCount
number times the vector automatically grew in size
Definition: vector.c:60
vec_stats::uiUsed
aint uiUsed
The current number elements used.
Definition: vector.h:51
vpVecAt
void * vpVecAt(void *vpCtx, aint uiIndex)
Get a the indexed vector element. The vector is not altered.
Definition: vector.c:362
vpMemRealloc
void * vpMemRealloc(void *vpCtx, const void *vpData, aint uiBytes)
Re-allocates memory previously allocated with vpMemAlloc().
Definition: memory.c:268
vec_stats
Vector usage statistics.
Definition: vector.h:46
XTHROW
#define XTHROW(ctx, msg)
Exception throw macro.
Definition: exception.h:67
vector::vpMem
void * vpMem
context to the underlying memory component
Definition: vector.c:55
vec_stats::uiPushed
aint uiPushed
The total number of elements pushed onto (added to) the vector.
Definition: vector.h:56
vpVecPop
void * vpVecPop(void *vpCtx)
Pops one element from the end of the array.
Definition: vector.c:250
vector::uiMaxUsed
aint uiMaxUsed
maximum number of elements used;
Definition: vector.c:64
aint
uint_fast32_t aint
The APG parser's unsigned integer type.
Definition: apg.h:79
vpVecLast
void * vpVecLast(void *vpCtx)
Get the last element one the vector. The vector is not altered.
Definition: vector.c:343
vector::spException
exception * spException
Definition: vector.c:54
vec_stats::uiOriginalElements
aint uiOriginalElements
The initial number of elements allocated to the vector.
Definition: vector.h:48
vpVecPopn
void * vpVecPopn(void *vpCtx, aint uiCount)
Pops one or more elements from the end of the array.
Definition: vector.c:271
vec_stats::uiUsedBytes
aint uiUsedBytes
The current number of bytes in use.
Definition: vector.h:54
spMemException
exception * spMemException(void *vpCtx)
Get a pointer to this memory objects's exception handler.
Definition: memory.c:174
vector
Private for internal use only. Defines the vector's state. Opaque to applications.
Definition: vector.c:52
vpMemAlloc
void * vpMemAlloc(void *vpCtx, aint uiBytes)
Allocates memory.
Definition: memory.c:196
vector::uiElementSize
aint uiElementSize
number of bytes in one element
Definition: vector.c:57
uiVecLen
aint uiVecLen(void *vpCtx)
Get the vector length. That is, the number of elements on the vector.
Definition: vector.c:385
vpVecCtor
void * vpVecCtor(void *vpMem, aint uiElementSize, aint uiInitialAlloc)
The vector object constructor.
Definition: vector.c:118
vec_stats::uiReservedBytes
aint uiReservedBytes
The current number of bytes reserved.
Definition: vector.h:53
vector::uiPopped
aint uiPopped
number of elements popped
Definition: vector.c:63
exception
A structure to describe the type and location of a caught exception.
Definition: exception.h:47
vMemFree
void vMemFree(void *vpCtx, const void *vpData)
Free memory previously allocated with vpMemAlloc().
Definition: memory.c:226
bVecValidate
abool bVecValidate(void *vpCtx)
Validates a vector component context.
Definition: vector.c:179
vector::cpData
char * cpData
pointer to the vector's data buffer
Definition: vector.c:56
vector::uiReserved
aint uiReserved
number of elements that have been reserved on the buffer
Definition: vector.c:58
exception::vpValidate
const void * vpValidate
Used by the memory object to validate the exception structure.
Definition: exception.h:48
vpVecFirst
void * vpVecFirst(void *vpCtx)
Get the first element one the vector. The vector is not altered.
Definition: vector.c:326
vpVecPushn
void * vpVecPushn(void *vpCtx, void *vpElement, aint uiCount)
Adds one or more elements to the end of the array.
Definition: vector.c:221
vec_stats::uiPopped
aint uiPopped
The total number of elements popped from (removed from) the vector.
Definition: vector.h:57
STATS_PUSH
#define STATS_PUSH(s, p)
Called by the vector object to count the number of pushed (added) elements.
Definition: vector.c:77
vector::uiUsed
aint uiUsed
number of the reserved elements that have been used
Definition: vector.c:59
STATS_GROW
#define STATS_GROW(s, n)
Called by the vector object to count the number of times the size of the vector was automatically ext...
Definition: vector.c:85
APG_TRUE
#define APG_TRUE
Definition: apg.h:291
vec_stats::uiGrownElements
aint uiGrownElements
The number new elements automatically added to the vector.
Definition: vector.h:59
bMemValidate
abool bMemValidate(void *vpCtx)
Validates a memory context.
Definition: memory.c:160
STATS_POP
#define STATS_POP(s, p)
Called by the vector object to count the number of popped (removed) elements.
Definition: vector.c:81
abool
uint8_t abool
abool is the APG bool type.
Definition: apg.h:140
vpVecPopi
void * vpVecPopi(void *vpCtx, aint uiIndex)
Pops the element at the given zero-based index and all higher indexes.
Definition: vector.c:306
vector::vpValidate
const void * vpValidate
must be equal to s_vpMagicNumber
Definition: vector.c:53
vector::uiGrownElements
aint uiGrownElements
number elements vector has grown by
Definition: vector.c:61
vpVecPush
void * vpVecPush(void *vpCtx, void *vpElement)
Adds one element to the end of the array.
Definition: vector.c:193
vec_stats::uiMaxUsedBytes
aint uiMaxUsedBytes
The maximum number of bytes used over the lifetime of the vector.
Definition: vector.h:55
vVecClear
void vVecClear(void *vpCtx)
Clears all used elements in a vector component.
Definition: vector.c:420
vec_stats::uiElementSize
aint uiElementSize
The number of bytes in one element.
Definition: vector.h:47
APG_FALSE
#define APG_FALSE
Definition: apg.h:292
vector::uiPushed
aint uiPushed
number of elements pushed
Definition: vector.c:62
vec_stats::uiMaxUsed
aint uiMaxUsed
The maximum number of elements used during the vector's lifetime.
Definition: vector.h:52
APG Version 7.0 is licensed under the 2-Clause BSD License,
an Open Source Initiative Approved License.