diff --git a/libinterp/corefcn/interpreter.cc b/libinterp/corefcn/interpreter.cc --- a/libinterp/corefcn/interpreter.cc +++ b/libinterp/corefcn/interpreter.cc @@ -1161,8 +1161,6 @@ namespace octave // is unloaded. // // OCTAVE_SAFE_CALL (singleton_cleanup_list::cleanup, ()); - - OCTAVE_SAFE_CALL (chunk_buffer::clear, ()); } tree_evaluator& interpreter::get_evaluator (void) diff --git a/liboctave/util/module.mk b/liboctave/util/module.mk --- a/liboctave/util/module.mk +++ b/liboctave/util/module.mk @@ -81,7 +81,6 @@ UTIL_SRC = \ %reldir%/oct-base64.cc \ %reldir%/oct-glob.cc \ %reldir%/oct-inttypes.cc \ - %reldir%/oct-locbuf.cc \ %reldir%/oct-mutex.cc \ %reldir%/oct-shlib.cc \ %reldir%/oct-sparse.cc \ diff --git a/liboctave/util/oct-locbuf.h b/liboctave/util/oct-locbuf.h --- a/liboctave/util/oct-locbuf.h +++ b/liboctave/util/oct-locbuf.h @@ -26,198 +26,26 @@ along with Octave; see the file COPYING. #include "octave-config.h" #include -#include "oct-cmplx.h" - -namespace octave -{ - // The default local buffer simply encapsulates an *array* pointer - // that gets deleted automatically. For common POD types, we provide - // specializations. - - template - class local_buffer - { - public: - - // Always allocate, even for zero-size buffers so that local - // buffers always have valid addresses, same as for directly using - // operator new. - - local_buffer (size_t size) : data (new T [size]) { } - - // No copying! - - local_buffer (const local_buffer&) = delete; - - local_buffer& operator = (const local_buffer&) = delete; - - ~local_buffer (void) { delete [] data; } - - operator T *() const { return data; } - - private: - - T *data; - }; - - // For buffers of POD types, we'll be smarter. 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 requires that 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. - - class chunk_buffer - { - public: - - OCTAVE_API chunk_buffer (size_t size); - - // No copying! - - chunk_buffer (const chunk_buffer&) = delete; - - chunk_buffer& operator = (const chunk_buffer&) = delete; - - OCTAVE_API virtual ~chunk_buffer (void); - - char * data (void) const { return dat; } - - static OCTAVE_API void clear (void); - - private: - - // The number of bytes we allocate for each large chunk of memory we - // manage. - static const size_t chunk_size; - - // Pointer to the end end of the last allocation. - static char *top; - - // Pointer to the current active chunk. - static char *chunk; - - // The number of bytes remaining in the active chunk. - static size_t left; - // The number of active allocations. - static size_t active; - - // Pointer to the current chunk. - char *cnk; - - // Pointer to the beginning of the most recent allocation. - char *dat; - }; - - // This specializes local_buffer to use the chunked buffer - // mechanism for POD types. -#define SPECIALIZE_POD_BUFFER(TYPE) \ - template <> \ - class local_buffer : private chunk_buffer \ - { \ - public: \ - local_buffer (size_t size) \ - : chunk_buffer (size * sizeof (TYPE)) { } \ - \ - operator TYPE *() const \ - { \ - return reinterpret_cast (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 ? +#include +#include - // All pointers and const pointers are also POD types. - template - class local_buffer : private chunk_buffer - { - public: - local_buffer (size_t size) - : chunk_buffer (size * sizeof (T *)) - { } - - operator T **() const { return reinterpret_cast (this->data ()); } - }; - - template - class local_buffer : private chunk_buffer - { - public: - local_buffer (size_t size) - : chunk_buffer (size * sizeof (const T *)) - { } - - operator const T **() const - { - return reinterpret_cast (this->data ()); - } - }; -} - -// 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. - -#define OCTAVE_LOCAL_BUFFER_MAX_STACK_SIZE 8192 - -// If we have automatic arrays, we use an automatic array if the size -// is small enough. To avoid possibly evaluating 'size' multiple -// times, we first cache it. Note that we always construct both the -// stack array and the octave::local_buffer object, but only one of -// them will be nonempty. +#if __cplusplus >= 201402L #define OCTAVE_LOCAL_BUFFER(T, buf, size) \ - const size_t _bufsize_ ## buf = size; \ - const bool _lbufaut_ ## buf = _bufsize_ ## buf * sizeof (T) \ - <= OCTAVE_LOCAL_BUFFER_MAX_STACK_SIZE; \ - T _bufaut_ ## buf [_lbufaut_ ## buf ? _bufsize_ ## buf : 0]; \ - octave::local_buffer _bufheap_ ## buf (! _lbufaut_ ## buf ? _bufsize_ ## buf : 0); \ - T *buf = (_lbufaut_ ## buf \ - ? _bufaut_ ## buf : static_cast (_bufheap_ ## buf)) + auto octave_local_buffer_ ## buf = std::make_unique (size); \ + T *buf = octave_local_buffer_ ## buf.get () #else -// If we don't have automatic arrays, we simply always use -// octave::local_buffer. - -#define OCTAVE_LOCAL_BUFFER(T, buf, size) \ - octave::local_buffer _buffer_ ## buf (size); \ - T *buf = _buffer_ ## buf +#define OCTAVE_LOCAL_BUFFER(T, buf, size) \ + std::unique_ptr octave_local_buffer_ ## buf { new T [size] }; \ + T *buf = octave_local_buffer_ ## buf.get () #endif -// Note: we use weird variables in the for loop to avoid warnings -// about shadowed parameters. - -#define OCTAVE_LOCAL_BUFFER_INIT(T, buf, size, value) \ - OCTAVE_LOCAL_BUFFER (T, buf, size); \ - for (size_t _buf_iter = 0, _buf_size = size; \ - _buf_iter < _buf_size; _buf_iter++) \ - buf[_buf_iter] = value +#define OCTAVE_LOCAL_BUFFER_INIT(T, buf, size, value) \ + OCTAVE_LOCAL_BUFFER (T, buf, size); \ + std::fill_n (buf, size, value) #endif