oct-locbuf.h

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2008-2012 Jaroslav Hajek
00004 
00005 This file is part of Octave.
00006 
00007 Octave is free software; you can redistribute it and/or modify it
00008 under the terms of the GNU General Public License as published by the
00009 Free Software Foundation; either version 3 of the License, or (at your
00010 option) any later version.
00011 
00012 Octave is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00015 for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Octave; see the file COPYING.  If not, see
00019 <http://www.gnu.org/licenses/>.
00020 
00021 */
00022 
00023 #if !defined (octave_local_buffer_h)
00024 #define octave_local_buffer_h 1
00025 
00026 #include <cstddef>
00027 #include "oct-cmplx.h"
00028 
00029 // The default local buffer simply encapsulates an *array* pointer
00030 // that gets deleted automatically.  For common POD types, we provide
00031 // specializations.
00032 
00033 template <class T>
00034 class octave_local_buffer
00035 {
00036 public:
00037   octave_local_buffer (size_t size)
00038     : data (0)
00039     {
00040       if (size)
00041         data = new T[size];
00042     }
00043   ~octave_local_buffer (void) { delete [] data; }
00044   operator T *() const { return data; }
00045 
00046 private:
00047   T *data;
00048 
00049   // No copying!
00050   octave_local_buffer (const octave_local_buffer&);
00051   octave_local_buffer& operator = (const octave_local_buffer&);
00052 };
00053 
00054 // For buffers of POD types, we'll be smarter.  There is one thing
00055 // that differentiates a local buffer from a dynamic array - the local
00056 // buffers, if not manipulated improperly, have a FIFO semantics,
00057 // meaning that if buffer B is allocated after buffer A, B *must* be
00058 // deallocated before A.  This is *guaranteed* if you use local buffer
00059 // exclusively through the OCTAVE_LOCAL_BUFFER macro, because the C++
00060 // standard requires that explicit local objects be destroyed in
00061 // reverse order of declaration.  Therefore, we can avoid memory
00062 // fragmentation by allocating fairly large chunks of memory and
00063 // serving local buffers from them in a stack-like manner.  The first
00064 // returning buffer in previous chunk will be responsible for
00065 // deallocating the chunk.
00066 
00067 class octave_chunk_buffer
00068 {
00069 public:
00070 
00071   OCTAVE_API octave_chunk_buffer (size_t size);
00072 
00073   OCTAVE_API virtual ~octave_chunk_buffer (void);
00074 
00075   char *data (void) const { return dat; }
00076 
00077   static OCTAVE_API void clear (void);
00078 
00079 private:
00080 
00081   // The number of bytes we allocate for each large chunk of memory we
00082   // manage.
00083   static const size_t chunk_size;
00084 
00085   // Pointer to the end end of the last allocation.
00086   static char *top;
00087 
00088   // Pointer to the current active chunk.
00089   static char *chunk;
00090 
00091   // The number of bytes remaining in the active chunk.
00092   static size_t left;
00093 
00094   // The number of active allocations.
00095   static size_t active;
00096 
00097   // Pointer to the current chunk.
00098   char *cnk;
00099 
00100   // Pointer to the beginning of the most recent allocation.
00101   char *dat;
00102 
00103   // No copying!
00104   octave_chunk_buffer (const octave_chunk_buffer&);
00105   octave_chunk_buffer& operator = (const octave_chunk_buffer&);
00106 };
00107 
00108 // This specializes octave_local_buffer to use the chunked buffer
00109 // mechanism for POD types.
00110 #define SPECIALIZE_POD_BUFFER(TYPE) \
00111 template <> \
00112 class octave_local_buffer<TYPE> : private octave_chunk_buffer \
00113 { \
00114 public: \
00115   octave_local_buffer (size_t size) \
00116     : octave_chunk_buffer (size * sizeof (TYPE)) { } \
00117  \
00118   operator TYPE *() const \
00119   { \
00120     return reinterpret_cast<TYPE *> (this->data ()); \
00121   } \
00122 }
00123 
00124 SPECIALIZE_POD_BUFFER (bool);
00125 SPECIALIZE_POD_BUFFER (char);
00126 SPECIALIZE_POD_BUFFER (unsigned short);
00127 SPECIALIZE_POD_BUFFER (short);
00128 SPECIALIZE_POD_BUFFER (int);
00129 SPECIALIZE_POD_BUFFER (unsigned int);
00130 SPECIALIZE_POD_BUFFER (long);
00131 SPECIALIZE_POD_BUFFER (unsigned long);
00132 SPECIALIZE_POD_BUFFER (float);
00133 SPECIALIZE_POD_BUFFER (double);
00134 // FIXME: Are these guaranteed to be POD and satisfy alignment?
00135 SPECIALIZE_POD_BUFFER (Complex);
00136 SPECIALIZE_POD_BUFFER (FloatComplex);
00137 // MORE ?
00138 
00139 // All pointers and const pointers are also POD types.
00140 template <class T>
00141 class octave_local_buffer<T *> : private octave_chunk_buffer
00142 {
00143 public:
00144   octave_local_buffer (size_t size)
00145     : octave_chunk_buffer (size * sizeof (T *))
00146     { }
00147 
00148   operator T **() const { return reinterpret_cast<T **> (this->data ()); }
00149 };
00150 
00151 template <class T>
00152 class octave_local_buffer<const T *> : private octave_chunk_buffer
00153 {
00154 public:
00155   octave_local_buffer (size_t size)
00156     : octave_chunk_buffer (size * sizeof (const T *))
00157     { }
00158 
00159   operator const T **() const
00160   {
00161     return reinterpret_cast<const T **> (this->data ());
00162   }
00163 };
00164 
00165 // If the compiler supports dynamic stack arrays, we can use the
00166 // attached hack to place small buffer arrays on the stack. It may be
00167 // even faster than our obstack-like optimization, but is dangerous
00168 // because stack is a very limited resource, so we disable it.
00169 
00170 #if 0 // defined (HAVE_DYNAMIC_AUTO_ARRAYS)
00171 
00172 // Maximum buffer size (in bytes) to be placed on the stack.
00173 
00174 #define OCTAVE_LOCAL_BUFFER_MAX_STACK_SIZE 8192
00175 
00176 // If we have automatic arrays, we use an automatic array if the size
00177 // is small enough.  To avoid possibly evaluating 'size' multiple
00178 // times, we first cache it.  Note that we always construct both the
00179 // stack array and the octave_local_buffer object, but only one of
00180 // them will be nonempty.
00181 
00182 #define OCTAVE_LOCAL_BUFFER(T, buf, size) \
00183   const size_t _bufsize_ ## buf = size; \
00184   const bool _lbufaut_ ## buf = _bufsize_ ## buf * sizeof (T) \
00185      <= OCTAVE_LOCAL_BUFFER_MAX_STACK_SIZE; \
00186   T _bufaut_ ## buf [_lbufaut_ ## buf ? _bufsize_ ## buf : 0]; \
00187   octave_local_buffer<T> _bufheap_ ## buf \
00188     (!_lbufaut_ ## buf ? _bufsize_ ## buf : 0); \
00189   T *buf = _lbufaut_ ## buf \
00190     ? _bufaut_ ## buf : static_cast<T *> (_bufheap_ ## buf)
00191 
00192 #else
00193 
00194 // If we don't have automatic arrays, we simply always use
00195 // octave_local_buffer.
00196 
00197 #define OCTAVE_LOCAL_BUFFER(T, buf, size) \
00198   octave_local_buffer<T> _buffer_ ## buf (size); \
00199   T *buf = _buffer_ ## buf
00200 
00201 #endif
00202 
00203 // Note: we use weird variables in the for loop to avoid warnings
00204 // about shadowed parameters.
00205 
00206 #define OCTAVE_LOCAL_BUFFER_INIT(T, buf, size, value) \
00207   OCTAVE_LOCAL_BUFFER(T, buf, size); \
00208   for (size_t _buf_iter = 0, _buf_size = size; \
00209         _buf_iter < _buf_size; _buf_iter++) \
00210     buf[_buf_iter] = value
00211 
00212 #endif
00213 
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines