nuttx/include/obstack.h
Karel Kočí b04da1892e libs/libc/obstack: implement ptr and int growing functions
The new API is defined by GNU and implemented in other LibCs, such as
Musl.

This also modifies API of obstack_blank_fast and obstack_1grow_fast.
These are defined as returning void and thus return value here is
incompatibility with other implementations.
2024-09-17 02:00:46 +08:00

549 lines
19 KiB
C

/****************************************************************************
* include/obstack.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/* This is based on the GlibC API but the implementation is not exactly same.
* The major difference is how required memory is allocated. The GlibC
* implementation starts with 4KB of allocated space. That would make it
* impossible to use this on MCUs. This implementation rather tries to
* allocated only required amount of space and it won't allocate chunk unless
* grow functions are used and even then it uses realloc to release unused
* space. It also in default won't use 4KB per chunk but rather just BUFSIZ.
*
* Not implemented interface:
* obstack_alignment_mask:
* The current implementation does not provide any alignment guaranties.
* obstack_chunk_alloc and obstack_chunk_free:
* Internal implementation uses not only alloc and free but also realloc
* and thus standard implementations are used unconditionally instead of
* requiring users to provide declaration for these functions.
*/
#ifndef __INCLUDE_OBSTACK_H
#define __INCLUDE_OBSTACK_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <stddef.h>
#include <stdarg.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Name: obstack_chunk_size
*
* Description:
* The access to the obstack configuration specifying the size of the
* single chunk used when growing object.
* It is documented t hat this is macro and that it is possible to use
* assignment to change the chunk size (eq.: obstack_chunk_size(h) = 1024).
*
* The default chunk size is set to BUFSIZ.
*
* The chunks size has to be always power of two due to the limitations of
* the obstack_make_room implementation!
*
* Input Parameters:
* h: pointer to the handle used to grow the object.
*
* Returned Value:
* Size of the single chunk.
*
****************************************************************************/
#define obstack_chunk_size(h) ((h)->chunk_size)
/****************************************************************************
* Name: obstack_base
*
* Description:
* Provides access to the tentative starting address of the
* currently growing object.
*
* Input Parameters:
* h: pointer to the handle used to grow the object.
*
* Returned Value:
* Tentative starting address of the currently growing object.
*
****************************************************************************/
#define obstack_base(h) ((h)->object_base)
/****************************************************************************
* Name: obstack_next_free
*
* Description:
* Provides access to the tentative address just after the end of the
* currently growing object.
*
* Input Parameters:
* h: pointer to the handle used to grow the object.
*
* Returned Value:
* Address just after the end of the currently growing object.
*
****************************************************************************/
#define obstack_next_free(h) ((h)->next_free)
/****************************************************************************
* Name: obstack_blank_fast
*
* Description:
* Moves the end of the currently growing object by given size and thus
* adding given number of uninitialized bytes to the growing object.
* There is no check if there is enough room and thus it is easy to cause
* buffer overrun. Use only when you are sure that there is enough room!
*
* Input Parameters:
* h: pointer to the handle used to grow the object.
* size: number of bytes
*
****************************************************************************/
#define obstack_blank_fast(h, size) ((void)((h)->next_free += (size)))
/****************************************************************************
* Name: obstack_1grow_fast
*
* Description:
* Adds one byte to the currently growing object.
* There is no check if there is enough room and thus it is easy to cause
* buffer overrun. Use only when you are sure that there is enough room!
*
* Input Parameters:
* h: pointer to the handle used to grow the object.
* data: byte to be added
*
****************************************************************************/
#define obstack_1grow_fast(h, data) ((void)(*((h)->next_free++) = (data)))
/****************************************************************************
* Name: obstack_ptr_grow_fast
*
* Description:
* Adds one pointer to the currently growing object.
* There is no check if there is enough room and thus it is easy to cause
* buffer overrun. Use only when you are sure that there is enough room!
*
* Input Parameters:
* h: pointer to the handle used to grow the object.
* ptr: pointer to be added
*
****************************************************************************/
#define obstack_ptr_grow_fast(h, ptr) \
do { \
FAR struct obstack *__o = (h); \
*(const void **)__o->next_free = (ptr); \
__o->next_free += sizeof(const void*); \
} while (0)
/****************************************************************************
* Name: obstack_int_grow_fast
*
* Description:
* Adds one integer to the currently growing object.
* There is no check if there is enough room and thus it is easy to cause
* buffer overrun. Use only when you are sure that there is enough room!
*
* Input Parameters:
* h: pointer to the handle used to grow the object.
* data: integer to be added
*
****************************************************************************/
#define obstack_int_grow_fast(h, data) \
do { \
FAR struct obstack *__o = (h); \
*(int*)__o->next_free = (data); \
__o->next_free += sizeof(const void*); \
} while (0)
/****************************************************************************
* Public Type Definitions
****************************************************************************/
struct _obstack_chunk /* Chunk head. */
{
FAR char *limit; /* Address of char after this chunk */
FAR struct _obstack_chunk *prev; /* Address of prior chunk or NULL */
};
struct obstack
{
size_t chunk_size; /* Preferred size to allocate chunks in */
FAR struct _obstack_chunk *chunk; /* Address of current struct _obstack_chunk */
FAR char *object_base; /* Address of object we are building */
FAR char *next_free; /* Where to add next char to current object */
};
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
#undef EXTERN
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* Name: obstack_init
*
* Description:
* Initialize obstack for allocation of objects.
* Compared to the GlibC version this won't initialize a first chunk.
*
* Input Parameters:
* h: pointer to the handle to initialize
*
****************************************************************************/
void obstack_init(FAR struct obstack *h);
/****************************************************************************
* Name: obstack_alloc
*
* Description:
* Allocate an object of given size with uninitialized bytes.
* Compared to the GlibC version this uses malloc to allocate exactly
* required space (plus overhead) and nothing more.
*
* Input Parameters:
* h: pointer to the handle to allocate an object in
* size: number of bytes to allocate
*
****************************************************************************/
FAR void *obstack_alloc(FAR struct obstack *h, size_t size);
/****************************************************************************
* Name: obstack_copy
*
* Description:
* Allocate an object of given size with contents copied from address.
* The same remarks regarding the allocation apply here as for
* obstack_alloc.
*
* Input Parameters:
* h: pointer to the handle to allocate an object in
* address: pointer to the bytes to be used to initialize new object
* size: number of bytes to allocate
*
****************************************************************************/
FAR void *obstack_copy(FAR struct obstack *h,
FAR const void *address, size_t size);
/****************************************************************************
* Name: obstack_copy0
*
* Description:
* Allocate an object of given size+1 with contents copied from address and
* append null byte at the end.
* The same remarks regarding the allocation apply here as for
* obstack_alloc.
*
* Input Parameters:
* h: pointer to the handle to allocate an object in
* address: pointer to the bytes to be used to initialize new object
* size: number of bytes to allocate (excluding the null byte)
*
****************************************************************************/
FAR void *obstack_copy0(FAR struct obstack *h,
FAR const void *address, size_t size);
/****************************************************************************
* Name: obstack_free
*
* Description:
* Free objects (and everything allocated in the specified obstack more
* recently than object). You can pass NULL to free everything.
* The buffer the allocated object was preset is kept and thus can be
* immediately reused for growing. The only exception for this is when NULL
* is passed as in such case even the last buffer is freed.
*
* Input Parameters:
* h: pointer to the handle object belongs to
* object: the pointer to the object or NULL
*
****************************************************************************/
void obstack_free(FAR struct obstack *h, FAR void *object);
/****************************************************************************
* Name: obstack_make_room
*
* Description:
* This is non-standard function that is probably available only on NuttX!
* Make sure that there is room in the buffer to fit object with given
* size. The allocation performed is in multiples of chunk_size specified
* for the obstack.
*
* Input Parameters:
* h: pointer to the handle where room should be made
* size: number of bytes to be free for growth
*
* Assumptions/Limitations:
* The obstack's chunk_size is expected to be power of two. This helps to
* eliminate division that might not be implemented in the HW and thus
* inefficient.
*
****************************************************************************/
void obstack_make_room(struct obstack *h, size_t size);
/****************************************************************************
* Name: obstack_blank
*
* Description:
* Grow object by given size. The bytes are uninitialized.
*
* Input Parameters:
* h: pointer to the handle to allocated object to
* size: number of bytes to grow object
*
****************************************************************************/
void obstack_blank(FAR struct obstack *h, size_t size);
/****************************************************************************
* Name: obstack_grow
*
* Description:
* Grow object by given size and allocated it with bytes from address.
*
* Input Parameters:
* h: pointer to the handle to allocated object to
* address: pointer to the bytes to be used to initialize the new object
* size: number of bytes to grow object
*
****************************************************************************/
void obstack_grow(FAR struct obstack *h,
FAR const void *address, size_t size);
/****************************************************************************
* Name: obstack_grow0
*
* Description:
* Grow object by given size+1 and allocated it with bytes from address
* plus null byte at the end.
*
* Input Parameters:
* h: pointer to the handle to allocated object to
* address: pointer to the bytes to be used to initialize the new object
* size: number of bytes to grow object (excluding the null byte)
*
****************************************************************************/
void obstack_grow0(FAR struct obstack *h,
FAR const void *address, size_t size);
/****************************************************************************
* Name: obstack_1grow
*
* Description:
* Grow object by single data byte.
*
* Input Parameters:
* h: pointer to the handle to allocated object to
* data: byte to be added to the growing object
*
****************************************************************************/
void obstack_1grow(FAR struct obstack *h, char data);
/****************************************************************************
* Name: obstack_ptr_grow
*
* Description:
* Grow object by one pointer.
*
* Input Parameters:
* h: pointer to the handle to allocated object to
* ptr: pointer to be added to the growing object
*
****************************************************************************/
void obstack_ptr_grow(FAR struct obstack *h, const void *ptr);
/****************************************************************************
* Name: obstack_int_grow
*
* Description:
* Grow object by one integer.
*
* Input Parameters:
* h: pointer to the handle to allocated object to
* data: integer to be added to the growing object
*
****************************************************************************/
void obstack_int_grow(FAR struct obstack *h, int data);
/****************************************************************************
* Name: obstack_finish
*
* Description:
* Finish growing object and receive address to it.
* Compared to the GlibC version this uses realloc to reduce buffer size to
* only allocated amount. The non-standard obstack_finish_norealloc can be
* used if you want the standard behavior for ever reason.
*
* Input Parameters:
* h: pointer to the handle used to grow the object.
*
* Returned Value:
* Permanent address to the object.
*
****************************************************************************/
FAR void *obstack_finish(FAR struct obstack *h);
/****************************************************************************
* Name: obstack_finish_norealloc
*
* Description:
* Finish growing object and receive address to it without reallocating
* buffer to fit the object (keeping space for more growth).
*
* Input Parameters:
* h: pointer to the handle used to grow the object.
*
* Returned Value:
* Permanent address to the object.
*
****************************************************************************/
FAR void *obstack_finish_norealloc(FAR struct obstack *h);
/****************************************************************************
* Name: obstack_object_size
*
* Description:
* Calculate the size of the currently growing object.
*
* Input Parameters:
* h: pointer to the handle used to grow the object.
*
* Returned Value:
* Size of the object.
*
****************************************************************************/
size_t obstack_object_size(FAR struct obstack *h);
/****************************************************************************
* Name: obstack_room
*
* Description:
* Calculate the number of bytes available for growth before reallocation
* is required.
*
* Input Parameters:
* h: pointer to the handle used to grow the object.
*
* Returned Value:
* Number of free bytes.
*
****************************************************************************/
size_t obstack_room(FAR struct obstack *h);
/****************************************************************************
* Name: obstack_printf
*
* Description:
* This is similar to the asprintf except it uses obstack to allocate
* string on. The characters are written onto the end of the currently
* growing object and terminated by null byte.
*
* This function is defined in stdio.h in GlibC. There is no definition
* that would be in stdio.h required for these here and thus it is easier
* to just keep these functions here as user has to include obstack anyway
* to get the full functionality.
*
* Input Parameters:
* h: pointer to the handle used to grow the object.
* fmt: format string with its format inputs followed.
*
* Returned Value:
* Number of characters added to the obstack excluding the null byte.
*
****************************************************************************/
int obstack_printf(FAR struct obstack *h, FAR const char *fmt, ...)
printf_like(2, 3);
/****************************************************************************
* Name: obstack_vprintf
*
* Description:
* This is similar to the vasprintf except it uses obstack to allocate
* string on. The characters are written onto the end of the currently
* growing object and terminated by null byte.
*
* The same remarks are applied here as for obstack_printf regarding the
* definition location in GlibC.
*
* Input Parameters:
* h: pointer to the handle used to grow the object.
* fmt: format string
* ap: format string input as a variable argument list
*
* Returned Value:
* Number of characters added to the obstack excluding the null byte.
*
****************************************************************************/
int obstack_vprintf(FAR struct obstack *h, FAR const char *fmt, va_list ap)
printf_like(2, 0);
/****************************************************************************
* Name: obstack_alloc_failed_handler
*
* Description:
* Error handler called when 'obstack_chunk_alloc' failed to allocate more
* memory. This can be set to a user defined function which should either
* abort gracefully or use longjump - but shouldn't return. The default
* action is to print a message and abort.
*
****************************************************************************/
extern void (*obstack_alloc_failed_handler) (void);
#undef EXTERN
#ifdef __cplusplus
}
#endif
#endif /* __INCLUDE_OBSTACK_H */