mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
lwsac: add blob deduplication helper
Add lwsac helper api to allow user code to perform constant string folding easily within an lwsac. After isolating a string or blob that it wants to store in the lwsac and point to, it can check if the string or blob already exists earlier in the lwsac first, and if so just point to that without copying it in again. For some formats with repeated strings like JSON, the saving can add up to something useful.
This commit is contained in:
parent
7a84ca4c83
commit
c776ac50d6
3 changed files with 70 additions and 37 deletions
|
@ -100,27 +100,6 @@ lws_list_ptr_insert(lws_list_ptr *phead, lws_list_ptr *add,
|
|||
LWS_VISIBLE LWS_EXTERN void *
|
||||
lwsac_use(struct lwsac **head, size_t ensure, size_t chunk_size);
|
||||
|
||||
/**
|
||||
* lwsac_use_zero - allocate / use some memory from a lwsac and zero it
|
||||
*
|
||||
* \param head: pointer to the lwsac list object
|
||||
* \param ensure: the number of bytes we want to use
|
||||
* \param chunk_size: 0, or the size of the chunk to (over)allocate if
|
||||
* what we want won't fit in the current tail chunk. If
|
||||
* 0, the default value of 4000 is used. If ensure is
|
||||
* larger, it is used instead.
|
||||
*
|
||||
* This also serves to init the lwsac if *head is NULL. Basically it does
|
||||
* whatever is necessary to return you a pointer to ensure bytes of memory
|
||||
* reserved for the caller.
|
||||
*
|
||||
* \p ensure bytes at the return address are zeroed if the allocation succeeded.
|
||||
*
|
||||
* Returns NULL if OOM.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN void *
|
||||
lwsac_use_zero(struct lwsac **head, size_t ensure, size_t chunk_size);
|
||||
|
||||
/**
|
||||
* lwsac_use - allocate / use some memory from a lwsac
|
||||
*
|
||||
|
@ -137,7 +116,9 @@ lwsac_use_zero(struct lwsac **head, size_t ensure, size_t chunk_size);
|
|||
* Returns NULL if OOM.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN void *
|
||||
lwsac_use_zeroed(struct lwsac **head, size_t ensure, size_t chunk_size);
|
||||
lwsac_use_zero(struct lwsac **head, size_t ensure, size_t chunk_size);
|
||||
|
||||
#define lwsac_use_zeroed lwsac_use_zero
|
||||
|
||||
/**
|
||||
* lwsac_free - deallocate all chunks in the lwsac and set head NULL
|
||||
|
@ -228,4 +209,21 @@ lwsac_info(struct lwsac *head);
|
|||
LWS_VISIBLE LWS_EXTERN uint64_t
|
||||
lwsac_total_alloc(struct lwsac *head);
|
||||
|
||||
/**
|
||||
* lwsac_scan_extant() - returns existing copy of blob, or NULL
|
||||
*
|
||||
* \param head: the lwsac to scan
|
||||
* \param find: the blob to look for
|
||||
* \param len: the length of the blob to look for
|
||||
* \param nul: nonzero if the next byte must be NUL
|
||||
*
|
||||
* Helper that looks through a whole lwsac for a given binary blob already
|
||||
* present. Used in the case that lwsac contents are const once written, and
|
||||
* strings or blobs may be repeated in the input: this allows the earlier
|
||||
* copy to be pointed to by subsequent references without repeating the string
|
||||
* or blob redundantly.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN uint8_t *
|
||||
lwsac_scan_extant(struct lwsac *head, uint8_t *find, size_t len, int nul);
|
||||
|
||||
///@}
|
||||
|
|
|
@ -90,7 +90,7 @@ lwsac if they need to, avoiding any need to visit them during destroy. It's
|
|||
like clearing up after a kids' party by gathering up a disposable tablecloth:
|
||||
no matter what was left on the table, it's all gone in one step.
|
||||
|
||||
## lws_list_ptr helpers
|
||||
## `lws_list_ptr` helpers
|
||||
|
||||
```
|
||||
/* sort may be NULL if you don't care about order */
|
||||
|
@ -100,7 +100,24 @@ lws_list_ptr_insert(lws_list_ptr *phead, lws_list_ptr *add,
|
|||
```
|
||||
|
||||
A common pattern needed with sub-allocated structs is they are on one or more
|
||||
linked-list. To make that simple to do cleanly, lws_list... apis are provided
|
||||
linked-list. To make that simple to do cleanly, `lws_list...` apis are provided
|
||||
along with a generic insertion function that can take a sort callback. These
|
||||
allow a struct to participate on multiple linked-lists simultaneously.
|
||||
|
||||
## common const string and blob folding
|
||||
|
||||
In some cases the input to be stored in the lwsac may repeat the same tokens
|
||||
multiple times... if the pattern is to store the string or blob in the lwsac
|
||||
and then point to it, you can make use of a helper api
|
||||
|
||||
```
|
||||
uint8_t *
|
||||
lwsac_scan_extant(struct lwsac *head, uint8_t *find, size_t len, int nul);
|
||||
```
|
||||
|
||||
This lets you check in all previous used parts of the lwsac for the same
|
||||
string or blob, plus optionally a terminal NUL afterwards. If not found,
|
||||
it returns `NULL` and you can copy it into the lwsac as usual. If it is
|
||||
found, a pointer is returned, and you can use this directly without copying
|
||||
the string or blob in again.
|
||||
|
||||
|
|
|
@ -72,8 +72,8 @@ lwsac_get_next(struct lwsac *lac)
|
|||
void *
|
||||
lwsac_use(struct lwsac **head, size_t ensure, size_t chunk_size)
|
||||
{
|
||||
size_t ofs, alloc, al;
|
||||
struct lwsac *chunk;
|
||||
size_t ofs, alloc;
|
||||
|
||||
/* ensure there's a chunk and enough space in it for this name */
|
||||
|
||||
|
@ -127,13 +127,42 @@ lwsac_use(struct lwsac **head, size_t ensure, size_t chunk_size)
|
|||
|
||||
ofs = (*head)->curr->ofs;
|
||||
|
||||
(*head)->curr->ofs += lwsac_align(ensure);
|
||||
al = lwsac_align(ensure);
|
||||
if (al > ensure) {
|
||||
/* zero down the alignment padding part */
|
||||
|
||||
memset((char *)(*head)->curr + ofs + ensure, 0, al - ensure);
|
||||
}
|
||||
(*head)->curr->ofs += al;
|
||||
if ((*head)->curr->ofs >= (*head)->curr->alloc_size)
|
||||
(*head)->curr->ofs = (*head)->curr->alloc_size;
|
||||
|
||||
return (char *)(*head)->curr + ofs;
|
||||
}
|
||||
|
||||
uint8_t *
|
||||
lwsac_scan_extant(struct lwsac *head, uint8_t *find, size_t len, int nul)
|
||||
{
|
||||
while (head) {
|
||||
uint8_t *pos = (uint8_t *)&head[1],
|
||||
*end = ((uint8_t *)head) + head->ofs - len;
|
||||
|
||||
if (head->ofs - sizeof(*head) >= len)
|
||||
while (pos < end) {
|
||||
if (*pos == *find && (!nul || !pos[len]) &&
|
||||
pos[len - 1] == find[len - 1] &&
|
||||
!memcmp(pos, find, len))
|
||||
/* found the blob */
|
||||
return pos;
|
||||
pos++;
|
||||
}
|
||||
|
||||
head = head->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *
|
||||
lwsac_use_zero(struct lwsac **head, size_t ensure, size_t chunk_size)
|
||||
{
|
||||
|
@ -145,17 +174,6 @@ lwsac_use_zero(struct lwsac **head, size_t ensure, size_t chunk_size)
|
|||
return p;
|
||||
}
|
||||
|
||||
void *
|
||||
lwsac_use_zeroed(struct lwsac **head, size_t ensure, size_t chunk_size)
|
||||
{
|
||||
void *r = lwsac_use(head, ensure, chunk_size);
|
||||
|
||||
if (r)
|
||||
memset(r, 0, ensure);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void
|
||||
lwsac_free(struct lwsac **head)
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue