1
0
Fork 0
mirror of https://github.com/git/git.git synced 2024-11-14 21:23:03 +01:00
git/commit-slab.h

98 lines
2.9 KiB
C
Raw Normal View History

commit-slab: introduce a macro to define a slab for new type Introduce a header file to define a macro that can define the struct type, initializer, accessor and cleanup functions to manage a commit slab. Update the "indegree" topological sort facility using it. To associate 32 flag bits with each commit, you can write: define_commit_slab(flag32, uint32); to declare "struct flag32" type, define an instance of it with struct flag32 flags; and initialize it by calling init_flag32(&flags); After that, a call to flag32_at() function uint32 *fp = flag32_at(&flags, commit); will return a pointer pointing at a uint32 for that commit. Once you are done with these flags, clean them up with clear_flag32(&flags); Callers that cannot hard-code how wide the data to be associated with the commit be at compile time can use the "_with_stride" variant to initialize the slab. Suppose you want to give one bit per existing ref, and paint commits down to find which refs are descendants of each commit. Saying typedef uint32 bits320[5]; define_commit_slab(flagbits, bits320); at compile time will still limit your code with hard-coded limit, because you may find that you have more than 320 refs at runtime. The code can declare a commit slab "struct flagbits" like this instead: define_commit_slab(flagbits, unsigned char); struct flagbits flags; and initialize it by: nrefs = ... count number of refs ... init_flagbits_with_stride(&flags, (nrefs + 7) / 8); so that unsigned char *fp = flagbits_at(&flags, commit); will return a pointer pointing at an array of 40 "unsigned char"s associated with the commit, once you figure out nrefs is 320 at runtime. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-04-13 20:56:41 +02:00
#ifndef COMMIT_SLAB_H
#define COMMIT_SLAB_H
/*
* define_commit_slab(slabname, elemtype) creates boilerplate code to define
* a new struct (struct slabname) that is used to associate a piece of data
* of elemtype to commits, and a few functions to use that struct.
*
* After including this header file, using:
*
* define_commit_slab(indegee, int);
*
* will let you call the following functions:
*
* - int *indegree_at(struct indegree *, struct commit *);
*
* This function locates the data associated with the given commit in
* the indegree slab, and returns the pointer to it.
*
* - void init_indegree(struct indegree *);
* void init_indegree_with_stride(struct indegree *, int);
*
* Initializes the indegree slab that associates an array of integers
* to each commit. 'stride' specifies how big each array is. The slab
* that id initialied by the variant without "_with_stride" associates
* each commit with an array of one integer.
*/
/* allocate ~512kB at once, allowing for malloc overhead */
#ifndef COMMIT_SLAB_SIZE
#define COMMIT_SLAB_SIZE (512*1024-32)
#endif
#define define_commit_slab(slabname, elemtype) \
\
struct slabname { \
unsigned slab_size; \
unsigned stride; \
unsigned slab_count; \
elemtype **slab; \
}; \
static int stat_ ##slabname## realloc; \
\
static void init_ ##slabname## _with_stride(struct slabname *s, \
unsigned stride) \
{ \
unsigned int elem_size; \
if (!stride) \
stride = 1; \
s->stride = stride; \
commit-slab.h: Fix memory allocation and addressing The slab initialization code includes the calculation of the slab 'elem_size', which is in turn used to determine the size (capacity) of the slab. Each element of the slab represents an array, of length 'stride', of 'elemtype'. (Note that it may be clearer if the define_commit_slab macro parameter was called 'basetype' rather than 'elemtype'). However, the 'elem_size' calculation incorrectly uses 'sizeof(struct slabname)' in the expression, rather than 'sizeof(elemtype)'. Within the slab access routine, <slabname>_at(), the given commit 'index' is transformed into an (slab#, slot#) pair used to address the required element (a pointer to the first element of the array of 'elemtype' associated with that commit). The current code to calculate these address coordinates multiplies the commit index by the 'stride' which, at least for the slab#, produces the wrong result. Using the commit index directly, without scaling by the 'stride', produces the correct 'logical' address. Also, when allocating a new slab, the size of the allocation only allows for a slab containing elements of single element arrays of 'elemtype'. This should allow for elements of an array of length 'stride' of 'elemtype'. In order to fix this, we need to change the element size parameter to xcalloc() by multiplying the current element size (sizeof(**s->slab)) by the s->stride. Having changed the calculation of the slot#, we now need to convert the logical 'nth_slot', by scaling with s->stride, into the correct physical address. Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-07-27 21:00:07 +02:00
elem_size = sizeof(elemtype) * stride; \
commit-slab: introduce a macro to define a slab for new type Introduce a header file to define a macro that can define the struct type, initializer, accessor and cleanup functions to manage a commit slab. Update the "indegree" topological sort facility using it. To associate 32 flag bits with each commit, you can write: define_commit_slab(flag32, uint32); to declare "struct flag32" type, define an instance of it with struct flag32 flags; and initialize it by calling init_flag32(&flags); After that, a call to flag32_at() function uint32 *fp = flag32_at(&flags, commit); will return a pointer pointing at a uint32 for that commit. Once you are done with these flags, clean them up with clear_flag32(&flags); Callers that cannot hard-code how wide the data to be associated with the commit be at compile time can use the "_with_stride" variant to initialize the slab. Suppose you want to give one bit per existing ref, and paint commits down to find which refs are descendants of each commit. Saying typedef uint32 bits320[5]; define_commit_slab(flagbits, bits320); at compile time will still limit your code with hard-coded limit, because you may find that you have more than 320 refs at runtime. The code can declare a commit slab "struct flagbits" like this instead: define_commit_slab(flagbits, unsigned char); struct flagbits flags; and initialize it by: nrefs = ... count number of refs ... init_flagbits_with_stride(&flags, (nrefs + 7) / 8); so that unsigned char *fp = flagbits_at(&flags, commit); will return a pointer pointing at an array of 40 "unsigned char"s associated with the commit, once you figure out nrefs is 320 at runtime. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-04-13 20:56:41 +02:00
s->slab_size = COMMIT_SLAB_SIZE / elem_size; \
s->slab_count = 0; \
s->slab = NULL; \
} \
\
static void init_ ##slabname(struct slabname *s) \
{ \
init_ ##slabname## _with_stride(s, 1); \
} \
\
static void clear_ ##slabname(struct slabname *s) \
{ \
int i; \
for (i = 0; i < s->slab_count; i++) \
free(s->slab[i]); \
s->slab_count = 0; \
free(s->slab); \
s->slab = NULL; \
} \
\
static elemtype *slabname## _at(struct slabname *s, \
const struct commit *c) \
{ \
commit-slab.h: Fix memory allocation and addressing The slab initialization code includes the calculation of the slab 'elem_size', which is in turn used to determine the size (capacity) of the slab. Each element of the slab represents an array, of length 'stride', of 'elemtype'. (Note that it may be clearer if the define_commit_slab macro parameter was called 'basetype' rather than 'elemtype'). However, the 'elem_size' calculation incorrectly uses 'sizeof(struct slabname)' in the expression, rather than 'sizeof(elemtype)'. Within the slab access routine, <slabname>_at(), the given commit 'index' is transformed into an (slab#, slot#) pair used to address the required element (a pointer to the first element of the array of 'elemtype' associated with that commit). The current code to calculate these address coordinates multiplies the commit index by the 'stride' which, at least for the slab#, produces the wrong result. Using the commit index directly, without scaling by the 'stride', produces the correct 'logical' address. Also, when allocating a new slab, the size of the allocation only allows for a slab containing elements of single element arrays of 'elemtype'. This should allow for elements of an array of length 'stride' of 'elemtype'. In order to fix this, we need to change the element size parameter to xcalloc() by multiplying the current element size (sizeof(**s->slab)) by the s->stride. Having changed the calculation of the slot#, we now need to convert the logical 'nth_slot', by scaling with s->stride, into the correct physical address. Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-07-27 21:00:07 +02:00
int nth_slab, nth_slot; \
commit-slab: introduce a macro to define a slab for new type Introduce a header file to define a macro that can define the struct type, initializer, accessor and cleanup functions to manage a commit slab. Update the "indegree" topological sort facility using it. To associate 32 flag bits with each commit, you can write: define_commit_slab(flag32, uint32); to declare "struct flag32" type, define an instance of it with struct flag32 flags; and initialize it by calling init_flag32(&flags); After that, a call to flag32_at() function uint32 *fp = flag32_at(&flags, commit); will return a pointer pointing at a uint32 for that commit. Once you are done with these flags, clean them up with clear_flag32(&flags); Callers that cannot hard-code how wide the data to be associated with the commit be at compile time can use the "_with_stride" variant to initialize the slab. Suppose you want to give one bit per existing ref, and paint commits down to find which refs are descendants of each commit. Saying typedef uint32 bits320[5]; define_commit_slab(flagbits, bits320); at compile time will still limit your code with hard-coded limit, because you may find that you have more than 320 refs at runtime. The code can declare a commit slab "struct flagbits" like this instead: define_commit_slab(flagbits, unsigned char); struct flagbits flags; and initialize it by: nrefs = ... count number of refs ... init_flagbits_with_stride(&flags, (nrefs + 7) / 8); so that unsigned char *fp = flagbits_at(&flags, commit); will return a pointer pointing at an array of 40 "unsigned char"s associated with the commit, once you figure out nrefs is 320 at runtime. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-04-13 20:56:41 +02:00
\
commit-slab.h: Fix memory allocation and addressing The slab initialization code includes the calculation of the slab 'elem_size', which is in turn used to determine the size (capacity) of the slab. Each element of the slab represents an array, of length 'stride', of 'elemtype'. (Note that it may be clearer if the define_commit_slab macro parameter was called 'basetype' rather than 'elemtype'). However, the 'elem_size' calculation incorrectly uses 'sizeof(struct slabname)' in the expression, rather than 'sizeof(elemtype)'. Within the slab access routine, <slabname>_at(), the given commit 'index' is transformed into an (slab#, slot#) pair used to address the required element (a pointer to the first element of the array of 'elemtype' associated with that commit). The current code to calculate these address coordinates multiplies the commit index by the 'stride' which, at least for the slab#, produces the wrong result. Using the commit index directly, without scaling by the 'stride', produces the correct 'logical' address. Also, when allocating a new slab, the size of the allocation only allows for a slab containing elements of single element arrays of 'elemtype'. This should allow for elements of an array of length 'stride' of 'elemtype'. In order to fix this, we need to change the element size parameter to xcalloc() by multiplying the current element size (sizeof(**s->slab)) by the s->stride. Having changed the calculation of the slot#, we now need to convert the logical 'nth_slot', by scaling with s->stride, into the correct physical address. Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-07-27 21:00:07 +02:00
nth_slab = c->index / s->slab_size; \
nth_slot = c->index % s->slab_size; \
commit-slab: introduce a macro to define a slab for new type Introduce a header file to define a macro that can define the struct type, initializer, accessor and cleanup functions to manage a commit slab. Update the "indegree" topological sort facility using it. To associate 32 flag bits with each commit, you can write: define_commit_slab(flag32, uint32); to declare "struct flag32" type, define an instance of it with struct flag32 flags; and initialize it by calling init_flag32(&flags); After that, a call to flag32_at() function uint32 *fp = flag32_at(&flags, commit); will return a pointer pointing at a uint32 for that commit. Once you are done with these flags, clean them up with clear_flag32(&flags); Callers that cannot hard-code how wide the data to be associated with the commit be at compile time can use the "_with_stride" variant to initialize the slab. Suppose you want to give one bit per existing ref, and paint commits down to find which refs are descendants of each commit. Saying typedef uint32 bits320[5]; define_commit_slab(flagbits, bits320); at compile time will still limit your code with hard-coded limit, because you may find that you have more than 320 refs at runtime. The code can declare a commit slab "struct flagbits" like this instead: define_commit_slab(flagbits, unsigned char); struct flagbits flags; and initialize it by: nrefs = ... count number of refs ... init_flagbits_with_stride(&flags, (nrefs + 7) / 8); so that unsigned char *fp = flagbits_at(&flags, commit); will return a pointer pointing at an array of 40 "unsigned char"s associated with the commit, once you figure out nrefs is 320 at runtime. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-04-13 20:56:41 +02:00
\
if (s->slab_count <= nth_slab) { \
int i; \
s->slab = xrealloc(s->slab, \
(nth_slab + 1) * sizeof(s->slab)); \
stat_ ##slabname## realloc++; \
for (i = s->slab_count; i <= nth_slab; i++) \
s->slab[i] = NULL; \
s->slab_count = nth_slab + 1; \
} \
if (!s->slab[nth_slab]) \
s->slab[nth_slab] = xcalloc(s->slab_size, \
commit-slab.h: Fix memory allocation and addressing The slab initialization code includes the calculation of the slab 'elem_size', which is in turn used to determine the size (capacity) of the slab. Each element of the slab represents an array, of length 'stride', of 'elemtype'. (Note that it may be clearer if the define_commit_slab macro parameter was called 'basetype' rather than 'elemtype'). However, the 'elem_size' calculation incorrectly uses 'sizeof(struct slabname)' in the expression, rather than 'sizeof(elemtype)'. Within the slab access routine, <slabname>_at(), the given commit 'index' is transformed into an (slab#, slot#) pair used to address the required element (a pointer to the first element of the array of 'elemtype' associated with that commit). The current code to calculate these address coordinates multiplies the commit index by the 'stride' which, at least for the slab#, produces the wrong result. Using the commit index directly, without scaling by the 'stride', produces the correct 'logical' address. Also, when allocating a new slab, the size of the allocation only allows for a slab containing elements of single element arrays of 'elemtype'. This should allow for elements of an array of length 'stride' of 'elemtype'. In order to fix this, we need to change the element size parameter to xcalloc() by multiplying the current element size (sizeof(**s->slab)) by the s->stride. Having changed the calculation of the slot#, we now need to convert the logical 'nth_slot', by scaling with s->stride, into the correct physical address. Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-07-27 21:00:07 +02:00
sizeof(**s->slab) * s->stride); \
return &s->slab[nth_slab][nth_slot * s->stride]; \
commit-slab: introduce a macro to define a slab for new type Introduce a header file to define a macro that can define the struct type, initializer, accessor and cleanup functions to manage a commit slab. Update the "indegree" topological sort facility using it. To associate 32 flag bits with each commit, you can write: define_commit_slab(flag32, uint32); to declare "struct flag32" type, define an instance of it with struct flag32 flags; and initialize it by calling init_flag32(&flags); After that, a call to flag32_at() function uint32 *fp = flag32_at(&flags, commit); will return a pointer pointing at a uint32 for that commit. Once you are done with these flags, clean them up with clear_flag32(&flags); Callers that cannot hard-code how wide the data to be associated with the commit be at compile time can use the "_with_stride" variant to initialize the slab. Suppose you want to give one bit per existing ref, and paint commits down to find which refs are descendants of each commit. Saying typedef uint32 bits320[5]; define_commit_slab(flagbits, bits320); at compile time will still limit your code with hard-coded limit, because you may find that you have more than 320 refs at runtime. The code can declare a commit slab "struct flagbits" like this instead: define_commit_slab(flagbits, unsigned char); struct flagbits flags; and initialize it by: nrefs = ... count number of refs ... init_flagbits_with_stride(&flags, (nrefs + 7) / 8); so that unsigned char *fp = flagbits_at(&flags, commit); will return a pointer pointing at an array of 40 "unsigned char"s associated with the commit, once you figure out nrefs is 320 at runtime. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-04-13 20:56:41 +02:00
} \
\
static int stat_ ##slabname## realloc
#endif /* COMMIT_SLAB_H */