PageRenderTime 18ms CodeModel.GetById 2ms app.highlight 13ms RepoModel.GetById 1ms app.codeStats 0ms

/src/FreeImage/Source/FreeImage/CacheFile.cpp

https://bitbucket.org/cabalistic/ogredeps/
C++ | 271 lines | 164 code | 72 blank | 35 comment | 33 complexity | c7965be9b0f5a6f60afcff179ec20aeb MD5 | raw file
  1// ==========================================================
  2// Multi-Page functions
  3//
  4// Design and implementation by
  5// - Floris van den Berg (flvdberg@wxs.nl)
  6// - checkered (checkered@users.sourceforge.net)
  7//
  8// This file is part of FreeImage 3
  9//
 10// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
 11// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
 12// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
 13// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
 14// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
 15// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
 16// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
 17// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
 18// THIS DISCLAIMER.
 19//
 20// Use at your own risk!
 21// ==========================================================
 22
 23#ifdef _MSC_VER 
 24#pragma warning (disable : 4786) // identifier was truncated to 'number' characters
 25#endif 
 26
 27#include "CacheFile.h"
 28
 29// ----------------------------------------------------------
 30
 31CacheFile::CacheFile(const std::string filename, BOOL keep_in_memory) :
 32m_file(NULL),
 33m_filename(filename),
 34m_free_pages(),
 35m_page_cache_mem(),
 36m_page_cache_disk(),
 37m_page_map(),
 38m_page_count(0),
 39m_current_block(NULL),
 40m_keep_in_memory(keep_in_memory) {
 41}
 42
 43CacheFile::~CacheFile() {
 44}
 45
 46BOOL
 47CacheFile::open() {
 48	if ((!m_filename.empty()) && (!m_keep_in_memory)) {
 49		m_file = fopen(m_filename.c_str(), "w+b");
 50		return (m_file != NULL);
 51	}
 52
 53	return (m_keep_in_memory == TRUE);
 54}
 55
 56void
 57CacheFile::close() {
 58	// dispose the cache entries
 59
 60	while (!m_page_cache_disk.empty()) {
 61		Block *block = *m_page_cache_disk.begin();
 62		m_page_cache_disk.pop_front();
 63		delete [] block->data;
 64		delete block;
 65	}
 66	while (!m_page_cache_mem.empty()) { 
 67		Block *block = *m_page_cache_mem.begin(); 
 68		m_page_cache_mem.pop_front(); 
 69		delete [] block->data; 
 70		delete block; 
 71	} 
 72
 73	if (m_file) {
 74		// close the file
 75
 76		fclose(m_file);
 77
 78		// delete the file
 79
 80		remove(m_filename.c_str());
 81	}
 82}
 83
 84void
 85CacheFile::cleanupMemCache() {
 86	if (!m_keep_in_memory) {
 87		if (m_page_cache_mem.size() > CACHE_SIZE) {
 88			// flush the least used block to file
 89
 90			Block *old_block = m_page_cache_mem.back();
 91			fseek(m_file, old_block->nr * BLOCK_SIZE, SEEK_SET);
 92			fwrite(old_block->data, BLOCK_SIZE, 1, m_file);
 93
 94			// remove the data
 95
 96			delete [] old_block->data;
 97			old_block->data = NULL;
 98
 99			// move the block to another list
100
101			m_page_cache_disk.splice(m_page_cache_disk.begin(), m_page_cache_mem, --m_page_cache_mem.end());
102			m_page_map[old_block->nr] = m_page_cache_disk.begin();
103		}
104	}
105}
106
107int
108CacheFile::allocateBlock() {
109	Block *block = new Block;
110	block->data = new BYTE[BLOCK_SIZE];
111	block->next = 0;
112
113	if (!m_free_pages.empty()) {
114		block->nr = *m_free_pages.begin();
115		m_free_pages.pop_front();
116	} else {
117		block->nr = m_page_count++;
118	}
119
120	m_page_cache_mem.push_front(block);
121	m_page_map[block->nr] = m_page_cache_mem.begin();
122
123	cleanupMemCache();
124
125	return block->nr;
126}
127
128Block *
129CacheFile::lockBlock(int nr) {
130	if (m_current_block == NULL) {
131		PageMapIt it = m_page_map.find(nr);
132
133		if (it != m_page_map.end()) {
134			m_current_block = *(it->second);
135
136			// the block is swapped out to disc. load it back
137			// and remove the block from the cache. it might get cached
138			// again as soon as the memory buffer fills up
139
140			if (m_current_block->data == NULL) {
141				m_current_block->data = new BYTE[BLOCK_SIZE];
142
143				fseek(m_file, m_current_block->nr * BLOCK_SIZE, SEEK_SET);
144				fread(m_current_block->data, BLOCK_SIZE, 1, m_file);
145
146				m_page_cache_mem.splice(m_page_cache_mem.begin(), m_page_cache_disk, it->second);
147				m_page_map[nr] = m_page_cache_mem.begin();
148			}
149
150			// if the memory cache size is too large, swap an item to disc
151
152			cleanupMemCache();
153
154			// return the current block
155
156			return m_current_block;
157		}
158	}
159
160	return NULL;
161}
162
163BOOL
164CacheFile::unlockBlock(int nr) {
165	if (m_current_block) {
166		m_current_block = NULL;
167
168		return TRUE;
169	}
170
171	return FALSE;
172}
173
174BOOL
175CacheFile::deleteBlock(int nr) {
176	if (!m_current_block) {
177		PageMapIt it = m_page_map.find(nr);
178
179		// remove block from cache
180
181		if (it != m_page_map.end())
182			m_page_map.erase(nr);
183
184		// add block to free page list
185
186		m_free_pages.push_back(nr);
187
188		return TRUE;
189	}
190
191	return FALSE;
192}
193
194BOOL
195CacheFile::readFile(BYTE *data, int nr, int size) {
196	if ((data) && (size > 0)) {
197		int s = 0;
198		int block_nr = nr;
199
200		do {
201			int copy_nr = block_nr;
202
203			Block *block = lockBlock(copy_nr);
204
205			block_nr = block->next;
206
207			memcpy(data + s, block->data, (s + BLOCK_SIZE > size) ? size - s : BLOCK_SIZE);
208
209			unlockBlock(copy_nr);
210
211			s += BLOCK_SIZE;
212		} while (block_nr != 0);
213
214		return TRUE;
215	}
216
217	return FALSE;
218}
219
220int
221CacheFile::writeFile(BYTE *data, int size) {
222	if ((data) && (size > 0)) {
223		int nr_blocks_required = 1 + (size / BLOCK_SIZE);
224		int count = 0;
225		int s = 0;
226		int stored_alloc;
227		int alloc;
228		
229		stored_alloc = alloc = allocateBlock();
230
231		do {
232			int copy_alloc = alloc;
233
234			Block *block = lockBlock(copy_alloc);
235
236			block->next = 0;
237
238			memcpy(block->data, data + s, (s + BLOCK_SIZE > size) ? size - s : BLOCK_SIZE);
239
240			if (count + 1 < nr_blocks_required)
241				alloc = block->next = allocateBlock();
242
243			unlockBlock(copy_alloc);
244
245			s += BLOCK_SIZE;			
246		} while (++count < nr_blocks_required);
247
248		return stored_alloc;
249	}
250
251	return 0;
252}
253
254void
255CacheFile::deleteFile(int nr) {
256	do {
257		Block *block = lockBlock(nr);
258
259		if (block == NULL)
260			break;
261
262		int next = block->next;
263
264		unlockBlock(nr);
265
266		deleteBlock(nr);
267
268		nr = next;
269	} while (nr != 0);
270}
271