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 #ifdef HAVE_CONFIG_H 00024 #include <config.h> 00025 #endif 00026 00027 #include <iostream> 00028 00029 #include "lo-error.h" 00030 #include "oct-locbuf.h" 00031 00032 // FIXME -- Maybe we should querying for available physical memory? 00033 00034 #ifndef OCTAVE_LOCBUF_CHUNKSIZE_MB 00035 #define OCTAVE_LOCBUF_CHUNKSIZE_MB 32 00036 #endif 00037 00038 // Each chunk will be at least this big. 00039 00040 const size_t octave_chunk_buffer::chunk_size = 00041 static_cast<size_t> (OCTAVE_LOCBUF_CHUNKSIZE_MB) << 20; 00042 00043 char *octave_chunk_buffer::top = 0; 00044 char *octave_chunk_buffer::chunk = 0; 00045 size_t octave_chunk_buffer::left = 0; 00046 size_t octave_chunk_buffer::active = 0; 00047 00048 octave_chunk_buffer::octave_chunk_buffer (size_t size) : cnk (0), dat (0) 00049 { 00050 // Alignment mask. The size of double or long int, whichever is 00051 // greater. All data will be aligned to this size. If it's not 00052 // enough for a type, that type should not be declared as POD. 00053 00054 static const size_t align_mask = (sizeof (long) < sizeof (double) 00055 ? sizeof (double) 00056 : sizeof (long)) - 1; 00057 00058 active++; 00059 00060 if (! size) 00061 return; 00062 00063 // Align size. Note that size_t is unsigned, so size-1 must correctly 00064 // wrap around. 00065 00066 size = ((size - 1) | align_mask) + 1; 00067 00068 if (size > left) 00069 { 00070 // Big buffers (> 1/8 chunk) will be allocated as stand-alone and 00071 // won't disrupt the chain. 00072 00073 if (size > chunk_size >> 3) 00074 { 00075 // Use new [] to get std::bad_alloc if out of memory. 00076 00077 dat = new char [size]; 00078 return; 00079 } 00080 00081 dat = new char [chunk_size]; 00082 chunk = top = dat; 00083 left = chunk_size; 00084 } 00085 00086 // Now allocate memory from the chunk and update state. 00087 00088 cnk = chunk; 00089 dat = top; 00090 left -= size; 00091 top += size; 00092 } 00093 00094 octave_chunk_buffer::~octave_chunk_buffer (void) 00095 { 00096 active--; 00097 00098 if (cnk == chunk) 00099 { 00100 // Our chunk is still the active one. Just restore the state. 00101 00102 left += top - dat; 00103 top = dat; 00104 } 00105 else 00106 { 00107 if (cnk) 00108 { 00109 // Responsible for deletion. 00110 00111 delete [] chunk; 00112 chunk = cnk; 00113 top = dat; 00114 00115 // FIXME -- the following calcuation of remaining data will 00116 // only work if each chunk has the same chunk_size. 00117 00118 left = chunk_size - (dat - cnk); 00119 } 00120 else 00121 { 00122 // We were a stand-alone buffer. 00123 00124 delete [] dat; 00125 } 00126 } 00127 } 00128 00129 // Clear the final chunk of allocated memory. 00130 00131 void 00132 octave_chunk_buffer::clear (void) 00133 { 00134 if (active == 0) 00135 { 00136 delete [] chunk; 00137 chunk = 0; 00138 top = 0; 00139 left = 0; 00140 } 00141 else 00142 { 00143 (*current_liboctave_warning_handler) 00144 ("octave_chunk_buffer::clear: %d active allocations remain!", 00145 active); 00146 } 00147 }