Creating generic DAL project in .net

I am looking to create generic DAL project in .net/.net core so it can be used for multiple projects like it will act as template etc.

I am right now aiming to use entity framework to suffice this requirement. Our requirements are as below.

  1. Reading ConnectionString, making connection to DB etc should be already setup. We will make minor changes in config file and it should be ready.
  2. Methods should be generic which will work with all DBs upto extent.
  3. We will create a package of this project and use it in other projects

Though I agree it will differ DB to DB and important part is creation of models per DB, but definitely I am not looking for it.

So, I am looking for the path/guidance to start over it. I have following some below links which uses generic repository pattern(But its way of patters not the project).

Entity Framework Core Generic Repository

https://blog.codingmilitia.com/2019/01/16/aspnet-011-from-zero-to-overkill-data-access-with-entity-framework-core

Any help on this appreciated !

How to design a generic RestClient using jersey 2.0.0 version and above?

I want to make a RestClient class using jersey API version 2.0.0 and above, that provides methods for all kinds of HTTP methods like GET/POST/PUT/DELETE and can support all functionalities like uri-parameters, setting cookies etc.

My initial thought is to design certain overridden methods in the class which can support varying type of arguments as shown below and provide one method which aggregates all of the parameters and performs the rest call and return the Generic Response.

method 1:

public Response callServer(Map<String,Object> queryParams, String restEndpointURL){} 

method 2:

public Response callServer(Map<String,Object> queryParams, String restEndpointURL, Cookies cookies){} 

method 3:

