Replies: 5 comments 8 replies
-
Hi, yes, I think there is a simpler solution to this, I will come back to you. |
Beta Was this translation helpful? Give feedback.
-
I am not keen on extending containers struct, in particular not conditionally, because it will then be very error-prone to pre-declare containers. From what I gather, in your case, only palloc() is context sensitive - repalloc() and pfree() knows which context the memory came from. In principle you can override c_malloc(), c_realloc, c_calloc() and c_free(),but you need to make sure that you have switched to the correct context before inserting new data into the containers. If you have one context per container, you can store the context in a struct along with the container. #define pgs_malloc(sz) palloc(sz)
#define pgs_calloc(n, sz) palloc0((n)*(sz))
#define pgs_realloc(p, sz) (p) ? repalloc(p, sz) : palloc(sz) // palloc() only called on first insert
#define pgs_free(p, sz) (p) ? pfree(p) : (void)0 Create your container: #define i_val int
#define i_allocator pgs
#include <stc/cvec.h> // cvec, cstack, csmap only uses realloc and free after some data is inserted. cmap and clist uses malloc.
...
setContext();
cvec_int vec = cvec_int_with_capacity(10); // allocate with current context
// now you can insert and free vec without worry about context. If you really need an allocator per container-instance, it gets more complicated, because then each of these functions must be given a pointer to the container, which is not always available. (e.g. an element may use dyn. allocation and be created before it is inserted into the container). |
Beta Was this translation helpful? Give feedback.
-
The code I showed (now updated) may be difficult to understand, but it exactly the same as having a context pointer inside each container - it is simply placed outside the container instead. The advantage is that this is typesafe, and you can place the context as a typesafe value. This will also be faster. As you see, you can place the allocator and declare_pgs_con() defines in a separate file and use it for every container. |
Beta Was this translation helpful? Give feedback.
-
The container_of macro is not in the standard, but is highly valuable for generic programming in C and well known as it is used in the linux kernel. The c_container_of() is in addition typesafe and portable. However, it still requires that the first arg. actually points to the member (third arg.) of the struct type given as the second argument. |
Beta Was this translation helpful? Give feedback.
-
Here is what you can do: // stcpgs.h
#define pgs_malloc(sz) MemoryContextAlloc(c_extend()->memctx, sz)
#define pgs_calloc(n, sz) MemoryContextAllocZero(c_extend()->memctx, (n)*(sz))
#define pgs_realloc(p, sz) (p ? repalloc(p, sz) : pgs_malloc(sz))
#define pgs_free(p) (p ? pfree(p) : (void)0)
#define i_extend MemoryContext memctx;
#define i_allocator pgs
#define i_no_clone
#include <stc/extend.h> Use #include <stdio.h>
#define i_type IVec
#define i_key int
#define i_base cvec // base container to use
#include "stcpgs.h"
#define i_type IMap
#define i_key int
#define i_val int
#define i_base csmap
#include "stcpgs.h"
void vectest()
{
IVec_ext vec = {.memctx=2};
c_forrange (i, 1, 16)
IVec_push(&vec.get, i*i);
c_foreach (i, IVec, vec.get)
printf("%d ", *i.ref);
puts("");
IVec_drop(&vec.get);
}
void maptest()
{
IMap_ext map = {.memctx=1};
c_forrange (i, 1, 16)
IMap_insert(&map.get, i*i, i);
c_foreach (i, IMap, map.get)
printf("%d:%d ", i.ref->first, i.ref->second);
puts("");
IMap_drop(&map.get);
} |
Beta Was this translation helpful? Give feedback.
-
I have a case where allocation primitives of the underlying systems are more complex than having a single global allocator. Essentially, multiple allocation areas with a concept of a "current one."
Specifically, I am using MemoryContexts in PostgreSQL.
The way STC currently works sometimes results in hard-to-find bugs. I may have a current memory context that would go out of scope and get dropped before I dispose of an STC collection.
So, I was thinking, what if we add optional allocators to collections?
Say, something like this interface-wise:
When
i_allocator
is defined, the underlying structure will get an additional field of an "allocator type," which is something like:And in this case, the container will use this allocator instead of the global one.
All the initializer members of such a container will receive an additional argument of that struct type (or, perhaps, a pointer to one) so that the underlying allocator and the methods can be appropriately initialized:
Happy to try working on a PR (however, I am still not very confident with STC's codebase so it may take some time) or help to get it done if there's an agreement.
Beta Was this translation helpful? Give feedback.
All reactions