solstice

Compute collected power and efficiencies of a solar plant
git clone git://git.meso-star.com/solstice.git
Log | Files | Refs | README | LICENSE

srcvl.c (12543B)


      1 /* Copyright (C) 2018-2026 |Meso|Star> (contact@meso-star.com)
      2  * Copyright (C) 2016-2018 CNRS
      3  *
      4  * This program is free software: you can redistribute it and/or modify
      5  * it under the terms of the GNU General Public License as published by
      6  * the Free Software Foundation, either version 3 of the License, or
      7  * (at your option) any later version.
      8  *
      9  * This program is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     12  * GNU General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU General Public License
     15  * along with this program. If not, see <http://www.gnu.org/licenses/>. */
     16 
     17 #include "srcvl.h"
     18 
     19 #include <rsys/cstr.h>
     20 #include <rsys/dynamic_array.h>
     21 #include <rsys/mem_allocator.h>
     22 #include <rsys/ref_count.h>
     23 #include <rsys/str.h>
     24 
     25 #include <stdio.h>
     26 #include <stdarg.h>
     27 #include <yaml.h>
     28 
     29 struct receiver {
     30   struct str name;
     31   enum srcvl_side side;
     32   enum srcvl_pp_output per_primitive_output;
     33 };
     34 
     35 static INLINE void
     36 receiver_init(struct mem_allocator* allocator, struct receiver* receiver)
     37 {
     38   ASSERT(receiver);
     39   str_init(allocator, &receiver->name);
     40   receiver->side = SRCVL_FRONT_AND_BACK;
     41   receiver->per_primitive_output = SRCVL_PP_NONE;
     42 }
     43 
     44 static INLINE void
     45 receiver_release(struct receiver* receiver)
     46 {
     47   ASSERT(receiver);
     48   str_release(&receiver->name);
     49 }
     50 
     51 static INLINE res_T
     52 receiver_copy(struct receiver* dst, const struct receiver* src)
     53 {
     54   ASSERT(dst && src);
     55   dst->side = src->side;
     56   dst->per_primitive_output = src->per_primitive_output;
     57   return str_copy(&dst->name, &src->name);
     58 }
     59 
     60 static INLINE res_T
     61 receiver_copy_and_release(struct receiver* dst, struct receiver* src)
     62 {
     63   ASSERT(dst && src);
     64   dst->side = src->side;
     65   dst->per_primitive_output = src->per_primitive_output;
     66   return str_copy_and_release(&dst->name, &src->name);
     67 }
     68 
     69 #define DARRAY_NAME receiver
     70 #define DARRAY_DATA struct receiver
     71 #define DARRAY_FUNCTOR_INIT receiver_init
     72 #define DARRAY_FUNCTOR_RELEASE receiver_release
     73 #define DARRAY_FUNCTOR_COPY receiver_copy
     74 #define DARRAY_FUNCTOR_COPY_AND_RELEASE receiver_copy_and_release
     75 #include <rsys/dynamic_array.h>
     76 
     77 struct srcvl {
     78   yaml_parser_t parser;
     79   int parser_is_init;
     80   struct darray_receiver receivers;
     81 
     82   struct str stream_name;
     83 
     84   ref_T ref;
     85   struct mem_allocator* allocator;
     86 };
     87 
     88 /*******************************************************************************
     89  * Helper functions
     90  ******************************************************************************/
     91 static INLINE void
     92 log_err
     93   (const struct srcvl* srcvl,
     94    const yaml_node_t* node,
     95    const char* fmt,
     96    ...)
     97 {
     98   va_list vargs_list;
     99   ASSERT(srcvl && node && fmt);
    100 
    101   fprintf(stderr, "%s:%lu:%lu: ",
    102     str_cget(&srcvl->stream_name),
    103     (unsigned long)node->start_mark.line+1,
    104     (unsigned long)node->start_mark.column+1);
    105   va_start(vargs_list, fmt);
    106   vfprintf(stderr, fmt, vargs_list);
    107   va_end(vargs_list);
    108 }
    109 
    110 static res_T
    111 parse_string
    112   (struct srcvl* srcvl,
    113    yaml_node_t* string,
    114    struct str* str)
    115 {
    116   res_T res = RES_OK;
    117   ASSERT(string && str);
    118 
    119   if(string->type != YAML_SCALAR_NODE
    120   || !strlen((char*)string->data.scalar.value)) {
    121     log_err(srcvl, string, "expect a character string.\n");
    122     res = RES_BAD_ARG;
    123     goto error;
    124   }
    125   res = str_set(str, (char*)string->data.scalar.value);
    126   if(res !=  RES_OK) {
    127     log_err(srcvl, string, "could not register the string `%s'.\n",
    128       string->data.scalar.value);
    129     goto error;
    130   }
    131 
    132 exit:
    133   return res;
    134 error:
    135   goto exit;
    136 }
    137 
    138 static res_T
    139 parse_side
    140   (struct srcvl* srcvl,
    141    yaml_node_t* side,
    142    enum srcvl_side* out_side)
    143 {
    144   res_T res = RES_OK;
    145   ASSERT(side && out_side);
    146 
    147   if(side->type != YAML_SCALAR_NODE) {
    148     log_err(srcvl, side, "expect a character string.\n");
    149     res = RES_BAD_ARG;
    150     goto error;
    151   }
    152 
    153   if(!strcmp((char*)side->data.scalar.value, "FRONT")) {
    154     *out_side = SRCVL_FRONT;
    155   } else if(!strcmp((char*)side->data.scalar.value, "BACK")) {
    156     *out_side = SRCVL_BACK;
    157   } else if(!strcmp((char*)side->data.scalar.value, "FRONT_AND_BACK")) {
    158     *out_side = SRCVL_FRONT_AND_BACK;
    159   } else {
    160     log_err(srcvl, side, "unknown side value `%s'.\n",
    161       side->data.scalar.value);
    162     res = RES_BAD_ARG;
    163     goto error;
    164   }
    165 exit:
    166   return res;
    167 error:
    168   goto exit;
    169 }
    170 
    171 static res_T
    172 parse_pp_output
    173   (struct srcvl* srcvl,
    174    yaml_node_t* side,
    175    enum srcvl_pp_output* out_side)
    176 {
    177   res_T res = RES_OK;
    178   ASSERT(side && out_side);
    179 
    180   if(side->type != YAML_SCALAR_NODE) {
    181     log_err(srcvl, side, "expect a character string.\n");
    182     res = RES_BAD_ARG;
    183     goto error;
    184   }
    185 
    186   if(!strcmp((char*) side->data.scalar.value, "NONE")) {
    187     *out_side = SRCVL_PP_NONE;
    188   } else if(!strcmp((char*) side->data.scalar.value, "INCOMING")) {
    189     *out_side = SRCVL_PP_INCOMING;
    190   } else if(!strcmp((char*) side->data.scalar.value, "ABSORBED")) {
    191     *out_side = SRCVL_PP_ABSORBED;
    192   } else if(!strcmp((char*) side->data.scalar.value, "INCOMING_AND_ABSORBED")) {
    193     *out_side = SRCVL_PP_INCOMING_AND_ABSORBED;
    194   } else {
    195     log_err(srcvl, side, "unknown per primitive output type value `%s'.\n",
    196       side->data.scalar.value);
    197     res = RES_BAD_ARG;
    198     goto error;
    199   }
    200 exit:
    201   return res;
    202 error:
    203   goto exit;
    204 }
    205 
    206 static res_T
    207 parse_receiver
    208   (struct srcvl* srcvl,
    209    yaml_document_t* doc,
    210    const yaml_node_t* receiver)
    211 {
    212   enum { NAME, PER_PRIMITIVE, SIDE };
    213   struct receiver* solreceiver = NULL;
    214   size_t isolreceiver;
    215   intptr_t i, n;
    216   int mask = 0; /* Register the parsed attributes */
    217   res_T res = RES_OK;
    218   ASSERT(srcvl && doc && receiver);
    219 
    220   if(receiver->type != YAML_MAPPING_NODE) {
    221     log_err(srcvl, receiver, "expect a receiver definition.\n");
    222     res = RES_BAD_ARG;
    223     goto error;
    224   }
    225 
    226   /* Allocate the receiver */
    227   isolreceiver = darray_receiver_size_get(&srcvl->receivers);
    228   res = darray_receiver_resize(&srcvl->receivers, isolreceiver + 1);
    229   if(res != RES_OK) {
    230     log_err(srcvl, receiver, "could not allocate the receiver.\n");
    231     goto error;
    232   }
    233   solreceiver = darray_receiver_data_get(&srcvl->receivers) + isolreceiver;
    234 
    235   n = receiver->data.mapping.pairs.top - receiver->data.mapping.pairs.start;
    236   FOR_EACH(i, 0, n) {
    237     yaml_node_t* key;
    238     yaml_node_t* val;
    239 
    240     key = yaml_document_get_node(doc, receiver->data.mapping.pairs.start[i].key);
    241     val = yaml_document_get_node(doc, receiver->data.mapping.pairs.start[i].value);
    242     if(key->type != YAML_SCALAR_NODE) {
    243       log_err(srcvl, key, "expect receiver parameters.\n");
    244       res = RES_BAD_ARG;
    245       goto error;
    246     }
    247     #define SETUP_MASK(Flag, Name) {                                           \
    248       if(mask & BIT(Flag)) {                                                   \
    249         log_err(srcvl, key, "the receiver "Name" is already defined.\n");  \
    250         res = RES_BAD_ARG;                                                     \
    251         goto error;                                                            \
    252       }                                                                        \
    253       mask |= BIT(Flag);                                                       \
    254     } (void)0
    255     if(!strcmp((char*)key->data.scalar.value, "name")) {
    256       SETUP_MASK(NAME, "name");
    257       res = parse_string(srcvl, val, &solreceiver->name);
    258     } else if(!strcmp((char*)key->data.scalar.value, "side")) {
    259       SETUP_MASK(SIDE, "side");
    260       res = parse_side(srcvl, val, &solreceiver->side);
    261     } else if(!strcmp((char*)key->data.scalar.value, "per_primitive")) {
    262       SETUP_MASK(PER_PRIMITIVE, "per_primitive");
    263       res = parse_pp_output(srcvl, val, &solreceiver->per_primitive_output);
    264     } else {
    265       log_err(srcvl, key, "unknown receiver parameter `%s'.\n",
    266         key->data.scalar.value);
    267       res = RES_BAD_ARG;
    268     }
    269     if(res != RES_OK) goto error;
    270     #undef SETUP_MASK
    271   }
    272 
    273   if(!(mask & BIT(NAME))) {
    274     log_err(srcvl, receiver, "the receiver name is missing.\n");
    275     res = RES_BAD_ARG;
    276     goto error;
    277   }
    278 
    279 exit:
    280   return res;
    281 error:
    282   if(solreceiver) darray_receiver_pop_back(&srcvl->receivers);
    283   goto exit;
    284 }
    285 
    286 static void
    287 receivers_clear(struct srcvl* srcvl)
    288 {
    289   ASSERT(srcvl);
    290   darray_receiver_clear(&srcvl->receivers);
    291 }
    292 
    293 static void
    294 receivers_release(ref_T* ref)
    295 {
    296   struct srcvl* srcvl;
    297   ASSERT(ref);
    298   srcvl = CONTAINER_OF(ref, struct srcvl, ref);
    299   if(srcvl->parser_is_init) yaml_parser_delete(&srcvl->parser);
    300   str_release(&srcvl->stream_name);
    301   darray_receiver_release(&srcvl->receivers);
    302   MEM_RM(srcvl->allocator, srcvl);
    303 }
    304 
    305 /*******************************************************************************
    306  * Local functions
    307  ******************************************************************************/
    308 res_T
    309 srcvl_create
    310   (struct mem_allocator* allocater, struct srcvl** out_receivers)
    311 {
    312   struct srcvl* srcvl = NULL;
    313   struct mem_allocator* mem_allocator;
    314   res_T res = RES_OK;
    315   ASSERT(out_receivers);
    316 
    317   mem_allocator = allocater ? allocater : &mem_default_allocator;
    318   srcvl = MEM_CALLOC(mem_allocator, 1, sizeof(struct srcvl));
    319   if(!srcvl) {
    320     fprintf(stderr, "Could not allocate the loader of the srcvl.\n");
    321     res = RES_MEM_ERR;
    322     goto error;
    323   }
    324   srcvl->allocator = mem_allocator;
    325   ref_init(&srcvl->ref);
    326   str_init(mem_allocator, &srcvl->stream_name);
    327   darray_receiver_init(mem_allocator, &srcvl->receivers);
    328 
    329 exit:
    330   *out_receivers = srcvl;
    331   return res;
    332 error:
    333   if(srcvl) {
    334     srcvl_ref_put(srcvl);
    335     srcvl = NULL;
    336   }
    337   goto exit;
    338 }
    339 
    340 void
    341 srcvl_ref_get(struct srcvl* srcvl)
    342 {
    343   ASSERT(srcvl);
    344   ref_get(&srcvl->ref);
    345 }
    346 
    347 void
    348 srcvl_ref_put(struct srcvl* srcvl)
    349 {
    350   ASSERT(srcvl);
    351   ref_put(&srcvl->ref, receivers_release);
    352 }
    353 
    354 res_T
    355 srcvl_setup_stream
    356   (struct srcvl* srcvl,
    357    const char* stream_name,
    358    FILE* stream)
    359 {
    360   res_T res = RES_OK;
    361   ASSERT(srcvl && stream);
    362 
    363   if(srcvl->parser_is_init) {
    364     yaml_parser_delete(&srcvl->parser);
    365     srcvl->parser_is_init = 0;
    366   }
    367 
    368   res = str_set(&srcvl->stream_name, stream_name ? stream_name:"<stream>");
    369   if(res != RES_OK) {
    370     fprintf(stderr, "Could not register the filename of the receiver stream.\n");
    371     goto error;
    372   }
    373   if(!yaml_parser_initialize(&srcvl->parser)) {
    374     fprintf(stderr,
    375       "Could not initialise the YAML parser of the receiver stream.\n");
    376     res = RES_UNKNOWN_ERR;
    377     goto error;
    378   }
    379   srcvl->parser_is_init = 1;
    380   yaml_parser_set_input_file(&srcvl->parser, stream);
    381 
    382 exit:
    383   return res;
    384 error:
    385   str_clear(&srcvl->stream_name);
    386   if(srcvl->parser_is_init) {
    387     yaml_parser_delete(&srcvl->parser);
    388     srcvl->parser_is_init = 0;
    389   }
    390   goto exit;
    391 }
    392 
    393 res_T
    394 srcvl_load(struct srcvl* srcvl)
    395 {
    396   yaml_document_t doc;
    397   yaml_node_t* root;
    398   const char* stream_name;
    399   intptr_t i, n;
    400   int doc_is_init = 0;
    401   res_T res = RES_OK;
    402   ASSERT(srcvl);
    403 
    404   stream_name = str_cget(&srcvl->stream_name);
    405   receivers_clear(srcvl); /* Clean up previously loaded data */
    406 
    407   if(!srcvl->parser_is_init) {
    408     res = RES_BAD_OP;
    409     goto error;
    410   }
    411 
    412   if(!yaml_parser_load(&srcvl->parser, &doc)) {
    413     fprintf(stderr, "%s:%lu:%lu: %s.\n",
    414       stream_name,
    415       (unsigned long)srcvl->parser.problem_mark.line+1,
    416       (unsigned long)srcvl->parser.problem_mark.column+1,
    417       srcvl->parser.problem);
    418     yaml_parser_delete(&srcvl->parser);
    419     srcvl->parser_is_init = 0;
    420     res = RES_BAD_OP;
    421     goto error;
    422   }
    423   doc_is_init = 1;
    424 
    425   root = yaml_document_get_root_node(&doc);
    426   if(!root) {
    427     yaml_parser_delete(&srcvl->parser);
    428     srcvl->parser_is_init = 0;
    429     res = RES_BAD_OP;
    430     goto error;
    431   }
    432 
    433   if(root->type != YAML_SEQUENCE_NODE) {
    434     log_err(srcvl, root, "expect a list of srcvl.\n");
    435     res = RES_BAD_ARG;
    436     goto error;
    437   }
    438 
    439   n = root->data.sequence.items.top - root->data.sequence.items.start;
    440   FOR_EACH(i, 0, n) {
    441     yaml_node_t* receiver;
    442 
    443     receiver = yaml_document_get_node(&doc, root->data.sequence.items.start[i]);
    444     res = parse_receiver(srcvl, &doc, receiver);
    445     if(res != RES_OK) goto error;
    446   }
    447 exit:
    448   if(doc_is_init) yaml_document_delete(&doc);
    449   return res;
    450 error:
    451   receivers_clear(srcvl);
    452   goto exit;
    453 }
    454 
    455 size_t
    456 srcvl_count(const struct srcvl* srcvl)
    457 {
    458   ASSERT(srcvl);
    459   return darray_receiver_size_get(&srcvl->receivers);
    460 }
    461 
    462 void
    463 srcvl_get
    464   (const struct srcvl* srcvl,
    465    const size_t i,
    466    struct srcvl_receiver* receiver)
    467 {
    468   const struct receiver* r;
    469   ASSERT(srcvl && receiver && i < srcvl_count(srcvl));
    470   r = darray_receiver_cdata_get(&srcvl->receivers) + i;
    471   receiver->name = str_cget(&r->name);
    472   receiver->side = r->side;
    473   receiver->per_primitive_output = r->per_primitive_output;
    474 }
    475