diff liboctave/oct-locbuf.h @ 8400:7b6e1fc1cb90

implement obstack-like optimization of local buffers
author Jaroslav Hajek <highegg@gmail.com>
date Fri, 12 Dec 2008 12:45:31 +0100
parents ad8ed668e0a4
children f274fbc29747
line wrap: on
line diff
--- a/liboctave/oct-locbuf.h
+++ b/liboctave/oct-locbuf.h
@@ -24,6 +24,7 @@
 #define octave_local_buffer_h 1
 
 #include <cstddef>
+#include "oct-cmplx.h"
 
 // The default local buffer simply encapsulates an *array* pointer that gets
 // delete[]d automatically. For common POD types, we provide specializations.
@@ -44,11 +45,68 @@
   T *data;
 };
 
+// For buffers of POD types, we'll be more smart. There is one thing that
+// differentiates a local buffer from a dynamic array - the local buffers, if
+// not manipulated improperly, have a FIFO semantics, meaning that if buffer B
+// is allocated after buffer A, B *must* be deallocated before A. This is
+// *guaranteed* if you use local buffer exclusively through the
+// OCTAVE_LOCAL_BUFFER macro, because the C++ standard *mandates* explicit
+// local objects be destroyed in reverse order of declaration.
+// Therefore, we can avoid memory fragmentation by allocating fairly large
+// chunks of memory and serving local buffers from them in a stack-like manner.
+// The first returning buffer in previous chunk will be responsible for
+// deallocating the chunk.
 
-// If the compiler supports dynamic stack arrays, we can use the attached hack to 
-// place small buffer arrays on the stack. 
+class octave_chunk_buffer
+{
+  static const size_t chunk_size;
+
+  static char *top, *chunk;
+  static size_t left;
+
+  char *cnk;
+  char *dat;
+
+public:
+
+  octave_chunk_buffer (size_t size);
+
+  ~octave_chunk_buffer (void);
+
+  char *data (void) const { return dat; }
+};
 
-#ifdef HAVE_DYNAMIC_AUTO_ARRAYS
+// This specializes octave_local_buffer to use the chunked buffer mechanism
+// for POD types.
+#define SPECIALIZE_POD_BUFFER(TYPE) \
+template <> \
+class octave_local_buffer<TYPE> : private octave_chunk_buffer \
+{ \
+public: \
+  octave_local_buffer (size_t size) : octave_chunk_buffer (size * sizeof (TYPE)) { } \
+  operator TYPE *() const { return reinterpret_cast<TYPE *> (this->data ()); } \
+}
+
+SPECIALIZE_POD_BUFFER (bool);
+SPECIALIZE_POD_BUFFER (char);
+SPECIALIZE_POD_BUFFER (unsigned short);
+SPECIALIZE_POD_BUFFER (short);
+SPECIALIZE_POD_BUFFER (int);
+SPECIALIZE_POD_BUFFER (unsigned int);
+SPECIALIZE_POD_BUFFER (long);
+SPECIALIZE_POD_BUFFER (unsigned long);
+SPECIALIZE_POD_BUFFER (float);
+SPECIALIZE_POD_BUFFER (double);
+// FIXME: Are these guaranteed to be POD and satisfy alignment?
+SPECIALIZE_POD_BUFFER (Complex);
+SPECIALIZE_POD_BUFFER (FloatComplex);
+// MORE ?
+
+// If the compiler supports dynamic stack arrays, we can use the attached hack
+// to place small buffer arrays on the stack. It may be even faster than our
+// obstack-like optimization, but is dangerous because stack is a very limited
+// resource, so we disable it.
+#if 0 //defined (HAVE_DYNAMIC_AUTO_ARRAYS)
 
 // Maximum buffer size (in bytes) to be placed on the stack.