summaryrefslogtreecommitdiff
path: root/Python/pyarena.c
diff options
context:
space:
mode:
authorNeal Norwitz <nnorwitz@gmail.com>2005-12-17 20:54:49 +0000
committerNeal Norwitz <nnorwitz@gmail.com>2005-12-17 20:54:49 +0000
commitadb69fcdffdc50ee3e1d33b00cd874020197b445 (patch)
tree9ea2ddcf5d0625a43739da1d5db7915ef597c8b1 /Python/pyarena.c
parent23a695891069f619b5b992d877820558bb8dc70f (diff)
downloadcpython-git-adb69fcdffdc50ee3e1d33b00cd874020197b445.tar.gz
Merge from ast-arena. This reduces the code in Python/ast.c by ~300 lines,
simplifies a lot of error handling code, and fixes many memory leaks.
Diffstat (limited to 'Python/pyarena.c')
-rw-r--r--Python/pyarena.c133
1 files changed, 133 insertions, 0 deletions
diff --git a/Python/pyarena.c b/Python/pyarena.c
new file mode 100644
index 0000000000..d67753215e
--- /dev/null
+++ b/Python/pyarena.c
@@ -0,0 +1,133 @@
+#include "Python.h"
+#include "pyarena.h"
+
+/* An arena list is a linked list that can store either pointers or
+ PyObjects. The type is clear from context.
+ */
+
+typedef struct _arena_list {
+ struct _arena_list *al_next;
+ void *al_pointer;
+} PyArenaList;
+
+/* There are two linked lists in an arena, one for malloc pointers and
+ one for PyObject. For each list, there is a pointer to the head
+ and to the tail. The head is used to free the list. The tail is
+ used to add a new element to the list.
+
+ The list always keeps one un-used node at the end of the list.
+*/
+
+struct _arena {
+ PyArenaList *a_malloc_head;
+ PyArenaList *a_malloc_tail;
+ PyArenaList *a_object_head;
+ PyArenaList *a_object_tail;
+};
+
+static PyArenaList*
+PyArenaList_New(void)
+{
+ PyArenaList *alist = (PyArenaList *)malloc(sizeof(PyArenaList));
+ if (!alist)
+ return NULL;
+
+ alist->al_next = NULL;
+ alist->al_pointer = NULL;
+ return alist;
+}
+
+static void
+PyArenaList_FreeObject(PyArenaList *alist)
+{
+ if (!alist)
+ return;
+
+ while (alist) {
+ PyArenaList *prev;
+ Py_XDECREF((PyObject *)alist->al_pointer);
+ alist->al_pointer = NULL;
+ prev = alist;
+ alist = alist->al_next;
+ free(prev);
+ }
+}
+
+static void
+PyArenaList_FreeMalloc(PyArenaList *alist)
+{
+ if (!alist)
+ return;
+
+ while (alist) {
+ PyArenaList *prev;
+ if (alist->al_pointer) {
+ free(alist->al_pointer);
+ }
+ alist->al_pointer = NULL;
+ prev = alist;
+ alist = alist->al_next;
+ free(prev);
+ }
+}
+
+
+PyArena *
+PyArena_New()
+{
+ PyArena* arena = (PyArena *)malloc(sizeof(PyArena));
+ if (!arena)
+ return NULL;
+
+ arena->a_object_head = PyArenaList_New();
+ arena->a_object_tail = arena->a_object_head;
+ arena->a_malloc_head = PyArenaList_New();
+ arena->a_malloc_tail = arena->a_malloc_head;
+ return arena;
+}
+
+void
+PyArena_Free(PyArena *arena)
+{
+ assert(arena);
+ PyArenaList_FreeObject(arena->a_object_head);
+ PyArenaList_FreeMalloc(arena->a_malloc_head);
+ free(arena);
+}
+
+void *
+PyArena_Malloc(PyArena *arena, size_t size)
+{
+ /* A better implementation might actually use an arena. The current
+ approach is just a trivial implementation of the API that allows
+ it to be tested.
+ */
+ void *p;
+ assert(size != 0);
+ p = malloc(size);
+ PyArena_AddMallocPointer(arena, p);
+ return p;
+}
+
+int
+PyArena_AddMallocPointer(PyArena *arena, void *pointer)
+{
+ assert(pointer);
+ PyArenaList *tail = arena->a_malloc_tail;
+ assert(tail->al_pointer != pointer);
+ tail->al_next = PyArenaList_New();
+ tail->al_pointer = pointer;
+ arena->a_malloc_tail = tail->al_next;
+ return 1;
+}
+
+int
+PyArena_AddPyObject(PyArena *arena, PyObject *pointer)
+{
+ assert(pointer);
+ PyArenaList *tail = arena->a_object_tail;
+ tail->al_next = PyArenaList_New();
+ tail->al_pointer = pointer;
+ arena->a_object_tail = tail->al_next;
+ return 1;
+}