/ src / core / roller1.inc
roller1.inc
  1  // -*- C -*-
  2  // SPDX-FileCopyrightText: 2023-2025 Le'Sec Core collective
  3  //
  4  // SPDX-License-Identifier: LGPL-3.0-or-later
  5  
  6  // This is purely internal, for testing purposes
  7  
  8  #include <stdlib.h>
  9  #include <stdio.h>
 10  #include <assert.h>
 11  #include "roller.h"
 12  
 13  struct test_roller1_data_t {
 14  # define TEST_INNER_ROLL_MIN_SIZE       2
 15  # define TEST_INNER_ROLL_MAX_SIZE       5
 16    unsigned int inner_roll_size; // Size of chunk to roll, in bytes
 17  # define TEST_INNER_ROLL_MIN_NUM        1
 18  # define TEST_INNER_ROLL_MAX_NUM        3
 19    unsigned int inner_roll_num; // Number of times to roll
 20  # define TEST_OUTER_ROLL_MIN_SIZE       2
 21  # define TEST_OUTER_ROLL_MAX_SIZE       5
 22    unsigned int outer_roll_size; // Size of section to roll, in chunks
 23  # define TEST_OUTER_ROLL_MIN_NUM        1
 24  # define TEST_OUTER_ROLL_MAX_NUM        3
 25    unsigned int outer_roll_num; // Number of times to roll
 26  
 27    char buffer[TEST_INNER_ROLL_MAX_SIZE * TEST_OUTER_ROLL_MAX_SIZE];
 28  
 29    TEST_roller_generator_t *generator;
 30    TEST_roller_extractor_t *extractor;
 31    TEST_roller_runner_t *runner;
 32  };
 33  
 34  struct test_roller1_generator_data_t {
 35    TEST_roller_t *obj;
 36    unsigned int seed;
 37  };
 38  
 39  static unsigned int reseed(unsigned int seed)
 40  {
 41    return (seed * 56473) % 91827;
 42  }
 43  
 44  static void generate(struct test_roller1_data_t *p, unsigned int seed)
 45  {
 46    seed = reseed(seed);
 47    p->inner_roll_size
 48      = (seed % (TEST_INNER_ROLL_MAX_SIZE - TEST_INNER_ROLL_MIN_SIZE + 1))
 49      + TEST_INNER_ROLL_MIN_SIZE;
 50    seed = reseed(seed);
 51    p->inner_roll_num
 52      = (seed % (TEST_INNER_ROLL_MAX_NUM - TEST_INNER_ROLL_MIN_NUM + 1))
 53      + TEST_INNER_ROLL_MIN_NUM;
 54    seed = reseed(seed);
 55    p->outer_roll_size
 56      = (seed % (TEST_OUTER_ROLL_MAX_SIZE - TEST_OUTER_ROLL_MIN_SIZE + 1))
 57      + TEST_OUTER_ROLL_MIN_SIZE;
 58    seed = reseed(seed);
 59    p->outer_roll_num
 60      = (seed % (TEST_OUTER_ROLL_MAX_NUM - TEST_OUTER_ROLL_MIN_NUM + 1))
 61      + TEST_OUTER_ROLL_MIN_NUM;
 62  }
 63  
 64  static LE_STATUS roll(struct test_roller1_data_t *p, const char *input,
 65                        char *output, size_t output_sz)
 66  {
 67    size_t n = strlen(input);
 68    size_t os = p->outer_roll_size;
 69    size_t is = p->inner_roll_size;
 70    if (n % (os * is) != 0)
 71      return LE_STS_ERROR;
 72    if (output_sz <= n)
 73      return LE_STS_ERROR;
 74  
 75    size_t on = p->outer_roll_num;
 76    size_t in = p->inner_roll_num;
 77  #ifdef TEST_OBJECT_DEBUG
 78    fprintf(stderr,
 79            "DEBUG[TEST_NR_roll]: "
 80            "n = %zu, os = %zu, is = %zu, on = %zu, in = %zu\n",
 81            n, os, is, on, in);
 82  #endif
 83  
 84    // i:     Current input start index
 85    // oi:    Current input outer roll index
 86    // ot:    Current buffer outer roll index
 87    // ii:    Current input inner roll index
 88    // it:    Current buffer inner roll index
 89    // pi:    Current input position
 90    // pb:    Current buffer position
 91    size_t i;
 92    for (i = 0; i < n; i += os * is) {
 93      for (size_t oi = 0; oi < os; oi++) {
 94        size_t ot = (oi + on) % os;
 95        for (size_t ii = 0; ii < is; ii++) {
 96          size_t it = (ii + in) % is;
 97          size_t pb = ot * is + it;
 98          size_t pi = i + oi * is + ii;
 99          char c = input[pi];
100  #ifdef TEST_OBJECT_DEBUG
101          char cs[3] = { 0, 0, 0 };
102          if (c)
103            cs[0] = c;
104          else
105            strcpy(cs, "\0");
106          fprintf(stderr,
107                  "DEBUG[TEST_NR_roll]: "
108                  "i = %zu, oi = %zu, ot = %zu, ii = %zu, it = %zu, "
109                  "buffer[%zu] = input[%zu] = '%s'\n",
110                  i, oi, ot, ii, it, pb, pi, cs);
111  #endif
112          p->buffer[pb] = c;
113        }
114      }
115      for (size_t o = 0; o < os * is; o++) {
116        size_t po = i + o;
117        char c = p->buffer[o];
118  #ifdef TEST_OBJECT_DEBUG
119        char cs[3] = { 0, 0, 0 };
120        if (c)
121          cs[0] = c;
122        else
123          strcpy(cs, "\0");
124        fprintf(stderr, "DEBUG[TEST_NR_roll]: output[%zu] = buffer[%zu] = '%s'\n",
125                po, o, cs);
126  #endif
127        output[po] = c;
128      }
129    }
130  #ifdef TEST_OBJECT_DEBUG
131    fprintf(stderr, "DEBUG[TEST_NR_roll]: output[%zu] = '\\0'\n", i);
132  #endif
133    output[i] = '\0';
134  
135    return LE_STS_SUCCESS;
136  }
137  
138  static LE_STATUS test_roller1_generator_dispatch(TEST_roller_generator_t *op,
139                                                   int num, ...)
140  {
141    LE_STATUS status = LE_STS_ERROR; // TODO: Set more precise status
142    va_list ap;
143    static const int cmds[] = { LSC_OBJECT_TYPE_GENERATOR_COMMANDS(roller), 0 };
144    static const LSC_param_desc_t param_desc[] = {
145      { "seed", 1,
146        (LSC_data_desc_t){LSC_DT_unsigned_integer,
147                          { { sizeof(unsigned int), sizeof(unsigned int) },
148                            { 0, 0 } } } },
149      { NULL, }
150    };
151  
152  
153    va_start(ap, num);
154    switch (num) {
155      LSC_OBJECT_GENERATOR_TYPE_DISPATCHES(roller, "roller1", op, status, ap, cmds);
156    case LSC_NR_get_settable_roller_generation_param_desc:
157    case LSC_NR_get_gettable_roller_generation_param_desc:
158      {
159        const LSC_param_desc_t **desc = va_arg(ap, const LSC_param_desc_t **);
160        *desc = param_desc;
161      }
162      status = LE_STS_SUCCESS;
163      break;
164    case LSC_NR_set_roller_generation_param:
165    case LSC_NR_get_roller_generation_param:
166      {
167        int param_num = va_arg(ap, int);
168        LSC_param_t *data = va_arg(ap, LSC_param_t *);
169        struct test_roller1_generator_data_t *gendata = op->lsc_data;
170  
171        switch (param_num) {
172        case 1:
173          if (data->size == sizeof(unsigned int)) {
174            switch (num) {
175            case LSC_NR_set_roller_generation_param:
176              gendata->seed = *(unsigned int *)data->data;
177              break;
178            case LSC_NR_get_roller_generation_param:
179              if (data->data != NULL)
180                *(unsigned int *)data->data = gendata->seed;
181              if (data->len != NULL)
182                *data->len = sizeof(int);
183              break;
184            }
185            status = LE_STS_SUCCESS;
186          }
187          break;
188        }
189  
190        data++;
191        if (data->data != NULL || data->len != NULL)
192          status = LE_STS_ERROR;
193      }
194      break;
195    case LSC_NR_generate_roller:
196      {
197        struct test_roller1_generator_data_t *gendata = op->lsc_data;
198  
199        if (gendata == NULL || gendata->obj == NULL)
200          break;
201  
202        unsigned int seed = gendata->seed;
203        struct test_roller1_data_t **p =
204          (struct test_roller1_data_t **)&gendata->obj->lsc_data;
205  
206        if (*p == NULL && (*p = malloc(sizeof(*p))) == NULL)
207          break;
208  
209        generate(*p, seed);
210      }
211      status = LE_STS_SUCCESS;
212      break;
213    default:
214      assert(("roller generator called with an unknown command number", 0));
215    }
216  
217    va_end(ap);
218    return status;
219  }
220  
221  static LE_STATUS test_destroy_roller1_generator(TEST_roller_generator_t *op)
222  {
223    if (op != NULL)
224      free(op->lsc_data);
225    free(op);
226    return LE_STS_SUCCESS;
227  }
228  
229  static LE_STATUS test_roller1_extractor_dispatch(TEST_roller_extractor_t *op,
230                                                   int num, ...)
231  {
232    LE_STATUS status = LE_STS_ERROR; // TODO: Set more precise status
233    struct test_roller1_data_t *p
234      = ((TEST_roller_t *)op->lsc_data)->lsc_data;
235    va_list ap;
236    static const int cmds[] = { LSC_OBJECT_TYPE_EXTRACTOR_COMMANDS(roller), 0 };
237    static const LSC_param_desc_t param_desc[] = {
238      { "inner-roll-size", 0,
239        (LSC_data_desc_t){LSC_DT_unsigned_integer,
240                          { { sizeof(unsigned int), sizeof(unsigned int) },
241                            { 0, 0 } } } },
242      { "inner-roll-num",  1,
243        (LSC_data_desc_t){LSC_DT_unsigned_integer,
244                          { { sizeof(unsigned int), sizeof(unsigned int) },
245                            { 0, 0 } } } },
246      { "outer-roll-size", 2,
247        (LSC_data_desc_t){LSC_DT_unsigned_integer,
248                          { { sizeof(unsigned int), sizeof(unsigned int) },
249                            { 0, 0 } } } },
250      { "outer-roll-num",  3,
251        (LSC_data_desc_t){LSC_DT_unsigned_integer,
252                          { { sizeof(unsigned int), sizeof(unsigned int) },
253                            { 0, 0 } } } },
254      { NULL, }
255    };
256  
257    va_start(ap, num);
258    switch (num) {
259      LSC_OBJECT_EXTRACTOR_TYPE_DISPATCHES(roller, "roller1", op, status, ap, cmds);
260    case LSC_NR_get_gettable_roller_extraction_param_desc:
261      {
262        const LSC_param_desc_t **desc = va_arg(ap, const LSC_param_desc_t **);
263        *desc = param_desc;
264      }
265      status = LE_STS_SUCCESS;
266      break;
267    case LSC_NR_get_roller_extraction_param:
268      {
269        int param_num = va_arg(ap, int);
270        LSC_param_t *data = va_arg(ap, LSC_param_t *);
271        unsigned int *outnum[] = {
272          &p->inner_roll_size, &p->inner_roll_num,
273          &p->outer_roll_size, &p->outer_roll_num
274        };
275  
276        if (param_num < 0 || param_num >= sizeof(outnum))
277          break;
278  
279        if (data->data != NULL)
280          *(unsigned int *)data->data = *outnum[param_num];
281        if (data->len != NULL)
282          *data->len = sizeof(*outnum[param_num]);
283  
284        data++;
285        if (data->data != NULL || data->len != NULL)
286          break;
287      }
288      status = LE_STS_SUCCESS;
289      break;
290    default:
291      assert(("roller extractor called with an unknown command number", 0));
292    }
293  
294    va_end(ap);
295    return status;
296  }
297  
298  static LE_STATUS test_destroy_roller1_extractor(TEST_roller_extractor_t *op)
299  {
300    free(op);
301    return LE_STS_SUCCESS;
302  }
303  
304  static LE_STATUS test_roller1_runner_dispatch(TEST_roller_runner_t *op, int num,
305                                                ...)
306  {
307    LE_STATUS status = LE_STS_ERROR; // TODO: Set more precise status
308    struct test_roller1_data_t *p
309      = ((TEST_roller_t *)op->lsc_data)->lsc_data;
310    va_list ap;
311    static const int cmds[] = { TEST_NR_run_roll, 0 };
312  
313    va_start(ap, num);
314    switch (num) {
315      LSC_OPERATION_TYPE_BASE_DISPATCHES(roller_runner, "roller1", r, status, ap,
316                                         cmds);
317    case TEST_NR_run_roll:
318      {
319        const char *input = va_arg(ap, const char *);
320        char *output = va_arg(ap, char *);
321        size_t output_sz = va_arg(ap, size_t);
322  
323        if (p == NULL)
324          break;
325  
326        status = roll(p, input, output, output_sz);
327      }
328      break;
329    }
330  
331    va_end(ap);
332    return status;
333  }
334  
335  static LE_STATUS test_destroy_roller1_runner(TEST_roller_runner_t *op)
336  {
337    free(op);
338    return LE_STS_SUCCESS;
339  }
340  
341  static LE_STATUS test_roller1_dispatch(TEST_roller_t *r, int num, ...)
342  {
343    LE_STATUS status = LE_STS_ERROR; // TODO: Set more precise status
344    struct test_roller1_data_t **p
345      = ((struct test_roller1_data_t **)&r->lsc_data);
346    va_list ap;
347    static const int cmds[] = { LSC_NR_get_roller_generator,
348                                LSC_NR_get_roller_extractor,
349                                TEST_NR_get_roller_runner,
350                                TEST_NR_roll, 0 };
351  
352    va_start(ap, num);
353    switch (num) {
354      LSC_OBJECT_TYPE_BASE_DISPATCHES(roller, "roller1", r, status, ap, cmds);
355    case LSC_NR_get_roller_generator:
356      {
357        TEST_roller_generator_t **op = va_arg(ap, TEST_roller_generator_t **);
358  
359        if (*p == NULL && (*p = malloc(sizeof(**p))) == NULL)
360          break;
361  
362        if ((*p)->generator == NULL) {
363          status = TEST_new_roller_generator(test_roller1_generator_dispatch,
364                                             test_destroy_roller1_generator,
365                                             NULL, &(*p)->generator);
366        }
367        if ((*p)->generator != NULL) {
368          struct test_roller1_generator_data_t **gendata
369            = (struct test_roller1_generator_data_t **)&(*p)->generator->lsc_data;
370  
371          if (*gendata == NULL)
372            *gendata = malloc(sizeof(**gendata));
373          if (*gendata == NULL) {
374            status = LE_STS_FATAL_ERROR;
375            break;
376          }
377          (*gendata)->obj = r;
378          (*op) = (*p)->generator;
379        }
380      }
381      break;
382    case LSC_NR_get_roller_extractor:
383      {
384        TEST_roller_extractor_t **op = va_arg(ap, TEST_roller_extractor_t **);
385  
386        if (*p == NULL && (*p = malloc(sizeof(**p))) == NULL)
387          break;
388  
389        if ((*p)->extractor == NULL) {
390          status = TEST_new_roller_extractor(test_roller1_extractor_dispatch,
391                                             test_destroy_roller1_extractor,
392                                             NULL, &(*p)->extractor);
393        }
394        if ((*p)->extractor != NULL) {
395          (*p)->extractor->lsc_data = r;
396          (*op) = (*p)->extractor;
397        }
398      }
399      break;
400    case TEST_NR_get_roller_runner:
401      {
402        TEST_roller_runner_t **op = va_arg(ap, TEST_roller_runner_t **);
403  
404        if (*p == NULL && (*p = malloc(sizeof(**p))) == NULL)
405          break;
406  
407        if ((*p)->runner == NULL) {
408          status = TEST_new_roller_runner(test_roller1_runner_dispatch,
409                                          test_destroy_roller1_runner,
410                                          NULL, &(*p)->runner);
411        }
412        if ((*p)->runner != NULL) {
413          (*p)->runner->lsc_data = r;
414          (*op) = (*p)->runner;
415        }
416      }
417      break;
418    case TEST_NR_roll:
419      {
420        const char *input = va_arg(ap, const char *);
421        char *output = va_arg(ap, char *);
422        size_t output_sz = va_arg(ap, size_t);
423  
424        if (*p == NULL)
425          break;
426  
427        status = roll(*p, input, output, output_sz);
428      }
429      break;
430    default:
431      assert(("roller called with an unknown command number", 0));
432    }
433  
434    va_end(ap);
435    return status;
436  }
437  
438  static LE_STATUS test_destroy_roller1(TEST_roller_t *r)
439  {
440    LE_STATUS status = LE_STS_SUCCESS;
441  
442    if (r != NULL) {
443      struct test_roller1_data_t *p
444        = (struct test_roller1_data_t *)r->lsc_data;
445  
446      if (!LE_status_is_OK(status = TEST_free_roller_generator(p->generator)))
447        return status;
448      if (!LE_status_is_OK(status = TEST_free_roller_extractor(p->extractor)))
449        return status;
450      if (!LE_status_is_OK(status = TEST_free_roller_runner(p->runner)))
451        return status;
452      free(r->lsc_data);
453    }
454    free(r);
455    return LE_STS_SUCCESS;
456  }
457  
458  static LE_STATUS TEST_new_roller1(TEST_roller_t **r)
459  {
460    return TEST_new_roller(test_roller1_dispatch, test_destroy_roller1, NULL,
461                           r);
462  }