3 * Reservoir and buffer handling
5 * (c) 2017 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of Catacomb.
12 * Catacomb is free software: you can redistribute it and/or modify it
13 * under the terms of the GNU Library General Public License as published
14 * by the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * Catacomb is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Library General Public License for more details.
22 * You should have received a copy of the GNU Library General Public
23 * License along with Catacomb. If not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
28 #ifndef CATACOMB_RSVR_H
29 #define CATACOMB_RSVR_H
35 /*----- Header files ------------------------------------------------------*/
39 /*----- Data structures ---------------------------------------------------*/
41 typedef struct rsvr_policy
{
42 unsigned f
; /* Flags... */
43 #define RSVRF_FULL 1u /* Hold back a full reservoir */
44 unsigned blksz
; /* Block size */
45 unsigned rsvrsz
; /* Reservoir size; multiple of
49 typedef struct rsvr_plan
{
50 unsigned head
; /* First, accumulate @head@ bytes
51 * into the reservoir */
52 unsigned from_rsvr
; /* Next, process @from_rsvr@ bytes
53 * from the reservoir */
54 size_t from_input
; /* Then, process @from_input@ bytes
55 * directly from the input */
56 unsigned tail
; /* Finally, accumulate the remaining
57 * @tail@ bytes of input into the
61 enum { RSVRSRC_RSVR
, RSVRSRC_INPUT
, RSVRSRC_DONE
};
63 typedef struct rsvr_state
{
67 const unsigned char *in
, *p
;
72 /*----- Functions provided ------------------------------------------------*/
74 /* --- @rsvr_mkplan@ --- *
76 * Arguments: @rsvr_plan *plan@ = pointer to plan to fill in
77 * @const rsvr_policy *pol@ = reservoir policy to follow
78 * @size_t used@ = amount of data in the reservoir
79 * @size_t insz@ = amount of fresh input data arriving
83 * Use: Prepares a plan for feeding input data into a block-oriented
86 * The caller's code for following the plan proceeds in four
89 * 1. Insert the first @plan->head@ input items into the
90 * reservoir; there will be sufficient space, and
91 * @plan->head@ will be at most @pol->blksz@.
93 * 2. Process the first @plan->from_rsvr@ items from the
94 * reservoir, shifting the remaining items forward;
95 * @plan->from_rsvr@ will be a multiple of @pol->blksz@.
97 * 3. Process the next @plan->from_input@ items directly from
98 * the input; @plan->from_input@ will be a multiple of
101 * 4. Insert the remaining @plan->tail@ input items into the
102 * reservoir for next time.
105 extern void rsvr_mkplan(rsvr_plan */
*plan*/
, const rsvr_policy */
*pol*/
,
106 size_t /*used*/, size_t /*insz*/);
108 /* --- @rsvr_setup@ --- *
110 * Arguments: @rsvr_state *st@ = pointer to state structure to fill in
111 * @const rsvr_policy *pol@ = reservoir policy to follow
112 * @void *rsvr@ = pointer to the actual reservoir
113 * @unsigned *used@ = pointer to the reservoir level
114 * @const void *in@ = pointer to the input data
115 * @size_t insz@ = size of the input
119 * Use: Prepares for a simple operation. This performs the initial
120 * copy of input data into the reservoir, and prepares for the
123 * After this, the calling code should usually proceed as
126 * 1. Call @RSVR_NEXT@ in a sequence of loops, with
127 * successively smaller values of @n@, to process waiting
128 * data from the reservoir. Usually, each @n@ will be some
129 * multiple of the block size @pol->blksz@, and the final
130 * loop will have @n = pol->blksz@.
132 * 2. Call @rsvr_done@ to indicate that this has been done.
134 * 3. Call @RSVR_NEXT@ in a sequence of loops, as in step 1,
135 * to process the remaining data from the input buffer.
137 * 4. Call @rsvr_done@ to indicate that the job is complete.
140 extern void rsvr_setup(rsvr_state */
*st*/
, const rsvr_policy */
*pol*/
,
141 void */
*rsvr*/
, unsigned */
*used*/
,
142 const void */
*in*/
, size_t /*insz*/);
144 /* --- @RSVR_NEXT@, @rsvr_next@ --- *
146 * Arguments: @rsvr_state *st@ = pointer to the state structure
147 * @size_t n@ = amount of input data required, in bytes; should
148 * usually be a multiple of @pol->blksz@
150 * Returns: A pointer to the next @n@ bytes of input, or null if there is
151 * insufficient data remaining.
154 #define RSVR_NEXT(st, n) \
157 : ((st)->sz -= (n), \
159 (const void *)((st)->p - (n))))
160 extern const void *rsvr_next(rsvr_state */
*st*/
, size_t /*n*/);
162 /* --- @rsvr_done@ --- *
164 * Arguments: @rsvr_state *st@ = pointer to the state structure
166 * Returns: Zero after the first pass, nonzero after the second.
168 * Use: Reports that the first or second stage (see @rsvr_setup@
169 * above) of an operation has been completed.
171 * If the first stage is complete, then this shifts stuff about
172 * in the reservoir and prepares for the second stage; if the
173 * second stage is complete, then it copies the remaining input
174 * into the reservoir and marks the state as complete.
177 extern int rsvr_done(rsvr_state */
*st*/
);
179 /* --- @RSVR_DO@ --- *
181 * Arguments: @st@ = pointer to state structure
183 * Use: Invoke as @RSVR_DO(st) stmt@: performs two passes of @stmt@
184 * over the reservoir and input buffers respectively.
187 #define RSVR_DO(st) switch (0) while (!rsvr_done(st)) case 0:
189 /*----- That's all, folks -------------------------------------------------*/