private actualCall(Map<String,Object> queryParams, String restEndpointURL, Cookies cookies, ...){     //perform the actual call to the server by making checks on all of the parameters provided by the calling methods     } 

The issue I am facing is in structuring the design of the Class which includes -what parameters should i provide support for other than queryParams,URI params and Cookies -how to validate these arguments in the actualCall

¿Como mostrar un mensaje o alerta en la pagina web desde un Generic Handler?

Hola comunidad espero me puedan ayudar y decirme que estoy haciendo mal o si esto es posible ya que aun no logro mostrar lo que necesito de antemano gracias.

Estoy subiendo un archivo al servidor pero no quiero que realice el postback así que utilizo un fileupload de html un GenericHandler y ajax. La extension ya la valide en el control del fileupload la propiedad accept pero también quiero validar en el generic handler y si la extension no es correcta mostrar un mensaje en una label o una alerta en mi formulario web desde el Generic Handler.

Bueno mi pregunta es: ¿Como mostrar ese mensaje desde el generic handler?

Aqui coloco mi codigo ajax

  $  (".custom-file-input").on("change", function() {             var fileName = $  (this).val().split("\").pop();             $  (this).siblings(".custom-file-label").addClass("selected").html(fileName);              if (fileupload.value != '') {                  $  .ajax({                     url: '/script/GuardarExcel.ashx',                     type: 'POST',                     data: new FormData($  ('form')[0]),                     cache: false,                     contentType: false,                     processData: false,                     success: function() {                                            },                     error: function() {                                           }                 });               }           });
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">   <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>   <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>   <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>  <label id="lblArchivo" class=" labelColor btn btn-primary" style="background-color:#5AAAFF; border-color:#5AAAFF" for="fileupload">seleccione archivo                     <input id="fileupload" type="file" name="fileupload" class="custom-file-input" accept=".xlsx"  />                     </label>

Aquí coloco el código de mi generic handler

 public void ProcessRequest(HttpContext context)     {          if (context.Request.Files.Count > 0)         {             //Fetch the Uploaded File.             HttpPostedFile postedFile = context.Request.Files[0];                string fileName = Path.GetFileName(postedFile.FileName);             string fileExtension = Path.GetExtension(postedFile.FileName).ToLower();              if (fileExtension == ".xlsx") // Compruebo que la extension sea la correcta             {                  string folderPath = context.Server.MapPath("~/Excel_Archivos/" + fileName);                 context.Session["folderPath"] = folderPath;                   postedFile.SaveAs(folderPath);               }             else // Aqui quiero mostrar el mensaje en caso de que la extension no sea la correcta pero no logro mostrar nada.             {                  StringBuilder sb = new StringBuilder();                 sb.Append("<body>");                 sb.Append("Error de archivo");                                     sb.Append("</body>");                  context.Response.ContentType = "text/html";               }          }     }      public bool IsReusable     {         get         {             return false;         }     } 

How to design generic bug-tracker integration?

I’m looking for ideas on how to design a “generic” bug-tracker integration architecture for Kiwi TCMS (opensource test case management system).

Background: at the moment we support integration with several systems: Bugzilla, JIRA, GitHub and GitLab. Behaviours are: – link existing bugs to test cases/test executions – add comments to existing bugs when TE fails – create new bugs from a TE (semi-automatically now) – display a link to open all reported bugs in a list format (if supported by the other system)

Other features required: – fully automatic creation of new bugs on failure – richer display of information from bug-tracker inside Kiwi TCMS.

Currently we have an interface class which defines the entry points to these actions and then separate implementation for every one of the 3rd party systems. This also means different settings for them and different 3rd party libraries we need to ship in our code.

This also means whenever somebody requests a different system we don’t have a ready solution.

For systems which ship multiple versions, e.g. Jira, some of the API may not be compatible with the current version of the library we’re using.

I am looking for something that will make it possible to integrate more easily with anything out there (in terms of link & display) b/c this is what most people use. Maybe Open Graph Protocol will help us here although none of the systems seems to support it (except GitHub).

Then for comments and auto creation I’m thinking webhooks but not really sure how to define anything else. 3rd party systems can be vastly different from one another, the list of required fields is also different. So while it is easier to just execute a web-hook I have no idea how to let the user properly configure its payload. There can be also the case where you need to make several HTTP calls (e.g. login, create, add/update) to complete the operation.

Ultimately I’d like to make this part of the software easier on the maintainers and also a bit easier for admins who would need to integrate these 3rd party systems with our software.

What do you reckon ? Has anyone done something similar for a web app?

Generic Macro Generated Interval Heap in C

When I saw this amazing data structure I couldn’t stop myself from trying it! I first sought resources such as this and an article about it here. It basically works as a Max-Heap and a Min-Heap at the same time. I was heavily based on these amazing Java implementations here and here.

This implementation is a macro that generates code for whichever data type you wish to work with and it is part of the C Macro Collections library currently hosted on GitHub and further to be improved when needed.

The main macro is INTERVALHEAP_GENERATE with the following parameters:

  • PFX – Functions prefix
  • SNAME – The struct name
  • FMOD – Function modifier (currently only static or empty)
  • V – Data type you wish to work with

All you need to get started is the header intervalheap.h. Now since a question is limited to 65536 characters I had to strip down a lot of code and lines so that it could fit in this question since the macro takes a lot of characters. The code might seem a bit squished together but you can find the original code (and maybe in the future, updated) here.

intervalheap.h

#ifndef CMC_INTERVALHEAP_H #define CMC_INTERVALHEAP_H  #include <stdlib.h> #include <stdbool.h> #include <string.h>  #define INTERVALHEAP_GENERATE(PFX, SNAME, FMOD, V)    \     INTERVALHEAP_GENERATE_HEADER(PFX, SNAME, FMOD, V) \     INTERVALHEAP_GENERATE_SOURCE(PFX, SNAME, FMOD, V)  /* HEADER ********************************************************************/ #define INTERVALHEAP_GENERATE_HEADER(PFX, SNAME, FMOD, V)                    \                                                                              \     /* Heap Structure */                                                     \     typedef struct SNAME##_s                                                 \     {                                                                        \         /* Dynamic array of nodes */                                         \         struct SNAME##_node_s *buffer;                                       \         /* Current array capacity (how many nodes can be stored) */          \         size_t capacity;                                                     \         /* Current amount of nodes in the dynamic array */                   \         size_t size;                                                         \         /* Current amount of elements in the heap */                         \         size_t count;                                                        \         /* Element comparison function */                                    \         int (*cmp)(V, V);                                                    \         /* Function that returns an iterator to the start of the heap */     \         struct SNAME##_iter_s (*it_start)(struct SNAME##_s *);               \         /* Function that returns an iterator to the end of the heap */       \         struct SNAME##_iter_s (*it_end)(struct SNAME##_s *);                 \     } SNAME, *SNAME##_ptr;                                                   \                                                                              \     /* Heap Node */                                                          \     typedef struct SNAME##_node_s                                            \     {                                                                        \         /* 0 - Value belonging to the MinHeap */                             \         /* 1 - Value belonging to the MaxHeap */                             \         V data[2];                                                           \     } SNAME##_node, *SNAME##_node_ptr;                                       \                                                                              \     /* Heap Iterator */                                                      \     typedef struct SNAME##_iter_s                                            \     {                                                                        \         /* Target heap */                                                    \         struct SNAME##_s *target;                                            \         /* Cursor's position (index) */                                      \         size_t cursor;                                                       \         /* If the iterator has reached the start of the iteration */         \         bool start;                                                          \         /* If the iterator has reached the end of the iteration */           \         bool end;                                                            \     } SNAME##_iter, *SNAME##_iter_ptr;                                       \                                                                              \     FMOD SNAME *PFX##_new(size_t capacity, int (*compare)(V, V));            \     FMOD void PFX##_clear(SNAME *_heap_);                                    \     FMOD void PFX##_free(SNAME *_heap_);                                     \     FMOD bool PFX##_insert(SNAME *_heap_, V element);                        \     FMOD bool PFX##_remove_max(SNAME *_heap_, V *result);                    \     FMOD bool PFX##_remove_min(SNAME *_heap_, V *result);                    \     FMOD bool PFX##_insert_if(SNAME *_heap_, V element, bool condition);     \     FMOD bool PFX##_remove_max_if(SNAME *_heap_, V *result, bool condition); \     FMOD bool PFX##_remove_min_if(SNAME *_heap_, V *result, bool condition); \     FMOD bool PFX##_update_max(SNAME *_heap_, V element);                    \     FMOD bool PFX##_update_min(SNAME *_heap_, V element);                    \     FMOD bool PFX##_max(SNAME *_heap_, V *value);                            \     FMOD bool PFX##_min(SNAME *_heap_, V *value);                            \     FMOD bool PFX##_contains(SNAME *_heap_, V element);                      \     FMOD bool PFX##_empty(SNAME *_heap_);                                    \     FMOD bool PFX##_full(SNAME *_heap_);                                     \     FMOD size_t PFX##_count(SNAME *_heap_);                                  \     FMOD size_t PFX##_capacity(SNAME *_heap_);                               \                                                                              \     FMOD SNAME##_iter *PFX##_iter_new(SNAME *target);                        \     FMOD void PFX##_iter_free(SNAME##_iter *iter);                           \     FMOD void PFX##_iter_init(SNAME##_iter *iter, SNAME *target);            \     FMOD bool PFX##_iter_start(SNAME##_iter *iter);                          \     FMOD bool PFX##_iter_end(SNAME##_iter *iter);                            \     FMOD void PFX##_iter_to_start(SNAME##_iter *iter);                       \     FMOD void PFX##_iter_to_end(SNAME##_iter *iter);                         \     FMOD bool PFX##_iter_next(SNAME##_iter *iter);                           \     FMOD bool PFX##_iter_prev(SNAME##_iter *iter);                           \     FMOD V PFX##_iter_value(SNAME##_iter *iter);                             \     FMOD size_t PFX##_iter_index(SNAME##_iter *iter);                        \                                                                              \     /* Default Value */                                                      \     static inline V PFX##_impl_default_value(void)                           \     {                                                                        \         V _empty_value_;                                                     \                                                                              \         memset(&_empty_value_, 0, sizeof(V));                                \                                                                              \         return _empty_value_;                                                \     }  #define INTERVALHEAP_GENERATE_SOURCE(PFX, SNAME, FMOD, V)                                   \                                                                                             \     /* Implementation Detail Functions */                                                   \     static bool PFX##_impl_grow(SNAME *_heap_);                                             \     static void PFX##_impl_float_up_max(SNAME *_heap_);                                     \     static void PFX##_impl_float_up_min(SNAME *_heap_);                                     \     static void PFX##_impl_float_down_max(SNAME *_heap_);                                   \     static void PFX##_impl_float_down_min(SNAME *_heap_);                                   \     static SNAME##_iter PFX##_impl_it_start(SNAME *_heap_);                                 \     static SNAME##_iter PFX##_impl_it_end(SNAME *_heap_);                                   \                                                                                             \     FMOD SNAME *PFX##_new(size_t capacity, int (*compare)(V, V))                            \     {                                                                                       \         SNAME *_heap_ = malloc(sizeof(SNAME));                                              \         if (!_heap_)                                                                        \             return NULL;                                                                    \                                                                                             \         /* Since each node can store two elements, divide the actual capacity by 2 */       \         /* Round the capacity of nodes up */                                                \         capacity = capacity % 2 == 0 ? capacity / 2 : (capacity + 1) / 2;                   \         _heap_->buffer = malloc(sizeof(SNAME##_node) * capacity);                           \                                                                                             \         if (!_heap_->buffer)                                                                \         {                                                                                   \             free(_heap_);                                                                   \             return NULL;                                                                    \         }                                                                                   \         memset(_heap_->buffer, 0, sizeof(SNAME##_node) * capacity);                         \         _heap_->capacity = capacity;                                                        \         _heap_->size = 0;                                                                   \         _heap_->count = 0;                                                                  \         _heap_->cmp = compare;                                                              \         _heap_->it_start = PFX##_impl_it_start;                                             \         _heap_->it_end = PFX##_impl_it_end;                                                 \         return _heap_;                                                                      \     }                                                                                       \                                                                                             \     FMOD void PFX##_clear(SNAME *_heap_)                                                    \     {                                                                                       \         memset(_heap_->buffer, 0, sizeof(V) * _heap_->capacity);                            \         _heap_->size = 0;                                                                   \         _heap_->count = 0;                                                                  \     }                                                                                       \                                                                                             \     FMOD void PFX##_free(SNAME *_heap_)                                                     \     {                                                                                       \         free(_heap_->buffer);                                                               \         free(_heap_);                                                                       \     }                                                                                       \                                                                                             \     FMOD bool PFX##_insert(SNAME *_heap_, V element)                                        \     {                                                                                       \         if (PFX##_full(_heap_))                                                             \         {                                                                                   \             if (!PFX##_impl_grow(_heap_))                                                   \                 return false;                                                               \         }                                                                                   \                                                                                             \         if (PFX##_count(_heap_) % 2 == 0)                                                   \         {                                                                                   \             /* Occupying a new node */                                                      \             _heap_->buffer[_heap_->size].data[0] = element;                                 \             _heap_->buffer[_heap_->size].data[1] = PFX##_impl_default_value();              \                                                                                             \             _heap_->size++;                                                                 \         }                                                                                   \         else                                                                                \         {                                                                                   \             SNAME##_node *curr_node = &(_heap_->buffer[_heap_->size - 1]);                  \                                                                                             \             if (_heap_->cmp(curr_node->data[0], element) > 0)                               \             {                                                                               \                 curr_node->data[1] = curr_node->data[0];                                    \                 curr_node->data[0] = element;                                               \             }                                                                               \             else                                                                            \             {                                                                               \                 curr_node->data[1] = element;                                               \             }                                                                               \         }                                                                                   \                                                                                             \         _heap_->count++;                                                                    \                                                                                             \         if (PFX##_count(_heap_) <= 2)                                                       \             return true;                                                                    \                                                                                             \         SNAME##_node *parent = &(_heap_->buffer[(_heap_->size - 1) / 2]);                   \                                                                                             \         if (_heap_->cmp(parent->data[0], element) > 0)                                      \             PFX##_impl_float_up_min(_heap_);                                                \         else if (_heap_->cmp(parent->data[1], element) < 0)                                 \             PFX##_impl_float_up_max(_heap_);                                                \                                                                                             \         return true;                                                                        \     }                                                                                       \                                                                                             \     FMOD bool PFX##_remove_max(SNAME *_heap_, V *result)                                    \     {                                                                                       \         if (PFX##_empty(_heap_))                                                            \             return false;                                                                   \                                                                                             \         if (PFX##_count(_heap_) == 1)                                                       \         {                                                                                   \             *result = _heap_->buffer[0].data[0];                                            \             _heap_->buffer[0].data[0] = PFX##_impl_default_value();                         \             _heap_->count--;                                                                \             return true;                                                                    \         }                                                                                   \         else                                                                                \             *result = _heap_->buffer[0].data[1];                                            \                                                                                             \         SNAME##_node *last_node = &(_heap_->buffer[_heap_->size - 1]);                      \                                                                                             \         if (PFX##_count(_heap_) % 2 == 1)                                                   \         {                                                                                   \             _heap_->buffer[0].data[1] = last_node->data[0];                                 \             last_node->data[0] = PFX##_impl_default_value();                                \             _heap_->size--;                                                                 \         }                                                                                   \         else                                                                                \         {                                                                                   \             _heap_->buffer[0].data[1] = last_node->data[1];                                 \                                                                                             \             last_node->data[1] = PFX##_impl_default_value();                                \         }                                                                                   \                                                                                             \         _heap_->count--;                                                                    \                                                                                             \         PFX##_impl_float_down_max(_heap_);                                                  \                                                                                             \         return true;                                                                        \     }                                                                                       \                                                                                             \     FMOD bool PFX##_remove_min(SNAME *_heap_, V *result)                                    \     {                                                                                       \         if (PFX##_empty(_heap_))                                                            \             return false;                                                                   \                                                                                             \         *result = _heap_->buffer[0].data[0];                                                \                                                                                             \         if (PFX##_count(_heap_) == 1)                                                       \         {                                                                                   \             _heap_->buffer[0].data[0] = PFX##_impl_default_value();                         \                                                                                             \             _heap_->count--;                                                                \                                                                                             \             return true;                                                                    \         }                                                                                   \                                                                                             \         SNAME##_node *last_node = &(_heap_->buffer[_heap_->size - 1]);                      \                                                                                             \         _heap_->buffer[0].data[0] = last_node->data[0];                                     \                                                                                             \         if (PFX##_count(_heap_) % 2 == 1)                                                   \         {                                                                                   \             last_node->data[0] = PFX##_impl_default_value();                                \                                                                                             \             _heap_->size--;                                                                 \         }                                                                                   \         else                                                                                \         {                                                                                   \             last_node->data[0] = last_node->data[1];                                        \             last_node->data[1] = PFX##_impl_default_value();                                \         }                                                                                   \                                                                                             \         _heap_->count--;                                                                    \                                                                                             \         PFX##_impl_float_down_min(_heap_);                                                  \                                                                                             \         return true;                                                                        \     }                                                                                       \                                                                                             \     FMOD bool PFX##_insert_if(SNAME *_heap_, V element, bool condition)                     \     {                                                                                       \         if (condition)                                                                      \             return PFX##_insert(_heap_, element);                                           \                                                                                             \         return false;                                                                       \     }                                                                                       \                                                                                             \     FMOD bool PFX##_remove_max_if(SNAME *_heap_, V *result, bool condition)                 \     {                                                                                       \         if (condition)                                                                      \             return PFX##_remove_max(_heap_, result);                                        \                                                                                             \         return false;                                                                       \     }                                                                                       \                                                                                             \     FMOD bool PFX##_remove_min_if(SNAME *_heap_, V *result, bool condition)                 \     {                                                                                       \         if (condition)                                                                      \             return PFX##_remove_min(_heap_, result);                                        \                                                                                             \         return false;                                                                       \     }                                                                                       \                                                                                             \     FMOD bool PFX##_update_max(SNAME *_heap_, V element)                                    \     {                                                                                       \         if (PFX##_empty(_heap_))                                                            \             return false;                                                                   \                                                                                             \         if (PFX##_count(_heap_) == 1)                                                       \         {                                                                                   \             _heap_->buffer[0].data[0] = element;                                            \         }                                                                                   \         else if (_heap_->cmp(element, _heap_->buffer[0].data[0]) < 0)                       \         {                                                                                   \             _heap_->buffer[0].data[1] = _heap_->buffer[0].data[0];                          \             _heap_->buffer[0].data[0] = element;                                            \                                                                                             \             PFX##_impl_float_down_max(_heap_);                                              \         }                                                                                   \         else                                                                                \         {                                                                                   \             _heap_->buffer[0].data[1] = element;                                            \                                                                                             \             PFX##_impl_float_down_max(_heap_);                                              \         }                                                                                   \                                                                                             \         return true;                                                                        \     }                                                                                       \                                                                                             \     FMOD bool PFX##_update_min(SNAME *_heap_, V element)                                    \     {                                                                                       \         if (PFX##_empty(_heap_))                                                            \             return false;                                                                   \                                                                                             \         if (PFX##_count(_heap_) == 1)                                                       \         {                                                                                   \             _heap_->buffer[0].data[0] = element;                                            \         }                                                                                   \         else if (_heap_->cmp(element, _heap_->buffer[0].data[1]) > 0)                       \         {                                                                                   \             _heap_->buffer[0].data[0] = _heap_->buffer[0].data[1];                          \             _heap_->buffer[0].data[1] = element;                                            \                                                                                             \             PFX##_impl_float_down_min(_heap_);                                              \         }                                                                                   \         else                                                                                \         {                                                                                   \             _heap_->buffer[0].data[0] = element;                                            \                                                                                             \             PFX##_impl_float_down_min(_heap_);                                              \         }                                                                                   \                                                                                             \         return true;                                                                        \     }                                                                                       \                                                                                             \     FMOD bool PFX##_max(SNAME *_heap_, V *value)                                            \     {                                                                                       \         if (PFX##_empty(_heap_))                                                            \             return false;                                                                   \                                                                                             \         if (PFX##_count(_heap_) == 1)                                                       \             *value = _heap_->buffer[0].data[0];                                             \         else                                                                                \             *value = _heap_->buffer[0].data[1];                                             \                                                                                             \         return true;                                                                        \     }                                                                                       \                                                                                             \     FMOD bool PFX##_min(SNAME *_heap_, V *value)                                            \     {                                                                                       \         if (PFX##_empty(_heap_))                                                            \             return false;                                                                   \                                                                                             \         *value = _heap_->buffer[0].data[0];                                                 \                                                                                             \         return true;                                                                        \     }                                                                                       \                                                                                             \     FMOD bool PFX##_contains(SNAME *_heap_, V element)                                      \     {                                                                                       \         for (size_t i = 0; i < _heap_->count; i++)                                          \         {                                                                                   \             if (_heap_->cmp(_heap_->buffer[i / 2].data[i % 2], element) == 0)               \                 return true;                                                                \         }                                                                                   \                                                                                             \         return false;                                                                       \     }                                                                                       \                                                                                             \     FMOD bool PFX##_empty(SNAME *_heap_)                                                    \     {                                                                                       \         return _heap_->count == 0;                                                          \     }                                                                                       \                                                                                             \     FMOD bool PFX##_full(SNAME *_heap_)                                                     \     {                                                                                       \         /* The heap is full if all nodes are completely filled */                           \         return _heap_->size >= _heap_->capacity && _heap_->count % 2 == 0;                  \     }                                                                                       \                                                                                             \     FMOD size_t PFX##_count(SNAME *_heap_)                                                  \     {                                                                                       \         return _heap_->count;                                                               \     }                                                                                       \                                                                                             \     FMOD size_t PFX##_capacity(SNAME *_heap_)                                               \     {                                                                                       \         /* Multiply by 2 since each node can store two elements */                          \         return _heap_->capacity * 2;                                                        \     }                                                                                       \                                                                                             \     FMOD SNAME##_iter *PFX##_iter_new(SNAME *target)                                        \     {                                                                                       \         SNAME##_iter *iter = malloc(sizeof(SNAME##_iter));                                  \                                                                                             \         if (!iter)                                                                          \             return NULL;                                                                    \                                                                                             \         PFX##_iter_init(iter, target);                                                      \                                                                                             \         return iter;                                                                        \     }                                                                                       \                                                                                             \     FMOD void PFX##_iter_free(SNAME##_iter *iter)                                           \     {                                                                                       \         free(iter);                                                                         \     }                                                                                       \                                                                                             \     FMOD void PFX##_iter_init(SNAME##_iter *iter, SNAME *target)                            \     {                                                                                       \         iter->target = target;                                                              \         iter->cursor = 0;                                                                   \         iter->start = true;                                                                 \         iter->end = PFX##_empty(target);                                                    \     }                                                                                       \                                                                                             \     FMOD bool PFX##_iter_start(SNAME##_iter *iter)                                          \     {                                                                                       \         return PFX##_empty(iter->target) || iter->start;                                    \     }                                                                                       \                                                                                             \     FMOD bool PFX##_iter_end(SNAME##_iter *iter)                                            \     {                                                                                       \         return PFX##_empty(iter->target) || iter->end;                                      \     }                                                                                       \                                                                                             \     FMOD void PFX##_iter_to_start(SNAME##_iter *iter)                                       \     {                                                                                       \         iter->cursor = 0;                                                                   \         iter->start = true;                                                                 \         iter->end = PFX##_empty(iter->target);                                              \     }                                                                                       \                                                                                             \     FMOD void PFX##_iter_to_end(SNAME##_iter *iter)                                         \     {                                                                                       \         iter->cursor = iter->target->count - 1;                                             \         iter->start = PFX##_empty(iter->target);                                            \         iter->end = true;                                                                   \     }                                                                                       \                                                                                             \     FMOD bool PFX##_iter_next(SNAME##_iter *iter)                                           \     {                                                                                       \         if (iter->end)                                                                      \             return false;                                                                   \                                                                                             \         iter->start = false;                                                                \                                                                                             \         if (iter->cursor == iter->target->count - 1)                                        \             iter->end = true;                                                               \         else                                                                                \             iter->cursor++;                                                                 \                                                                                             \         return true;                                                                        \     }                                                                                       \                                                                                             \     FMOD bool PFX##_iter_prev(SNAME##_iter *iter)                                           \     {                                                                                       \         if (iter->start)                                                                    \             return false;                                                                   \                                                                                             \         iter->end = false;                                                                  \                                                                                             \         if (iter->cursor == 0)                                                              \             iter->start = true;                                                             \         else                                                                                \             iter->cursor--;                                                                 \                                                                                             \         return true;                                                                        \     }                                                                                       \                                                                                             \     FMOD V PFX##_iter_value(SNAME##_iter *iter)                                             \     {                                                                                       \         if (PFX##_empty(iter->target))                                                      \             return PFX##_impl_default_value();                                              \                                                                                             \         return iter->target->buffer[iter->cursor / 2].data[iter->cursor % 2];               \     }                                                                                       \                                                                                             \     FMOD size_t PFX##_iter_index(SNAME##_iter *iter)                                        \     {                                                                                       \         return iter->cursor;                                                                \     }                                                                                       \                                                                                             \     static bool PFX##_impl_grow(SNAME *_heap_)                                              \     {                                                                                       \         size_t new_cap = _heap_->capacity * 2;                                              \                                                                                             \         SNAME##_node *new_buffer = realloc(_heap_->buffer, sizeof(SNAME##_node) * new_cap); \                                                                                             \         if (!new_buffer)                                                                    \             return false;                                                                   \                                                                                             \         memset(new_buffer + _heap_->capacity, 0, sizeof(SNAME##_node) * _heap_->capacity);  \                                                                                             \         _heap_->buffer = new_buffer;                                                        \         _heap_->capacity = new_cap;                                                         \                                                                                             \         return true;                                                                        \     }                                                                                       \                                                                                             \     static void PFX##_impl_float_up_max(SNAME *_heap_)                                      \     {                                                                                       \         size_t index = _heap_->size - 1;                                                    \                                                                                             \         SNAME##_node *curr_node = &(_heap_->buffer[index]);                                 \                                                                                             \         while (index > 0)                                                                   \         {                                                                                   \             /* Parent index */                                                              \             size_t P_index = (index - 1) / 2;                                               \                                                                                             \             SNAME##_node *parent = &(_heap_->buffer[P_index]);                              \                                                                                             \             if (index == _heap_->size - 1 && PFX##_count(_heap_) % 2 != 0)                  \             {                                                                               \                 if (_heap_->cmp(curr_node->data[0], parent->data[1]) < 0)                   \                     break;                                                                  \                                                                                             \                 V tmp = curr_node->data[0];                                                 \                 curr_node->data[0] = parent->data[1];                                       \                 parent->data[1] = tmp;                                                      \             }                                                                               \             else                                                                            \             {                                                                               \                 if (_heap_->cmp(curr_node->data[1], parent->data[1]) < 0)                   \                     break;                                                                  \                                                                                             \                 V tmp = curr_node->data[1];                                                 \                 curr_node->data[1] = parent->data[1];                                       \                 parent->data[1] = tmp;                                                      \             }                                                                               \                                                                                             \             index = P_index;                                                                \             curr_node = parent;                                                             \         }                                                                                   \     }                                                                                       \                                                                                             \     static void PFX##_impl_float_up_min(SNAME *_heap_)                                      \     {                                                                                       \         size_t index = _heap_->size - 1;                                                    \         SNAME##_node *curr_node = &(_heap_->buffer[index]);                                 \                                                                                             \         while (index > 0)                                                                   \         {                                                                                   \             size_t P_index = (index - 1) / 2;                                               \             SNAME##_node *parent = &(_heap_->buffer[P_index]);                              \                                                                                             \             if (_heap_->cmp(curr_node->data[0], parent->data[0]) >= 0)                      \                 break;                                                                      \                                                                                             \             V tmp = curr_node->data[0];                                                     \             curr_node->data[0] = parent->data[0];                                           \             parent->data[0] = tmp;                                                          \             index = P_index;                                                                \             curr_node = parent;                                                             \         }                                                                                   \     }                                                                                       \                                                                                             \     static void PFX##_impl_float_down_max(SNAME *_heap_)                                    \     {                                                                                       \         size_t index = 0;                                                                   \         SNAME##_node *curr_node = &(_heap_->buffer[index]);                                 \                                                                                             \         while (true)                                                                        \         {                                                                                   \             if (2 * index + 1 >= _heap_->size)                                              \                 break;                                                                      \                                                                                             \             size_t child;                                                                   \             size_t L_index = index * 2 + 1;                                                 \             size_t R_index = index * 2 + 2;                                                 \                                                                                             \             if (R_index < _heap_->size)                                                     \             {                                                                               \                 SNAME##_node *L = &(_heap_->buffer[L_index]);                               \                 SNAME##_node *R = &(_heap_->buffer[R_index]);                               \                                                                                             \                 if (R_index == _heap_->size - 1 && PFX##_count(_heap_) % 2 != 0)            \                     child = _heap_->cmp(L->data[1], R->data[0]) > 0 ? L_index : R_index;    \                 else                                                                        \                     child = _heap_->cmp(L->data[1], R->data[1]) > 0 ? L_index : R_index;    \             }                                                                               \             else                                                                            \                 child = L_index;                                                            \                                                                                             \             SNAME##_node *child_node = &(_heap_->buffer[child]);                            \                                                                                             \             if (child == _heap_->size - 1 && PFX##_count(_heap_) % 2 != 0)                  \             {                                                                               \                 if (_heap_->cmp(curr_node->data[1], child_node->data[0]) >= 0)              \                     break;                                                                  \                                                                                             \                 V tmp = child_node->data[0];                                                \                 child_node->data[0] = curr_node->data[1];                                   \                 curr_node->data[1] = tmp;                                                   \             }                                                                               \             else                                                                            \             {                                                                               \                 if (_heap_->cmp(curr_node->data[1], child_node->data[1]) >= 0)              \                     break;                                                                  \                                                                                             \                 V tmp = child_node->data[1];                                                \                 child_node->data[1] = curr_node->data[1];                                   \                 curr_node->data[1] = tmp;                                                   \                                                                                             \                 if (_heap_->cmp(child_node->data[0], child_node->data[1]) > 0)              \                 {                                                                           \                     tmp = child_node->data[0];                                              \                     child_node->data[0] = child_node->data[1];                              \                     child_node->data[1] = tmp;                                              \                 }                                                                           \             }                                                                               \             index = child;                                                                  \             curr_node = child_node;                                                         \         }                                                                                   \     }                                                                                       \                                                                                             \     static void PFX##_impl_float_down_min(SNAME *_heap_)                                    \     {                                                                                       \         size_t index = 0;                                                                   \                                                                                             \         SNAME##_node *curr_node = &(_heap_->buffer[index]);                                 \                                                                                             \         while (true)                                                                        \         {                                                                                   \             if (2 * index + 1 >= _heap_->size)                                              \                 break;                                                                      \                                                                                             \             size_t child;                                                                   \             size_t L_index = index * 2 + 1;                                                 \             size_t R_index = index * 2 + 2;                                                 \                                                                                             \             if (R_index < _heap_->size)                                                     \             {                                                                               \                 SNAME##_node *L = &(_heap_->buffer[L_index]);                               \                 SNAME##_node *R = &(_heap_->buffer[R_index]);                               \                 child = _heap_->cmp(L->data[0], R->data[0]) < 0 ? L_index : R_index;        \             }                                                                               \             else                                                                            \                 child = L_index;                                                            \                                                                                             \             SNAME##_node *child_node = &(_heap_->buffer[child]);                            \                                                                                             \             if (_heap_->cmp(curr_node->data[0], child_node->data[0]) < 0)                   \                 break;                                                                      \                                                                                             \             V tmp = child_node->data[0];                                                    \             child_node->data[0] = curr_node->data[0];                                       \             curr_node->data[0] = tmp;                                                       \                                                                                             \             if (child != _heap_->size - 1 || PFX##_count(_heap_) % 2 == 0)                  \             {                                                                               \                 if (_heap_->cmp(child_node->data[0], child_node->data[1]) > 0)              \                 {                                                                           \                     tmp = child_node->data[0];                                              \                     child_node->data[0] = child_node->data[1];                              \                     child_node->data[1] = tmp;                                              \                 }                                                                           \             }                                                                               \             index = child;                                                                  \             curr_node = child_node;                                                         \         }                                                                                   \     }                                                                                       \                                                                                             \     static SNAME##_iter PFX##_impl_it_start(SNAME *_heap_)                                  \     {                                                                                       \         SNAME##_iter iter;                                                                  \         PFX##_iter_init(&iter, _heap_);                                                     \         PFX##_iter_to_start(&iter);                                                         \         return iter;                                                                        \     }                                                                                       \                                                                                             \     static SNAME##_iter PFX##_impl_it_end(SNAME *_heap_)                                    \     {                                                                                       \         SNAME##_iter iter;                                                                  \         PFX##_iter_init(&iter, _heap_);                                                     \         PFX##_iter_to_end(&iter);                                                           \         return iter;                                                                        \     }  #endif /* CMC_INTERVALHEAP_H */ 

test.c

#include "intervalheap.h" #include <stdio.h>  /* Generate the Interval Heap */ INTERVALHEAP_GENERATE(h, heap, , int)  /* Comparison function */ int intcmp(int a, int b) {     return (a > b) - (a < b); }  #define TOTAL 100  int main(void) {     heap *my_heap = h_new(50, intcmp);      for (size_t i = 1; i <= TOTAL; i++)     {         h_insert(my_heap, i);     }      size_t half = h_count(my_heap) / 2;      for (size_t i = 0; !h_empty(my_heap); i++)     {         int r;          i < half ? h_remove_max(my_heap, &r) : h_remove_min(my_heap, &r);          printf("%d ", r);     }      h_free(my_heap);      return 0; } 

Policy based generic Adc monitor/notifier

I’ve tried to make a generic class that reads an Adc value and, depending on the policies of the class, notify its observers when either the value is too high and or too low.

Most of our objects are Subjects or Observers and for this specific implementation I was looking for a generic way to make make it only one subject or two subjects depending on whether the policy is to raise an event when the value is too low or high (or both).

I personally am not happy with how the code turned out with the fact that I need too specific functions (NotifyIfAboveLimit and NotifyIfBelowLimit) and thus two separate policies for the greater/lesser versions. Since they both have the same implementation (only a differing comparator) I extracted the functionality to a base policy class for both verions.

I am mostly looking on critique/comments on the naming of the policies and on whether I can provide only one policy and not with the current version having two implementations.

I’ve redacted the non-stl includes.

I have chosen to make the policies themselves a Subject because that way if there is no policy for lower than or higher than then that Subject is not valid and can and should never raise a notify so it makes no sense to make it a Subject for that condition.

That’s also why the FeedbackLoopMonitor publicly inherits from the policies because other Observers might want to Attach to the FeedbackLoopMonitor’s Subject’s.

FeedbackLoopMonitor.h:

#include <cstdint> #include <functional>  namespace ApplicationLayer {     template <std::uint16_t Limit, typename Event, typename Compare>     class LimitPolicy : public Common::Subject<Event>     {     protected:         void NotifyIfLimitExceeded(std::uint16_t value)         {             if (Compare()(value, Limit) == true)             {                 Notify(Event());             }         }     };      template <std::uint16_t Limit, typename Event, typename Compare = std::greater<std::uint16_t>>     class GreaterLimitPolicy : public LimitPolicy<Limit, Event, Compare>     {     protected:         void NotifyIfAboveLimit(std::uint16_t value)         {             NotifyIfLimitExceeded(value);         }     };      class NoGreaterLimitPolicy     {     protected:         void NotifyIfAboveLimit(std::uint16_t value)         {         }     };      template <std::uint16_t Limit, typename Event, typename Compare = std::less<std::uint16_t>>     class LessLimitPolicy : public LimitPolicy<Limit, Event, Compare>     {     protected:         void NotifyIfBelowLimit(std::uint16_t value)         {             NotifyIfLimitExceeded(value);         }     };      class NoLessLimitPolicy     {     protected:         void NotifyIfBelowLimit(std::uint16_t value)         {         }     };      template <typename LimitPolicyLess = NoLessLimitPolicy, typename LimitPolicyGreater = NoGreaterLimitPolicy>     class FeedbackLoopMonitor         : public LimitPolicyLess         , public LimitPolicyGreater         , private Event     {     public:         FeedbackLoopMonitor(PeripheralLayer::FeedbackLoop& feedbackLoop)             : adcFeedbackLoop(feedbackLoop)         {             Queue();         }      private:         virtual void Execute() override         {             auto value = adcFeedbackLoop.GetMeasurement();              NotifyIfBelowLimit(value);             NotifyIfAboveLimit(value);              Queue();         }          PeripheralLayer::FeedbackLoop& adcFeedbackLoop;     };      /* Specialization to catch useless instances of a FeedbackLoopMonitor.      * This specialization can't be constructed since it has a private constructor. */     template <>     class FeedbackLoopMonitor<NoLessLimitPolicy, NoGreaterLimitPolicy>     {         FeedbackLoopMonitor(PeripheralLayer::FeedbackLoop& feedbackLoop);     }; } 

What 5E published adventures have generic optional rules sections usable outside the adventure?

I just learned that Ghosts of Saltmarsh apparently has a section called “Of Ships and the Sea”, presumably developed from the Unearthed Arcana of the same name. I generally don’t buy adventure books unless I’m planning to run that actual adventure — but it occurs to me that these rules might come in handy should my players in a different game decide to venture into the ocean. I learned about this because I happened across a review:

But it also has just as much info on how to navigate the sea according to 5e rules, the dangers that await, weather conditions and health issues, the creatures that inhabit it, and all the mechanics in-between. If you’re a DM and you want to create an adventure in the ocean, D&D just gave you every tool you’ll ever need to make it happen on your own terms. That’s one hell of an addition to the game that a lot of people who deal with seaside adventures will gladly take advantage of.

This seems pretty significant — in previous editions this might have been a section of the Dungeon Master’s Guide, or a DMG II, or a book specifically for adventuring in a that type of environment. This time around, it seems like they’re tying the publishing of this kind of rules expansion to adventure hardcovers.

So, this has me wondering. What other adventures published for 5E by WotC have significant rule sections like this? I don’t mean lists of magic items or monsters, but specific rules that might be useful in any campaign. Or, perhaps, what’s an easy way to find all such possible rules without looking through every published adventure, or just knowing?

Generic data structures in C

I’m new to C, and I thought a great way to learn would be to implement some generic data structures and algorithms. So far I’ve implemented a linked list and a dynamic array. Both are generic, the linked list with void*s and the dynamic array with macros. Both have some straightforward tests in Unity. Both compile with no warnings with the flags:

-std=c89 -ansi -pedantic

Let me know what you think!

dynamic_array.h

/*  * A generic dynamic array implemented from scratch in C89.  *  * Define a dynamic array through the macro 'DEFINE_DYNAMIC_ARRAY(T)'. Put this  * in your code to define a dynamic array called 'DynamicArray_T' that holds  * type 'T'. For example: 'DEFINE_DYNAMIC_ARRAY(float)' will define a dynamic  * array called 'DynamicArray_float' that holds floats. This macro will also  * define all the dynamic array operations as well. These include:  *   - dynamic_array_T_construct(~)  *   - dynamic_array_T_destruct(~)  *   - dynamic_array_T_add(~)  *   - dynamic_array_T_add_at(~)  *   - dynamic_array_T_remove(~)  *   - dynamic_array_T_remove_at(~)  *   - dynamic_array_T_contains(~)  * Different types of Dynamic arrays can be defined in the same file. Their  * types and operations are differentiated by the 'T' in their names.  * See the macros that define these operations below for their docs.  * The initial capacity of the array and when it expands/contracts, and by how  * much, are defined in the constants below.  *  * Written by Max Hanson, June 2019.  */  #ifndef DYNAMIC_ARRAY_H #define DYNAMIC_ARRAY_H  #include <stdlib.h>  static const int INIT_CAPACITY = 10; /* Initial capacity. */ static const float EXPANSION_POINT = 1.0; /* load > this -> array expands */ static const float CONTRACTION_POINT = 0.3; /* load < this -> array contracts */ /* Expanded capacity = this * old capacity */ static const float EXPANSION_FACTOR = 2.0; /* Contracted capacity = this * old capacity */ static const float CONTRACTION_FACTOR = 0.5;  /*  * Macro to define a dynamic array of type T and its operations.  *  * A type parameter 'T' is valid if, and only if:  *   - It contains no spaces. Note this means pointers must be typecast.  */ #define DEFINE_DYNAMIC_ARRAY(T)                                                \     DEFINE_DYNAMIC_ARRAY_STRUCT(T)                                             \     DECLARE_DYNAMIC_ARRAY_HELPERS(T)                                           \     DEFINE_DYNAMIC_ARRAY_CTOR(T)                                               \     DEFINE_DYNAMIC_ARRAY_DTOR(T)                                               \     DEFINE_DYNAMIC_ARRAY_ADD(T)                                                \     DEFINE_DYNAMIC_ARRAY_ADD_AT(T)                                             \     DEFINE_DYNAMIC_ARRAY_REMOVE(T)                                             \     DEFINE_DYNAMIC_ARRAY_REMOVE_AT(T)                                          \     DEFINE_DYNAMIC_ARRAY_CONTAINS(T)                                           \     DEFINE_DYNAMIC_ARRAY_EXPAND(T)                                             \     DEFINE_DYNAMIC_ARRAY_CONTRACT(T)                                           \     DEFINE_DYNAMIC_ARRAY_INSERT_ELEM(T)                                        \     DEFINE_DYNAMIC_ARRAY_DELETE_ELEM(T)                                        \     DEFINE_DYNAMIC_ARRAY_RECALC_LOAD(T)  /*  * A generic dynamic array.  *  * A dynamic array is valid if, and only if:  *   - Its size is how many elements it contains.  *   - Its capacity is how large the internal array is.  *   - Its load is its size divided by its capacity.  *   - All of its elements are consecutive and start at index 0.  * The constructor is guaranteed to return a valid dynamic array and each  * operation will keep a valid dynamic array valid.  */ #define DEFINE_DYNAMIC_ARRAY_STRUCT(T)                                         \     typedef struct DynamicArrayTag_##T                                          \     {                                                                           \         float load;                                                             \         int size;                                                               \         int capacity;                                                           \         T *array;                                                               \     } DynamicArray_##T;  /*  * Create an empty dynamic array on the heap.  *  * The initial array capacity is defined in a constant at the top of the file.  *  * Every case complexity: BIG-THETA( malloc() ).  * If:  *   - The type 'T' supplied to the definition macro is valid.  * Then:  *   - A pointer to a valid dynamic array is returned.  *   - The size and load of the array will be 0.  *   - The capacity will be initialized according to the constants above.  *   - The elements of the internal array will be random.  * Edge cases:  *   - If there is an error allocating either the internal array or the dynamic  *     array instance, then null will be returned.  */ #define DEFINE_DYNAMIC_ARRAY_CTOR(T)                                           \     DynamicArray_##T *dynamic_array_##T##_construct()                           \     {                                                                           \         T *array;                                                               \                                                                                 \         DynamicArray_##T *self = malloc(sizeof(DynamicArray_##T));           \         array = malloc(INIT_CAPACITY * sizeof(T));                              \         if (self == NULL || array == NULL)                                   \         {                                                                       \             return NULL;                                                        \         }                                                                       \         self->array = array;                                                 \                                                                                 \         self->capacity = INIT_CAPACITY;                                      \         self->size = 0;                                                      \         self->load = 0;                                                      \     }  /*  * Free all memory associated with a dynamic array.  *  * Every case complexity: BIG-THETA( free() ).  * If:  *   - The dynamic array is valid.  * Then:  *   - All memory associated with the dynamic array will be deallocated.  */ #define DEFINE_DYNAMIC_ARRAY_DTOR(T)                                           \     void dynamic_array_##T##_destruct(DynamicArray_##T *self)                \     {                                                                           \         free(self->array);                                                   \         free(self);                                                          \     }  /*  * Add an element to the end of a dynamic array.  *  * Every case complexity: O( n + malloc() + free() ). N: size of the array.  * Amortized complexity: O(1).  * If:  *   - The dynamic array is valid.  * Then:  *   - The new element is added onto the end of the array and 0 is returned.  *   - The arrays size will be incremented.  *   - The arrays load factor will be recalculated.  *   - If the array is full, then it will be expanded to hold the new element.  * Edge cases:  *   - If the array is full and reallocation fails (no more memory), then 1  *     is returned and the array is not altered.  */ #define DEFINE_DYNAMIC_ARRAY_ADD(T)                                            \     int dynamic_array_##T##_add(DynamicArray_##T *self, T elem)              \     {                                                                           \         return dynamic_array_##T##_insert_elem(self, elem, self->size);   \     }  /*  * Add an element at the i-th index of a dynamic array.  *  * Every case complexity: O( n + malloc() + free() ) to expand the array.  *   N: size of the array.  * Amortized complexity: O(1).  * If:  *   - The dynamic array is valid.  * Then:  *   - The element will be the new i-th element of the array.  *   - The arrays size will be incremented.  *   - The arrays load factor will be recalculated.  *   - If the array is full, then it will be expanded to hold the new element.  * Edge cases:  *   - If the array is full and reallocation fails (no more memory), then 1  *     is returned and the array is not altered.  */ #define DEFINE_DYNAMIC_ARRAY_ADD_AT(T)                                         \     int dynamic_array_##T##_add_at(DynamicArray_##T *self, T elem, int i)    \     {                                                                           \         return dynamic_array_##T##_insert_elem(self, elem, i);               \     }  /*  * Remove the first occurrence of an element in the array.  *  * Worst case complexity: O( n + malloc() + free() ) to contract the array.  *   N: number of elements in the array.  * Best case complexity: O(1) to remove the last element.  * Average case complexity: O(n) to remvoe an intermediate element.  * If:  *   - The dynamic array is valid.  * Then:  *   - The first occurence of the element is removed from the array and all  *     elements after it are moved one index down.  *   - The size of the array is decremented.  *   - The load factor of the array is recalculated.  *   - If the load is small enough (see constants), then the array is contracted.  * Edge cases:  *   - If the array is contracted and there is an error allocating the new array,  *     then 1 is returned and the original array is not modified.  */ #define DEFINE_DYNAMIC_ARRAY_REMOVE(T)                                         \     int dynamic_array_##T##_remove(DynamicArray_##T *self, T elem)           \     {                                                                           \         int idx;                                                                \                                                                                 \         for (idx = 0; idx < self->size; idx++)                               \         {                                                                       \             if ((self->array)[idx] == elem)                                  \             {                                                                   \                 return dynamic_array_##T##_delete_elem(self, idx);           \             }                                                                   \         }                                                                       \         return 0;                                                               \     }  /*  * Remove the i-th element in the array.  *  * Worst case complexity: O( n + malloc() + free() ) to contract the array.  *   N: number of elements in the array.  * Best case complexity: O(1) to remove the last element.  * Average case complexity: O(n) to remvoe an intermediate element.  * If:  *   - The dynamic array is valid.  * Then:  *   - The i-th element is removed from the array and all elements after it  *     are moved one index down.  *   - The size of the array is decremented.  *   - The load factor of the array is recalculated.  *   - If the load is small enough (see constants), then the array is contracted.  * Edge cases:  *   - If the array is contracted and there is an error allocating the new array,  *     then 1 is returned and the original array is not modified.  */ #define DEFINE_DYNAMIC_ARRAY_REMOVE_AT(T)                                      \     int dynamic_array_##T##_remove_at(DynamicArray_##T *self, int i)         \     {                                                                           \         return dynamic_array_##T##_delete_elem(self, i);                     \     }  /*  * Determine if the array contains an element.  *  * Every case complexity: O(n).  * If:  *   - The dynamic array is valid  * Then:  *   - If the array contains the element, then 1 is returned. If it does not,  *     then 0 is returned.  */ #define DEFINE_DYNAMIC_ARRAY_CONTAINS(T)                                       \     int dynamic_array_##T##_contains(DynamicArray_##T *self, T elem)         \     {                                                                           \         int idx;                                                                \         T *array;                                                               \                                                                                 \         array = self->array;                                                 \         for (idx = 0; idx < self->size; idx++)                               \         {                                                                       \             if (array[idx] == elem)                                             \             {                                                                   \                 return 1;                                                       \             }                                                                   \         }                                                                       \         return 0;                                                               \     }  /*  * Declare signatures of helper methods.  */ #define DECLARE_DYNAMIC_ARRAY_HELPERS(T)                                       \     static int dynamic_array_##T##_expand(DynamicArray_##T *self);           \     static int dynamic_array_##T##_contract(DynamicArray_##T *self);         \     static int dynamic_array_##T##_insert_elem(DynamicArray_##T *self,       \                                                T elem, int i);                  \     static int dynamic_array_##T##_delete_elem(DynamicArray_##T *self,       \                                                int rem_idx);                    \     static void dynamic_array_##T##_recalc_load(DynamicArray_##T *self);     \  /*  * Expand the array.  *  * The capacity of the new array is defined in the EXPANSION_FACTOR constant  * at the top if this file.  *  * Every case complexity: O( n + malloc() + free() ). N: size of array.  * If:  *   - The array is valid.  * Then:  *   - A new, expanded array is allocated.  *   - All elements in the dynamic array are copied to this new array.  *   - The dynamic arrays internal array is swapped with this new array.  *   - 0 is returned.  * Edge cases:  *   - If there is an error allocating the new array, then 1 is returned. and  *     the old array is not modified.  */ #define DEFINE_DYNAMIC_ARRAY_EXPAND(T)                                         \     static int dynamic_array_##T##_expand(DynamicArray_##T *self)            \     {                                                                           \         T *new_array;                                                           \         int new_capacity;                                                       \         int idx;                                                                \                                                                                 \         /* Allocate new array. */                                               \         new_capacity = EXPANSION_FACTOR * (self->capacity);                  \         new_array = malloc(new_capacity * sizeof(T));                           \         if (new_array == NULL)                                                  \         {                                                                       \             /* Return and do not alter original array. */                       \             return 1;                                                           \         }                                                                       \                                                                                 \         /* Copy elements over and swap arrays. */                               \         for (idx = 0; idx <= self->size; idx++)                              \         {                                                                       \             new_array[idx] = self->array[idx];                               \         }                                                                       \         free(self->array);                                                   \         self->array = new_array;                                             \                                                                                 \         self->capacity = new_capacity;                                       \         dynamic_array_##T##_recalc_load(self);                               \                                                                                 \         return 0;                                                               \     }  /*  * Contract the array.  *  * The capacity of the new array is defined in the CONTRACTION_FACTOR constant  * at the top if this file.  *  * Every case complexity: O( n + malloc() + free() ). N: size of array.  * If:  *   - The array is valid.  * Then:  *   - A new, contracted array is allocated.  *   - All elements in the dynamic array are copied to this new array.  *   - The dynamic arrays internal array is swapped with this new array.  *   - 0 is returned.  * Edge cases:  *   - If there is an error allocating the new array, then 1 is returned and the  *     old array is not modified.  */ #define DEFINE_DYNAMIC_ARRAY_CONTRACT(T)                                       \     static int dynamic_array_##T##_contract(DynamicArray_##T *self)          \     {                                                                           \         T *new_array;                                                           \         int new_capacity;                                                       \         int idx;                                                                \                                                                                 \         /* Allocate new array. */                                               \         new_capacity = CONTRACTION_FACTOR * self->capacity;                  \         new_array = malloc(new_capacity * sizeof(T));                           \         if (new_array == NULL)                                                  \         {                                                                       \             /* Return error and leave old array unmodified. */                  \             return 1;                                                           \         }                                                                       \                                                                                 \         /* Copy elements over and swap arrays. */                               \         for (idx = 0; idx <= self->size; idx++)                              \         {                                                                       \             new_array[idx] = self->array[idx];                               \         }                                                                       \         free(new_array);                                                        \         self->array = new_array;                                             \                                                                                 \         self->capacity = new_capacity;                                       \         dynamic_array_##T##_recalc_load(self);                               \                                                                                 \         return 0;                                                               \     }  /*  * Insert an element at the i-th index of a dynamic array.  * Helper methods for add, add_at operations.  *   * Worst case complexity: O(n + malloc() + free() ) to expand the array.  *   N: size of array.  * Best case complexity: O(1) to add to the end of the array.  * If:  *   - The dynamic array is valid.  *   - 0 <= i <= self->size.  * Then:  *   - The element will be the new i-th element in the dynamic array.  *   - The dynamic arrays size will be incremented.  *   - The dynamic arrays load factor will be recalculated.  *   - If the dynamic array is full, then it will be expanded.  * Edge cases:  *   - If the dynamic array is full and there is an error expanding it, then 1  *     is returned.  */ #define DEFINE_DYNAMIC_ARRAY_INSERT_ELEM(T)                                    \ static int dynamic_array_##T##_insert_elem(DynamicArray_##T *self, T elem,   \                                            int i)                               \ {                                                                               \     int idx;                                                                    \     int status;                                                                 \     T *array;                                                                   \                                                                                 \     /* Expand if needed. */                                                     \     if (self->load == EXPANSION_POINT)                                       \     {                                                                           \         status = dynamic_array_##T##_expand(self);                           \         if (status > 1)                                                         \         {                                                                       \             return status; /* pass allocation error code up */                  \         }                                                                       \     }                                                                           \                                                                                 \     /* Move all elements in [i+1..self->size) forward one index. */          \     array = self->array;                                                     \     for (idx = self->size; idx > i; idx--)                                   \     {                                                                           \         array[idx] = array[idx - 1];                                            \     }                                                                           \                                                                                 \     array[idx] = elem;                                                          \     self->size += 1;                                                         \     dynamic_array_##T##_recalc_load(self);                                   \                                                                                 \     return 0;                                                                   \ }  /*  * Delete the element at the ith index of a dynamic array.  * Helper method for the remove, remove_at operations.  *  * If:  *   - The dynamic array is valid.  *   - 0 <= i < self->size.  * Then:  *   - The element at the i-th index of the array will be removed.  *   - All elements higher than the i-th index will be moved an index down.  *   - The array size will be decremented.  *   - The array load will be recalculated.  *   - If the array is sufficiently small after removal (see constants), then  *     the array will be contracted. The capacity and load will be recalculated.  *   - 0 is returned.  * Edge cases:  *   - If the array is contracted and there is an error allocating a new array,  *     then 1 is returned.  */ #define DEFINE_DYNAMIC_ARRAY_DELETE_ELEM(T)                                    \ static int dynamic_array_##T##_delete_elem(DynamicArray_##T *self,           \                                            int i)                               \ {                                                                               \     int idx;                                                                    \     T *array;                                                                   \                                                                                 \     /* Copy every element in [i+1..) back one index. Overwrites array[i] */     \     array = self->array;                                                     \     for (idx = i + 1; idx < self->size; idx++)                               \     {                                                                           \         array[idx - 1] = array[idx];                                            \     }                                                                           \                                                                                 \     /* Contract if necessary. Only contract if array has expanded before */     \     if (self->load <= CONTRACTION_POINT && self->capacity > INIT_CAPACITY)\     {                                                                           \         return dynamic_array_##T##_contract(self);                           \     }                                                                           \                                                                                 \     self->size -= 1;                                                         \     dynamic_array_##T##_recalc_load(self);                                   \                                                                                 \     return 0;                                                                   \ }  /*  * Set load equal to size divided by capacity.  *  * If:  *   - The dynamic array is valid.  * Then:  *   - load will equal size divided by capacity.  */ #define DEFINE_DYNAMIC_ARRAY_RECALC_LOAD(T)                                    \     static void dynamic_array_##T##_recalc_load(DynamicArray_##T *self)      \     {                                                                           \         self->load = ((float)self->size) / ((float)self->capacity);    \     }  #endif 

linked_list.h:

/*  * A basic, generic forward-linked-list data structure and relevant operations  * implemented from scratch in pure, old fashioned C.  *  * All functions in this header are prepended with 'linked_list_' to create a  * psuedo-namespace. The linked list supports operations to: create a new linked  * list, add an element (at the end or at an index), remove an element (from the  * end or by key), test if a key is in the list, and determine the size of the  * list.  *  * Written by Max Hanson, June 2019.  */   #ifndef LINKED_LIST_H #define LINKED_LIST_H  #include <stdlib.h> /* For malloc/NULL */   /*  * A generic forward-linked-list data structure.  *  * Note that by 'generic' I mean the key is a void pointer that can point to any  * data type. It is the client's responsibility to track what data type the  * linked list's keys are and safely cast them to/from void pointers.  * Also note that it is necessary that each key in the list points to an object  * on the heap that was allocated with 'malloc/calloc/realloc'. This is because  * each key is freed in the linked_list_destruct operation. Undefined behavior  * will occur if this requirement is not met.  *  * A LinkedList is valid if, and only if:  *   - The key of all nodes is non-null pointer.  *   - The next node of all nodes points to another node, except the tail node  *     whose next is null.  *   - There are no loops in the list.  *   - The head node leads to the tail node.  * Note that these operations do not verify linked list validity, but it is  * guaranteed that the constructor will create a valid linked list and that  * each operation will leave a valid linked list valid.  */ typedef struct linked_list_node_tag LinkedListNode; struct linked_list_node_tag {     void *key;     LinkedListNode *next; }; typedef struct linked_list_tag {     int size;     LinkedListNode *head;     LinkedListNode *tail; } LinkedList;  /*  * Create a new linked list from a key.  *  * Every case complexity: BIG-THETA(1).  * If:  *   - The head_key is not NULL.  * Then:  *   - A valid LinkedList is returned such that:  *     - Its head nodes key is the head_key.  *     - Its head node is its tail node.  *     - Its size is 1.  * Edge cases:  *   - If there is not enough space on the heap for a new LinkedList and  *     LinkedListNode, then NULL is returned.  */ LinkedList *linked_list_construct(void *head_key);  /*  * Deallocate a linked list.  *  *   * Every case runtime: BIG-THETA(n) where n is the size of the list.  * If:  *   - The list is a valid linked list.  * Then:  *   - All keys in the list will be freed.  *   - All nodes in the list will be freed.  *   - The linked list itself will be freed.  *   - The list pointer will be NULL.  */ void linked_list_destruct(LinkedList *list);  /*  * Append a key to a linked list.  *  * Every case complexity: BIG-THETA(1).  * If:  *   - The list is a valid LinkedList.  *   - The key points to the same data type as all nodes of the list.  * Then:  *   - A new node is created whose key is The key.  *   - The lists previous tail will point to this new node.  *   - The lists tail will point to this new node.  *   - The lists size will be incremented.  *   - A positive value is returned.  * Edge cases:  *   - If there is not enough space on the heap for a new LinkedListNode, then  *     zero is returned.  */ int linked_list_add(LinkedList *list, void *key);  /*  * Add an element to the i-th index of a linked list.  *  * Every case complexity: O(n) where n is the number of nodes in the list.  * Worst case complexity: BIG-THETA(n).  * Best case complexity: BIG-THETA(1).  * If:  *   - The list is a valid LinkedList.  *   - The key points to the same data type as all nodes of the list.  *   - 0 <= 'i' <= list.size.  * Then:  *   - A new node is created whose key is The key.  *   - This new node will be the i-th node of the list.  *   - If a new head is added, then the lists head will be updated.  *   - The lists size will be incremented.  *   - A positive value is returned.  * Edge cases:  *   - If there is not enough space on the heap for a new LinkedListNode, then  *     zero is returned.  */ int linked_list_add_at(LinkedList *list, void *key, int i);  /*  * Remove the i-th node of a linked list.  *  * Every case complexity: O(n) where n is the number of elements in the list.  * Worst case complexity: BIG-THETA(n).  * Best case complexity: BIG-THETA(1).  * If:  *   - The list is a valid LinkedList.  *   - 0 <= i < 'list.size'.  * Then:  *   - The node previously at the lists i-th index will be removed.  *   - If the head/tail is removed, then the new head/tail will be updated.  *   - The lists size will be decremented.  */ void linked_list_remove_at(LinkedList *list, int i);  /*  * Remove the first node containing a certain key from a linked list.  *  * Every case complexity: O(n) where n is the number of elements in the list.  * Worst case complexity: BIG-THETA(n).  * Best case complexity: BIG-THETA(1).  * If:  *   - The list is a valid LinkedList.  *   - The key is not NULL.  * Then:  *   - If the list contains the key, the first node with the matching key  *     (comparing addresses) is removed and a positive value is returned.  *   - If the list doesnt contain the key, then the list is unchanged and zero  *     is returned.  */ int linked_list_remove_key(LinkedList *list, void *key);  /*  * Determine if a linked list contains a key.  *  * Every case complexity: O(n) where n is the nubmer of elements in the list.  * Worst case complexity: BIG-THETA(n).  * Best case complexity: BIG-THETA(1).  * If:  *   - The list is a valid LinkedList.  *   - The key is not NULL.  * Then:  *   - If the list contains the key, then a positive value is returned.  *   - If the list doesnt contain the key then zero is returned.  */ int linked_list_contains_key(LinkedList *list, void *key);  /*  * Get the key of the i-th node of a linked list.  *  * Every case complexity: O(n) where n is the number of elements in the list.  * Worst case complexity: BIG-THETA(n).  * Best case complexity: BIG-THETA(1).  * If:  *   - The list is a valid LinkedList.  *   - 0 <= i < list.size  * Then:  *   - The key of the i-th node of the list is returned.  */ void *linked_list_get_key(LinkedList *list, int i);   #endif 

linked_list.c:

/**  * An implementation of the linked list operations from scratch.  *  * See the function definitions in the linked list header for documentation.  *  * Written by Max Hanson, June 2019.  */  #include "linked_list.h"  static LinkedListNode *create_node(void *key); static void point_to_index(LinkedList *list, LinkedListNode **prev_ptr,                            LinkedListNode **cursor_ptr, int index); static void point_to_key(LinkedList *list, LinkedListNode **prev_ptr,                          LinkedListNode **cursor_ptr, void *key); static void remove_node(LinkedList *list, LinkedListNode *prev,                         LinkedListNode *cursor);   LinkedList *linked_list_construct(void *head_key) {     LinkedListNode *new_node;     LinkedList *new_llist;      new_node = create_node(head_key);      new_llist = malloc(sizeof(LinkedList));     if (new_node == NULL || new_llist == NULL)     {         /* Allocation failed. */         return NULL;     }     new_llist->size = 1;     new_llist->head = new_node;     new_llist->tail = new_node;      return new_llist; }  void linked_list_destruct(LinkedList *list) {     LinkedListNode *cursor;     LinkedListNode *prev;      /* Step through, freeing each previous. Frees tail too. */     cursor = list->head;     prev = NULL;     while (cursor != NULL)     {         prev = cursor;         cursor = cursor->next;          free(prev->key);         free(prev);     }     free(list); }  int linked_list_add(LinkedList *list, void *key) {     LinkedListNode *new_node;      new_node = create_node(key);     if (new_node == NULL)     {         return 0;     }      list->tail->next = new_node;     list->tail = new_node;     list->size += 1;      return 1; }  int linked_list_add_at(LinkedList *list, void *key, int i) {     LinkedListNode *new_node;     LinkedListNode *cursor;     LinkedListNode *prev;     int idx;      new_node = create_node(key);     if (new_node == NULL)     {         return 0;     }      point_to_index(list, &prev, &cursor, i);     /* Add new_node as new i-th node. */     if (cursor == list->head)     {         /* Adding new head. Prev is null. */         new_node->next = cursor;         list->head = new_node;     }     if (prev == list->tail)     {         /* Adding a new tail. Cursor is null. */         prev->next = new_node;         list->tail = new_node;     }     else     {         /* Adding intermediate node. */         prev->next = new_node;         new_node->next = cursor;     }     list->size += 1;      return 1; }  void linked_list_remove_at(LinkedList *list, int i) {     LinkedListNode *cursor;     LinkedListNode *prev;     int idx;      /* NOTE assumed that i is within range, no checking. */     point_to_index(list, &prev, &cursor, i);     remove_node(list, prev, cursor); }  int linked_list_remove_key(LinkedList *list, void *key) {     LinkedListNode *cursor;     LinkedListNode *prev;     int idx;      point_to_key(list, &prev, &cursor, key);     if (cursor == NULL)     {         /* NOTE null if no matching key. */         return 0;     }     remove_node(list, prev, cursor);     return 1; }  int linked_list_contains_key(LinkedList *list, void *key) {     LinkedListNode *cursor;     LinkedListNode *prev;     int idx;      point_to_key(list, &prev, &cursor, key);     return (cursor != NULL); /* NOTE null if no matching key. */ }  void *linked_list_get_key(LinkedList *list, int i) {     LinkedListNode *cursor;     LinkedListNode *prev;     int idx;      point_to_index(list, &prev, &cursor, i);      return cursor->key; }  /* === HELPER METHODS === */  /*  * Create a new node on the heap.  *  * Every case complexity: O(1).  * If:  *   - The key is not NULL.  * Then:  *   - A pointer to a node whose key is 'key' and next is NULL is returned.  * Edge cases:  *   - If there is not room for a new node on the heap, the NULL is returned.  */ static LinkedListNode *create_node(void *key) {     LinkedListNode *new_node;      new_node = malloc(sizeof(LinkedListNode));     if (new_node == NULL)     {         return NULL;     }     new_node->key = key;     new_node->next = NULL;      return new_node; }  /*  * Point a cursor to a lists i-th node.  *  * Note the double pointers used in the arguments. This is so the function can  * modify the first-level pointer.  *  * Every case runtime: O(n) where n is the number of nodes in the list.  * Worst case runtime: BIG-THETA(n).  * Best case runtime: BIG-THETA(1).  * If:  *   - The list is a valid linked list.  *   - 0 <= index <= list.size  * Then:  *   - The cursor will point to the i-th node.  *   - The prev will point to the (i-1)-th node, or null if cursor is the head.  *   - If i = list.size: then cursor will be null and prev will be the tail.  */ static void point_to_index(LinkedList *list, LinkedListNode **prev_ptr,                            LinkedListNode **cursor_ptr, int index) {     int idx;     LinkedListNode *cursor;     LinkedListNode *prev;      /* Point cursor, prev to the correct nodes. */     idx = 0;     cursor = list->head;     prev = NULL;     while(idx != index)     {         prev = cursor;         cursor = cursor->next;         idx++;     }      /* Point what the args point to to the correct nodes. */     (*prev_ptr) = prev;     (*cursor_ptr) = cursor; }  /*  * Point a cursor to the first node in a list containing a key.  *  * A node contains a key if they both point to the same location in memory.  * Note the double pointers used in the arguments. This is so the function can  * modify the first-level pointer.  *  * Every case runtime: O(n) where n is the size of the list.  * Worst case runtime: BIG-THETA(n).  * Best case runtime: BIG-THETA(1).  * If:  *   - The list is a valid linked list.  *   - The key points to the same type of data as the list.  * Then:  *   - If the key is in the list, then the cursor will point to the first node  *     that contains that key and the prev will point to its previous.  *   - If the key is not in the list, then the cursor and prev will be NULL.  */ static void point_to_key(LinkedList *list, LinkedListNode **prev_ptr,                            LinkedListNode **cursor_ptr, void *key) {     LinkedListNode *cursor;     LinkedListNode *prev;      /* Point cursor, prev to the correct nodes */     cursor = list->head;     prev = NULL;     while(cursor != NULL && cursor->key != key)     {         prev = cursor;         cursor = cursor->next;     }      /* Point what the args point to to the correct nodes */     (*cursor_ptr) = cursor;     (*prev_ptr) = prev; }  /*  * Remove a node from a linked list.  *  * Every case runtime: O(1).  * If:  *   - The list is a valid list.  *   - The cursor points to a node in the list.  *   - The prev points to the node that points to the cursor.  * Then:  *   - The list will no longer contain the cursor.  *   - The lists size will be decremented.  *   - If the cursor was the lists head/tail, then the head/tail will be updated.  *   - The cursor will be deallocated.  */ static void remove_node(LinkedList *list, LinkedListNode *prev,                         LinkedListNode *cursor) {     if (cursor == list->head)     {         /* Removing head. Prev is NULL. */         list->head = cursor->next;     }     else if (cursor == list->tail)     {         /* Removing tail. */         prev->next = NULL;         list->tail = prev;     }     else     {         /* Removing intermediate node. */         prev->next = cursor->next;     }     free(cursor);     list->size -= 1; } ``` 

Postfix generic changes causing DKIM permerror

We have modifed the Return-Path: and Reply-To: sections of our email by doing the following:

/etc/postfix/main.cf

smtp_generic_maps = hash:/etc/postfix/generic 

/etc/postfix/generic

bounce@mainserver.com       bounce@relay.com admin@mainserver.com       admin@relay.com 

before adding this we get

Return-Path: <bounce@mainserver.com> Authentication-Results: mta1087.mail.ir2.yahoo.com   header.i=@relay.com header.s=mail dkim=pass (ok);  spfDomain=mainserver.com spfResult=none;  dmarc=pass(p=none sp=quarantine dis=none) header.from=relay.com Received-SPF: none (domain of mainserver.com does not designate permitted sender hosts) 

after:

Return-Path: <bounce@relay.com> Authentication-Results: mta1129.mail.ir2.yahoo.com   header.i=@relay.com header.s=mail dkim=permerror (bad sig);  spfDomain=relay.com spfResult=pass;  dmarc=pass(p=none sp=quarantine dis=none) header.from=relay.com Received-SPF: pass (domain of relay.com designates 51.89.165.124 as permitted sender) 

This change is causing our DKIM to get permerror (bad sig) is there a fix for this or another approach?