summaryrefslogtreecommitdiffstats
path: root/generic/tclCkalloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclCkalloc.c')
-rw-r--r--generic/tclCkalloc.c143
1 files changed, 143 insertions, 0 deletions
diff --git a/generic/tclCkalloc.c b/generic/tclCkalloc.c
index 09e140a..106a62c 100644
--- a/generic/tclCkalloc.c
+++ b/generic/tclCkalloc.c
@@ -16,6 +16,7 @@
*/
#include "tclInt.h"
+#include <assert.h>
#define FALSE 0
#define TRUE 1
@@ -1234,6 +1235,148 @@ TclDumpMemoryInfo(
#endif /* TCL_MEM_DEBUG */
/*
+ *------------------------------------------------------------------------
+ *
+ * TclAllocElemsEx --
+ *
+ * See TclAttemptAllocElemsEx. This function differs in that it panics
+ * on failure.
+ *
+ * Results:
+ * Non-NULL pointer to allocated memory block.
+ *
+ * Side effects:
+ * Panics if memory of at least the requested size could not be
+ * allocated.
+ *
+ *------------------------------------------------------------------------
+ */
+void *
+TclAllocElemsEx(
+ Tcl_Size elemCount, /* Allocation will store at least these many... */
+ Tcl_Size elemSize, /* ...elements of this size */
+ Tcl_Size leadSize, /* Additional leading space in bytes */
+ Tcl_Size *capacityPtr) /* OUTPUT: Actual capacity is stored
+ here if non-NULL. Only modified on success */
+{
+ void *ptr = TclAttemptReallocElemsEx(
+ NULL, elemCount, elemSize, leadSize, capacityPtr);
+ if (ptr == NULL) {
+ Tcl_Panic("Failed to allocate %" TCL_SIZE_MODIFIER
+ "d elements of size %" TCL_SIZE_MODIFIER "d bytes.",
+ elemCount,
+ elemSize);
+ }
+ return ptr;
+}
+
+/*
+ *------------------------------------------------------------------------
+ *
+ * TclAttemptReallocElemsEx --
+ *
+ * Attempts to allocate (oldPtr == NULL) or reallocate memory of the
+ * requested size plus some more for future growth. The amount of
+ * reallocation is adjusted depending on on failure.
+ *
+ *
+ * Results:
+ * Pointer to allocated memory block which is at least as large
+ * as the requested size or NULL if allocation failed.
+ *
+ *------------------------------------------------------------------------
+ */
+void *
+TclAttemptReallocElemsEx(
+ void *oldPtr, /* Pointer to memory block to reallocate or
+ * NULL to indicate this is a new allocation */
+ Tcl_Size elemCount, /* Allocation will store at least these many... */
+ Tcl_Size elemSize, /* ...elements of this size */
+ Tcl_Size leadSize, /* Additional leading space in bytes */
+ Tcl_Size *capacityPtr) /* OUTPUT: Actual capacity is stored
+ here if non-NULL. Only modified on success */
+{
+ void *ptr;
+ Tcl_Size limit;
+ Tcl_Size attempt;
+
+ assert(elemCount > 0);
+ assert(elemSize > 0);
+ assert(elemSize < TCL_SIZE_MAX);
+ assert(leadSize > 0);
+ assert(leadSize < TCL_SIZE_MAX);
+
+ limit = (TCL_SIZE_MAX - leadSize) / elemSize;
+ if (elemCount > limit) {
+ return NULL;
+ }
+ /* Loop trying for extra space, reducing request each time */
+ attempt = TclUpsizeAlloc(0, elemCount, limit);
+ ptr = NULL;
+ while (attempt > elemCount) {
+ if (oldPtr) {
+ ptr = Tcl_AttemptRealloc(oldPtr, leadSize + attempt * elemSize);
+ } else {
+ ptr = Tcl_AttemptAlloc(leadSize + attempt * elemSize);
+ }
+ if (ptr) {
+ break;
+ }
+ attempt = TclUpsizeRetry(elemCount, attempt);
+ }
+ /* Try exact size as a last resort */
+ if (ptr == NULL) {
+ attempt = elemCount;
+ if (oldPtr) {
+ ptr = Tcl_AttemptRealloc(oldPtr, leadSize + attempt * elemSize);
+ } else {
+ ptr = Tcl_AttemptAlloc(leadSize + attempt * elemSize);
+ }
+ }
+ if (ptr && capacityPtr) {
+ *capacityPtr = attempt;
+ }
+ return ptr;
+}
+
+/*
+ *------------------------------------------------------------------------
+ *
+ * TclReallocElemsEx --
+ *
+ * See TclAttemptReallocElemsEx. This function differs in that it panics
+ * on failure.
+ *
+ * Results:
+ * Non-NULL pointer to allocated memory block.
+ *
+ * Side effects:
+ * Panics if memory of at least the requested size could not be
+ * allocated.
+ *
+ *------------------------------------------------------------------------
+ */
+void *
+TclReallocElemsEx(
+ void *oldPtr, /* Pointer to memory block to reallocate */
+ Tcl_Size elemCount, /* Allocation will store at least these many... */
+ Tcl_Size elemSize, /* ...elements of this size */
+ Tcl_Size leadSize, /* Additional leading space in bytes */
+ Tcl_Size *capacityPtr) /* OUTPUT: Actual capacity is stored
+ here if non-NULL. Only modified on success */
+{
+ void *ptr = TclAttemptReallocElemsEx(
+ oldPtr, elemCount, elemSize, leadSize, capacityPtr);
+ if (ptr == NULL) {
+ Tcl_Panic("Failed to reallocate %" TCL_SIZE_MODIFIER
+ "d elements of size %" TCL_SIZE_MODIFIER "d bytes.",
+ elemCount,
+ elemSize);
+ }
+ return ptr;
+}
+
+/*
*---------------------------------------------------------------------------
*
* TclFinalizeMemorySubsystem --