chiark / gitweb /
Merge branch '2.5.x'
[catacomb] / base / rsvr.h
1 /* -*-c-*-
2  *
3  * Reservoir and buffer handling
4  *
5  * (c) 2017 Straylight/Edgeware
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
9  *
10  * This file is part of Catacomb.
11  *
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.
16  *
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.
21  *
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,
25  * USA.
26  */
27
28 #ifndef CATACOMB_RSVR_H
29 #define CATACOMB_RSVR_H
30
31 #ifdef __cplusplus
32   extern "C" {
33 #endif
34
35 /*----- Header files ------------------------------------------------------*/
36
37 #include <stddef.h>
38
39 /*----- Data structures ---------------------------------------------------*/
40
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
46                                          * @blksz@ */
47 } rsvr_policy;
48
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
58                                          * reservoir */
59 } rsvr_plan;
60
61 enum { RSVRSRC_RSVR, RSVRSRC_INPUT, RSVRSRC_DONE };
62
63 typedef struct rsvr_state {
64   rsvr_plan plan;
65   unsigned *used;
66   unsigned char *rsvr;
67   const unsigned char *in, *p;
68   size_t sz;
69   unsigned src;
70 } rsvr_state;
71
72 /*----- Functions provided ------------------------------------------------*/
73
74 /* --- @rsvr_mkplan@ --- *
75  *
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
80  *
81  * Returns:     ---
82  *
83  * Use:         Prepares a plan for feeding input data into a block-oriented
84  *              operation.
85  *
86  *              The caller's code for following the plan proceeds in four
87  *              parts.
88  *
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@.
92  *
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@.
96  *
97  *                3. Process the next @plan->from_input@ items directly from
98  *                   the input; @plan->from_input@ will be a multiple of
99  *                   @pol->blksz@.
100  *
101  *                4. Insert the remaining @plan->tail@ input items into the
102  *                   reservoir for next time.
103  */
104
105 extern void rsvr_mkplan(rsvr_plan */*plan*/, const rsvr_policy */*pol*/,
106                         size_t /*used*/, size_t /*insz*/);
107
108 /* --- @rsvr_setup@ --- *
109  *
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
116  *
117  * Returns:     ---
118  *
119  * Use:         Prepares for a simple operation.  This performs the initial
120  *              copy of input data into the reservoir, and prepares for the
121  *              next step.
122  *
123  *              After this, the calling code should usually proceed as
124  *              follows.
125  *
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@.
131  *
132  *                2. Call @rsvr_done@ to indicate that this has been done.
133  *
134  *                3. Call @RSVR_NEXT@ in a sequence of loops, as in step 1,
135  *                   to process the remaining data from the input buffer.
136  *
137  *                4. Call @rsvr_done@ to indicate that the job is complete.
138  */
139
140 extern void rsvr_setup(rsvr_state */*st*/, const rsvr_policy */*pol*/,
141                        void */*rsvr*/, unsigned */*used*/,
142                        const void */*in*/, size_t /*insz*/);
143
144 /* --- @RSVR_NEXT@, @rsvr_next@ --- *
145  *
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@
149  *
150  * Returns:     A pointer to the next @n@ bytes of input, or null if there is
151  *              insufficient data remaining.
152  */
153
154 #define RSVR_NEXT(st, n)                                                \
155         ((n) > (st)->sz                                                 \
156                 ? 0                                                     \
157                 : ((st)->sz -= (n),                                     \
158                    (st)->p += (n),                                      \
159                    (const void *)((st)->p - (n))))
160 extern const void *rsvr_next(rsvr_state */*st*/, size_t /*n*/);
161
162 /* --- @rsvr_done@ --- *
163  *
164  * Arguments:   @rsvr_state *st@ = pointer to the state structure
165  *
166  * Returns:     Zero after the first pass, nonzero after the second.
167  *
168  * Use:         Reports that the first or second stage (see @rsvr_setup@
169  *              above) of an operation has been completed.
170  *
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.
175  */
176
177 extern int rsvr_done(rsvr_state */*st*/);
178
179 /* --- @RSVR_DO@ --- *
180  *
181  * Arguments:   @st@ = pointer to state structure
182  *
183  * Use:         Invoke as @RSVR_DO(st) stmt@: performs two passes of @stmt@
184  *              over the reservoir and input buffers respectively.
185  */
186
187 #define RSVR_DO(st) switch (0) while (!rsvr_done(st)) case 0:
188
189 /*----- That's all, folks -------------------------------------------------*/
190
191 #ifdef __cplusplus
192   }
193 #endif
194
195 #endif