GNU Octave 7.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
BlockArray.cpp
Go to the documentation of this file.
1/*
2 This file is part of Konsole, an X terminal.
3 Copyright (C) 2000, 2013 by Stephan Kulow <coolo@kde.org>
4
5 Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
6
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301 USA.
21
22*/
23
24// Own
25#include "unix/BlockArray.h"
26
27#include <QtCore>
28
29// System
30#include <assert.h>
31#include <sys/mman.h>
32#include <sys/param.h>
33#include <unistd.h>
34#include <stdio.h>
35
36
37static int blocksize = 0;
38
40 : size(0),
41 current(size_t(-1)),
42 index(size_t(-1)),
43 lastmap(nullptr),
44 lastmap_index(size_t(-1)),
45 lastblock(nullptr), ion(-1),
46 length(0)
47{
48 // lastmap_index = index = current = size_t(-1);
49 if (blocksize == 0)
50 blocksize = ((sizeof(Block) / getpagesize()) + 1) * getpagesize();
51
52}
53
55{
57 assert(!lastblock);
58}
59
61{
62 if (!size)
63 return size_t(-1);
64
65 ++current;
66 if (current >= size) current = 0;
67
68 int rc;
69 rc = lseek(ion, current * blocksize, SEEK_SET); if (rc < 0) { perror("HistoryBuffer::add.seek"); setHistorySize(0); return size_t(-1); }
70 rc = write(ion, block, blocksize); if (rc < 0) { perror("HistoryBuffer::add.write"); setHistorySize(0); return size_t(-1); }
71
72 length++;
73 if (length > size) length = size;
74
75 ++index;
76
77 delete block;
78 return current;
79}
80
82{
83 if (!size)
84 return size_t(-1);
86
87 lastblock = new Block();
88 return index + 1;
89}
90
92{
93 return lastblock;
94}
95
96bool BlockArray::has(size_t i) const
97{
98 if (i == index + 1)
99 return true;
100
101 if (i > index)
102 return false;
103 if (index - i >= length)
104 return false;
105 return true;
106}
107
108const Block* BlockArray::at(size_t i)
109{
110 if (i == index + 1)
111 return lastblock;
112
113 if (i == lastmap_index)
114 return lastmap;
115
116 if (i > index) {
117 qDebug() << "BlockArray::at() i > index\n";
118 return nullptr;
119 }
120
121// if (index - i >= length) {
122// kDebug(1211) << "BlockArray::at() index - i >= length\n";
123// return 0;
124// }
125
126 size_t j = i; // (current - (index - i) + (index/size+1)*size) % size ;
127
128 assert(j < size);
129 unmap();
130
131 Block *block = (Block*)mmap(nullptr, blocksize, PROT_READ, MAP_PRIVATE, ion, j * blocksize);
132
133 if (block == (Block*)-1) { perror("mmap"); return nullptr; }
134
135 lastmap = block;
136 lastmap_index = i;
137
138 return block;
139}
140
142{
143 if (lastmap) {
144 int res = munmap((char*)lastmap, blocksize);
145 if (res < 0) perror("munmap");
146 }
147 lastmap = nullptr;
148 lastmap_index = size_t(-1);
149}
150
151bool BlockArray::setSize(size_t newsize)
152{
153 return setHistorySize(newsize * 1024 / blocksize);
154}
155
156bool BlockArray::setHistorySize(size_t newsize)
157{
158// kDebug(1211) << "setHistorySize " << size << " " << newsize;
159
160 if (size == newsize)
161 return false;
162
163 unmap();
164
165 if (!newsize) {
166 delete lastblock;
167 lastblock = nullptr;
168 if (ion >= 0) close(ion);
169 ion = -1;
170 current = size_t(-1);
171 return true;
172 }
173
174 if (!size) {
175 FILE* tmp = tmpfile();
176 if (!tmp) {
177 perror("konsole: cannot open temp file.\n");
178 } else {
179 ion = dup(fileno(tmp));
180 if (ion<0) {
181 perror("konsole: cannot dup temp file.\n");
182 fclose(tmp);
183 }
184 }
185 if (ion < 0)
186 return false;
187
188 assert(!lastblock);
189
190 lastblock = new Block();
191 size = newsize;
192 return false;
193 }
194
195 if (newsize > size) {
197 size = newsize;
198 return false;
199 } else {
200 decreaseBuffer(newsize);
201 if (ftruncate(ion, length*blocksize) == -1)
202 perror("ftruncate");
203 size = newsize;
204
205 return true;
206 }
207}
208
209void moveBlock(FILE *fion, int cursor, int newpos, char *buffer2)
210{
211 int res = fseek(fion, static_cast<long int> (cursor) * blocksize, SEEK_SET);
212 if (res)
213 perror("fseek");
214 res = fread(buffer2, blocksize, 1, fion);
215 if (res != 1)
216 perror("fread");
217
218 res = fseek(fion, static_cast<long int> (newpos) * blocksize, SEEK_SET);
219 if (res)
220 perror("fseek");
221 res = fwrite(buffer2, blocksize, 1, fion);
222 if (res != 1)
223 perror("fwrite");
224 // printf("moving block %d to %d\n", cursor, newpos);
225}
226
227void BlockArray::decreaseBuffer(size_t newsize)
228{
229 if (index < newsize) // still fits in whole
230 return;
231
232 int offset = (current - (newsize - 1) + size) % size;
233
234 if (!offset)
235 return;
236
237 // The Block constructor could do somthing in future...
238 char *buffer1 = new char[blocksize];
239
240 FILE *fion = fdopen(dup(ion), "w+b");
241 if (!fion) {
242 delete [] buffer1;
243 perror("fdopen/dup");
244 return;
245 }
246
247 int firstblock;
248 if (current <= newsize) {
249 firstblock = current + 1;
250 } else {
251 firstblock = 0;
252 }
253
254 size_t oldpos;
255 for (size_t i = 0, cursor=firstblock; i < newsize; i++) {
256 oldpos = (size + cursor + offset) % size;
257 moveBlock(fion, oldpos, cursor, buffer1);
258 if (oldpos < newsize) {
259 cursor = oldpos;
260 } else
261 cursor++;
262 }
263
264 current = newsize - 1;
265 length = newsize;
266
267 delete [] buffer1;
268
269 fclose(fion);
270
271}
272
274{
275 if (index < size) // not even wrapped once
276 return;
277
278 int offset = (current + size + 1) % size;
279 if (!offset) // no moving needed
280 return;
281
282 // The Block constructor could do somthing in future...
283 char *buffer1 = new char[blocksize];
284 char *buffer2 = new char[blocksize];
285
286 int runs = 1;
287 int bpr = size; // blocks per run
288
289 if (size % offset == 0) {
290 bpr = size / offset;
291 runs = offset;
292 }
293
294 FILE *fion = fdopen(dup(ion), "w+b");
295 if (!fion) {
296 perror("fdopen/dup");
297 delete [] buffer1;
298 delete [] buffer2;
299 return;
300 }
301
302 int res;
303 for (int i = 0; i < runs; i++)
304 {
305 // free one block in chain
306 int firstblock = (offset + i) % size;
307 res = fseek(fion, static_cast<long int> (firstblock) * blocksize, SEEK_SET);
308 if (res)
309 perror("fseek");
310 res = fread(buffer1, blocksize, 1, fion);
311 if (res != 1)
312 perror("fread");
313 int newpos = 0;
314 for (int j = 1, cursor=firstblock; j < bpr; j++)
315 {
316 cursor = (cursor + offset) % size;
317 newpos = (cursor - offset + size) % size;
318 moveBlock(fion, cursor, newpos, buffer2);
319 }
320 res = fseek(fion, static_cast<long int> (i) * blocksize, SEEK_SET);
321 if (res)
322 perror("fseek");
323 res = fwrite(buffer1, blocksize, 1, fion);
324 if (res != 1)
325 perror("fwrite");
326 }
327 current = size - 1;
328 length = size;
329
330 delete [] buffer1;
331 delete [] buffer2;
332
333 fclose(fion);
334
335}
static int blocksize
Definition: BlockArray.cpp:37
void moveBlock(FILE *fion, int cursor, int newpos, char *buffer2)
Definition: BlockArray.cpp:209
#define SEEK_SET
bool has(size_t index) const
Definition: BlockArray.cpp:96
size_t current
Definition: BlockArray.h:106
size_t length
Definition: BlockArray.h:114
void decreaseBuffer(size_t newsize)
Definition: BlockArray.cpp:227
size_t newBlock()
Definition: BlockArray.cpp:81
Block * lastblock
Definition: BlockArray.h:111
void increaseBuffer()
Definition: BlockArray.cpp:273
void unmap()
Definition: BlockArray.cpp:141
size_t index
Definition: BlockArray.h:107
BlockArray()
Creates a history file for holding maximal size blocks.
Definition: BlockArray.cpp:39
const Block * at(size_t index)
gets the block at the index.
Definition: BlockArray.cpp:108
~BlockArray()
destructor
Definition: BlockArray.cpp:54
Block * lastBlock() const
Definition: BlockArray.cpp:91
bool setSize(size_t newsize)
Convenient function to set the size in KBytes instead of blocks.
Definition: BlockArray.cpp:151
bool setHistorySize(size_t newsize)
reorders blocks as needed.
Definition: BlockArray.cpp:156
size_t lastmap_index
Definition: BlockArray.h:110
size_t append(Block *block)
adds the Block at the end of history.
Definition: BlockArray.cpp:60
size_t size
Definition: BlockArray.h:104
Block * lastmap
Definition: BlockArray.h:109