star-buffer

Load 1D arrays in binary format
git clone git://git.meso-star.fr/star-buffer.git
Log | Files | Refs | README | LICENSE

test_sbuf_load.c (10270B)


      1 /* Copyright (C) 2022, 2023 |Méso|Star> (contact@meso-star.com)
      2  *
      3  * This program is free software: you can redistribute it and/or modify
      4  * it under the terms of the GNU General Public License as published by
      5  * the Free Software Foundation, either version 3 of the License, or
      6  * (at your option) any later version.
      7  *
      8  * This program is distributed in the hope that it will be useful,
      9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     11  * GNU General Public License for more details.
     12  *
     13  * You should have received a copy of the GNU General Public License
     14  * along with this program. If not, see <http://www.gnu.org/licenses/>. */
     15 
     16 #include "sbuf.h"
     17 #include <rsys/math.h>
     18 #include <rsys/mem_allocator.h>
     19 #include <string.h>
     20 
     21 struct type_desc {
     22   void (*set)(void* data, const size_t i);
     23   int (*eq)(const void* a, const void* b);
     24 
     25   uint64_t size;
     26   uint64_t alignment;
     27 };
     28 
     29 struct header {
     30   uint64_t pagesize;
     31   uint64_t size;
     32   uint64_t szitem;
     33   uint64_t alitem;
     34 };
     35 
     36 /*******************************************************************************
     37  * i16_f32 type
     38  ******************************************************************************/
     39 struct i16_f32 {
     40   int16_t i16;
     41   float f32;
     42 };
     43 
     44 static void
     45 i16_f32_set(void* data, const size_t i)
     46 {
     47   struct i16_f32* t = data;
     48   CHK(t);
     49   t->i16 = (int16_t)i;
     50   t->f32 = (float)i/100.f;
     51 }
     52 
     53 static int
     54 i16_f32_eq(const void* a, const void* b)
     55 {
     56   const struct i16_f32* t0 = a;
     57   const struct i16_f32* t1 = b;
     58   CHK(t0 && t1);
     59   return t0->i16 == t1->i16 && t0->f32 == t1->f32;
     60 }
     61 
     62 /*******************************************************************************
     63  * char[7]
     64  ******************************************************************************/
     65 typedef char (char7_T) [7];
     66 
     67 static void
     68 char7_set(void* data, const size_t i)
     69 {
     70   char* str = data;
     71   CHK(i < 1000);
     72   sprintf(str, "%3dabc", (int)i);
     73 }
     74 
     75 static int
     76 char7_eq(const void* a, const void* b)
     77 {
     78   const char* s0 = a;
     79   const char* s1 = b;
     80   CHK(s0 && s1);
     81   return strcmp(s0, s1) == 0;
     82 }
     83 
     84 /*******************************************************************************
     85  * ui32_f32 type
     86  ******************************************************************************/
     87 struct ui32_f32 {
     88   uint32_t ui32;
     89   float f32;
     90 };
     91 
     92 static void
     93 ui32_f32_set(void* data, const size_t i)
     94 {
     95   struct ui32_f32* t = data;
     96   CHK(t);
     97   t->ui32 = (uint32_t)i;
     98   t->f32 = (float)i/100.f;
     99 }
    100 
    101 static int
    102 ui32_f32_eq(const void* a, const void* b)
    103 {
    104   const struct ui32_f32* t0 = a;
    105   const struct ui32_f32* t1 = b;
    106   CHK(t0 && t1);
    107   return t0->ui32 == t1->ui32 && t0->f32 == t1->f32;
    108 }
    109 
    110 /*******************************************************************************
    111  * float
    112  ******************************************************************************/
    113 static void
    114 f32_set(void* data, const size_t i)
    115 {
    116   float* f = data;
    117   CHK(f);
    118   *f = (float)i;
    119 }
    120 
    121 static int
    122 f32_eq(const void* a, const void* b)
    123 {
    124   const float* f0 = a;
    125   const float* f1 = b;
    126   CHK(f0 && f1);
    127   return *f0 == *f1;
    128 }
    129 
    130 /*******************************************************************************
    131  * Helper functions
    132  ******************************************************************************/
    133 static void
    134 check_sbuf_desc
    135   (const struct sbuf_desc* desc,
    136    const uint64_t size,
    137    const struct type_desc* type)
    138 {
    139   char ALIGN(512) mem[512] = {0};
    140   size_t i;
    141   CHK(desc && type);
    142   CHK(type->size <= sizeof(mem));
    143   CHK(type->alignment <= ALIGNOF(mem));
    144 
    145   CHK(desc->buffer != NULL);
    146   CHK(desc->size == size);
    147   CHK(desc->szitem == type->size);
    148   CHK(desc->alitem == type->alignment);
    149   CHK(desc->pitch == ALIGN_SIZE(type->size, type->alignment));
    150 
    151   FOR_EACH(i, 0, size) {
    152     const void* item = sbuf_desc_at(desc, i);
    153     CHK(IS_ALIGNED(item, desc->alitem));
    154     type->set(mem, i);
    155     CHK(type->eq(mem, item));
    156   }
    157 }
    158 
    159 static void
    160 write_buffer
    161   (FILE* fp,
    162    const struct header* header,
    163    const struct type_desc* type)
    164 {
    165   char ALIGN(512) mem[512] = {0};
    166   size_t i;
    167   const char byte = 0;
    168 
    169   CHK(type);
    170   CHK(type->size <= sizeof(mem));
    171 
    172   /* Write file header */
    173   CHK(fwrite(&header->pagesize, sizeof(header->pagesize), 1, fp) == 1);
    174   CHK(fwrite(&header->size, sizeof(header->size), 1, fp) == 1);
    175   CHK(fwrite(&header->szitem, sizeof(header->szitem), 1, fp) == 1);
    176   CHK(fwrite(&header->alitem, sizeof(header->alitem), 1, fp) == 1);
    177 
    178   /* Padding */
    179   CHK(fseek(fp,
    180     (long)ALIGN_SIZE((size_t)ftell(fp), header->pagesize), SEEK_SET) == 0);
    181 
    182   /* Write the buffer data */
    183   FOR_EACH(i, 0, header->size) {
    184     type->set(mem, i);
    185     CHK(fwrite(mem, type->size, 1, fp) == 1);
    186     CHK(fseek(fp,
    187       (long)ALIGN_SIZE((size_t)ftell(fp), type->alignment), SEEK_SET) == 0);
    188   }
    189 
    190   /* Padding. Write one char to position the EOF indicator */
    191   CHK(fseek(fp,
    192     (long)ALIGN_SIZE((size_t)ftell(fp), header->pagesize)-1, SEEK_SET) == 0);
    193   CHK(fwrite(&byte, sizeof(byte), 1, fp) == 1);
    194   CHK(fflush(fp) == 0);
    195 }
    196 
    197 static void
    198 test_misc(struct sbuf* buf)
    199 {
    200   struct sbuf_desc desc = SBUF_DESC_NULL;
    201   struct header header;
    202   struct type_desc type;
    203   FILE* fp = NULL;
    204   CHK(buf);
    205 
    206   type.set = f32_set;
    207   type.eq = f32_eq;
    208   type.size = sizeof(float);
    209   type.alignment = ALIGNOF(float);
    210 
    211   header.pagesize = 16384;
    212   header.size = 123;
    213   header.szitem = type.size;
    214   header.alitem = type.alignment;
    215 
    216   CHK(fp = tmpfile());
    217   write_buffer(fp, &header, &type);
    218   rewind(fp);
    219 
    220   CHK(sbuf_load_stream(NULL, fp, NULL) == RES_BAD_ARG);
    221   CHK(sbuf_load_stream(buf, NULL, NULL) == RES_BAD_ARG);
    222   CHK(sbuf_load_stream(buf, fp, NULL) == RES_OK);
    223 
    224   rewind(fp);
    225   CHK(sbuf_load_stream(buf, fp, "<stream>") == RES_OK);
    226 
    227   CHK(sbuf_get_desc(NULL, &desc) == RES_BAD_ARG);
    228   CHK(sbuf_get_desc(buf, NULL) == RES_BAD_ARG);
    229   CHK(sbuf_get_desc(buf, &desc) == RES_OK);
    230   check_sbuf_desc(&desc, header.size, &type);
    231 
    232   CHK(fclose(fp) == 0);
    233 }
    234 
    235 static void
    236 test_buffer
    237   (struct sbuf* buf,
    238    const struct header* header,
    239    const struct type_desc* type,
    240    const res_T res)
    241 {
    242   FILE* fp = NULL;
    243   CHK(buf && type);
    244 
    245   CHK(fp = tmpfile());
    246   write_buffer(fp, header, type);
    247   rewind(fp);
    248 
    249   CHK(sbuf_load_stream(buf, fp, NULL) == res);
    250 
    251   if(res == RES_OK) {
    252     struct sbuf_desc desc = SBUF_DESC_NULL;
    253     CHK(sbuf_get_desc(buf, &desc) == RES_OK);
    254     check_sbuf_desc(&desc, header->size, type);
    255   }
    256 
    257   CHK(fclose(fp) == 0);
    258 }
    259 
    260 static void
    261 test_load(struct sbuf* buf)
    262 {
    263   struct header header;
    264   struct type_desc type;
    265 
    266   type.set = i16_f32_set;
    267   type.eq = i16_f32_eq;
    268   type.size = sizeof(struct i16_f32);
    269   type.alignment = ALIGNOF(struct i16_f32);
    270 
    271   header.pagesize = 16384;
    272   header.size = 287;
    273   header.szitem = type.size;
    274   header.alitem = type.alignment;
    275 
    276   test_buffer(buf, &header, &type, RES_OK);
    277 
    278   type.alignment = header.alitem = 32;
    279   test_buffer(buf, &header, &type, RES_OK);
    280 
    281   type.set = char7_set;
    282   type.eq = char7_eq;
    283   type.size = header.szitem = sizeof(char7_T);
    284   type.alignment = header.alitem = ALIGNOF(char7_T);
    285   test_buffer(buf, &header, &type, RES_OK);
    286 
    287   type.set = ui32_f32_set;
    288   type.eq = ui32_f32_eq;
    289   type.size = header.szitem = sizeof(struct ui32_f32);
    290   type.alignment = header.alitem = ALIGNOF(struct ui32_f32);
    291   test_buffer(buf, &header, &type, RES_OK);
    292 
    293   type.set = f32_set;
    294   type.eq = f32_eq;
    295   type.size = header.szitem = sizeof(float);
    296   type.alignment = header.alitem = ALIGNOF(float);
    297   test_buffer(buf, &header, &type, RES_OK);
    298 }
    299 
    300 static void
    301 test_load_fail(struct sbuf* buf)
    302 {
    303   struct type_desc type;
    304   struct header header;
    305   uint64_t size = 0;
    306   FILE* fp = NULL;
    307 
    308   type.set = f32_set;
    309   type.eq = f32_eq;
    310   type.size = sizeof(float);
    311   type.alignment = 32;
    312 
    313   header.pagesize = 4096;
    314   header.size = 100;
    315   header.szitem = type.size;
    316   header.alitem = type.alignment;
    317 
    318   /* Check the a priori validity of the current parameters */
    319   test_buffer(buf, &header, &type, RES_OK);
    320 
    321   /* Invalid page size */
    322   header.pagesize = 2048;
    323   test_buffer(buf, &header, &type, RES_BAD_ARG);
    324   header.pagesize = 4098;
    325   test_buffer(buf, &header, &type, RES_BAD_ARG);
    326 
    327   /* Invalid size */
    328   header.pagesize = 4096;
    329   header.size = 0;
    330   test_buffer(buf, &header, &type, RES_BAD_ARG);
    331 
    332   /* Invalid item  size */
    333   header.size = 100;
    334   header.szitem = 0;
    335   test_buffer(buf, &header, &type, RES_BAD_ARG);
    336 
    337   /* Invalid type alignment */
    338   header.szitem = type.size;
    339   header.alitem = 0;
    340   test_buffer(buf, &header, &type, RES_BAD_ARG);
    341   header.alitem = 33;
    342   test_buffer(buf, &header, &type, RES_BAD_ARG);
    343   header.alitem = 8192;
    344   test_buffer(buf, &header, &type, RES_BAD_ARG);
    345 
    346   /* Invalid file size */
    347   header.alitem = type.alignment;
    348   CHK(fp = tmpfile());
    349   write_buffer(fp, &header, &type);
    350   CHK(fseek(fp, 8, SEEK_SET) == 0); /* Overwrite the size */
    351   size = 5000;
    352   CHK(fwrite(&size, sizeof(size), 1, fp) == 1);
    353   rewind(fp);
    354   CHK(sbuf_load_stream(buf, fp, NULL) == RES_IO_ERR);
    355   CHK(fclose(fp) == 0);
    356 }
    357 
    358 static void
    359 test_load_files(struct sbuf* buf, int argc, char** argv)
    360 {
    361   int i;
    362   CHK(buf);
    363   FOR_EACH(i, 1, argc) {
    364     struct sbuf_desc desc = SBUF_DESC_NULL;
    365     size_t iitem;
    366 
    367     printf("Loading %s\n", argv[i]);
    368     CHK(sbuf_load(buf, argv[i]) == RES_OK);
    369     CHK(sbuf_get_desc(buf, &desc) == RES_OK);
    370     CHK(desc.buffer);
    371     CHK(desc.size);
    372     CHK(desc.szitem);
    373     CHK(desc.alitem);
    374     CHK(desc.pitch);
    375     CHK(IS_POW2(desc.alitem));
    376 
    377     FOR_EACH(iitem, 0, desc.size) {
    378       const void* data = NULL;
    379       data = sbuf_desc_at(&desc, iitem);
    380       CHK(data != 0);
    381       CHK(IS_ALIGNED(data, desc.alitem));
    382       if(iitem) {
    383         const void* prev = (char*)data - desc.pitch;
    384         CHK(prev == sbuf_desc_at(&desc, iitem-1));
    385       }
    386     }
    387   }
    388 }
    389 
    390 /*******************************************************************************
    391  * Main function
    392  ******************************************************************************/
    393 int
    394 main(int argc, char** argv)
    395 {
    396   struct sbuf_create_args args = SBUF_CREATE_ARGS_DEFAULT;
    397   struct sbuf* buf = NULL;
    398   (void)argc, (void)argv;
    399 
    400   args.verbose = 1;
    401   CHK(sbuf_create(&args, &buf) == RES_OK);
    402 
    403   if(argc > 1) {
    404     test_load_files(buf, argc, argv);
    405   } else {
    406     test_misc(buf);
    407     test_load(buf);
    408     test_load_fail(buf);
    409   }
    410 
    411   CHK(sbuf_ref_put(buf) == RES_OK);
    412   CHK(mem_allocated_size() == 0);
    413   return 0;
    414 }