forgot commit

This commit is contained in:
David Rose 2007-05-13 16:05:44 +00:00
parent 6f2aae0c37
commit 378beb4b63
6 changed files with 666 additions and 0 deletions

View File

@ -0,0 +1,149 @@
// Filename: simpleAllocator.I
// Created by: drose (12May07)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocator::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE SimpleAllocator::
SimpleAllocator(size_t max_size) :
LinkedListNode(true),
_total_size(0),
_max_size(max_size)
{
}
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocator::get_total_size
// Access: Published
// Description: Returns the total size of allocated objects.
////////////////////////////////////////////////////////////////////
INLINE size_t SimpleAllocator::
get_total_size() const {
return _total_size;
}
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocator::get_max_size
// Access: Published
// Description: Returns the available space for allocated objects.
////////////////////////////////////////////////////////////////////
INLINE size_t SimpleAllocator::
get_max_size() const {
return _max_size;
}
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocator::set_max_size
// Access: Published
// Description: Changes the available space for allocated objects.
// This will not affect any already-allocated objects,
// but will have an effect on future calls to alloc().
////////////////////////////////////////////////////////////////////
INLINE void SimpleAllocator::
set_max_size(size_t max_size) {
_max_size = max_size;
}
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocatorBlock::Constructor
// Access: Private
// Description: A SimpleAllocatorBlock must be constructed via the
// SimpleAllocator::alloc() call.
////////////////////////////////////////////////////////////////////
INLINE SimpleAllocatorBlock::
SimpleAllocatorBlock(SimpleAllocator *alloc,
size_t start, size_t size) :
_allocator(alloc),
_start(start),
_size(size)
{
}
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocatorBlock::Destructor
// Access: Published
// Description: The block automatically frees itself when it
// destructs.
////////////////////////////////////////////////////////////////////
INLINE SimpleAllocatorBlock::
~SimpleAllocatorBlock() {
free();
}
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocatorBlock::free
// Access: Published
// Description: Releases the allocated space.
////////////////////////////////////////////////////////////////////
INLINE void SimpleAllocatorBlock::
free() {
if (_allocator != (SimpleAllocator *)NULL) {
_allocator->_total_size -= _size;
remove_from_list();
_allocator = NULL;
}
}
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocatorBlock::get_allocator
// Access: Published
// Description: Returns the SimpleAllocator object that owns this
// block. Returns NULL if the block has been freed.
////////////////////////////////////////////////////////////////////
INLINE SimpleAllocator *SimpleAllocatorBlock::
get_allocator() const {
return _allocator;
}
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocatorBlock::get_start
// Access: Published
// Description: Returns the starting point of this block. It is an
// error to call this if the block has been freed.
////////////////////////////////////////////////////////////////////
INLINE size_t SimpleAllocatorBlock::
get_start() const {
nassertr(_allocator != (SimpleAllocator *)NULL, 0);
return _start;
}
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocatorBlock::get_size
// Access: Published
// Description: Returns the size of this block. It is an
// error to call this if the block has been freed.
////////////////////////////////////////////////////////////////////
INLINE size_t SimpleAllocatorBlock::
get_size() const {
nassertr(_allocator != (SimpleAllocator *)NULL, 0);
return _size;
}
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocatorBlock::is_free
// Access: Published
// Description: Returns true if the block has been freed, false if it
// is still valid.
////////////////////////////////////////////////////////////////////
INLINE bool SimpleAllocatorBlock::
is_free() const {
return (_allocator != (SimpleAllocator *)NULL);
}

View File

@ -0,0 +1,127 @@
// Filename: simpleAllocator.cxx
// Created by: drose (12May07)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "simpleAllocator.h"
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocator::Destructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
SimpleAllocator::
~SimpleAllocator() {
// We're shutting down. Force-free everything remaining.
while (_next != (LinkedListNode *)this) {
nassertv(_next != (LinkedListNode *)NULL);
((SimpleAllocatorBlock *)_next)->free();
}
}
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocator::alloc
// Access: Published
// Description: Allocates a new block. Returns NULL if a block of the
// requested size cannot be allocated.
//
// To free the allocated block, call block->free(), or
// simply delete the block pointer.
////////////////////////////////////////////////////////////////////
SimpleAllocatorBlock *SimpleAllocator::
alloc(size_t size) {
// First fit algorithm: walk through all the empty blocks until we
// find one that has enough room.
SimpleAllocatorBlock *block = NULL;
size_t end = 0;
if (_next != this) {
// We have at least one allocated block.
block = (SimpleAllocatorBlock *)_next;
end = block->_start + block->_size;
// Scan until we have reached the last allocated block.
while (block->_next != this) {
SimpleAllocatorBlock *next = (SimpleAllocatorBlock *)block->_next;
size_t free_size = next->_start - end;
if (size <= free_size) {
SimpleAllocatorBlock *new_block = new SimpleAllocatorBlock(this, end, size);
new_block->insert_before(next);
_total_size += size;
return new_block;
}
block = next;
end = block->_start + block->_size;
}
}
// No free blocks; check for room at the end.
size_t free_size = _max_size - end;
if (size <= free_size) {
SimpleAllocatorBlock *new_block = new SimpleAllocatorBlock(this, end, size);
new_block->insert_before(this);
_total_size += size;
return new_block;
}
// No room for this block.
return NULL;
}
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocator::output
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
void SimpleAllocator::
output(ostream &out) const {
out << "SimpleAllocator, " << _total_size << " of " << _max_size
<< " allocated";
}
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocator::write
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
void SimpleAllocator::
write(ostream &out) const {
out << *this << ":\n";
SimpleAllocatorBlock *block = (SimpleAllocatorBlock *)_next;
while (block->_next != this) {
SimpleAllocatorBlock *next = (SimpleAllocatorBlock *)block->_next;
out << " " << *block << "\n";
block = next;
}
}
////////////////////////////////////////////////////////////////////
// Function: SimpleAllocatorBlock::output
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
void SimpleAllocatorBlock::
output(ostream &out) const {
if (_allocator == (SimpleAllocator *)NULL) {
out << "free block\n";
} else {
out << "block of size " << _size << " at " << _start;
}
}

View File

@ -0,0 +1,107 @@
// Filename: simpleAllocator.h
// Created by: drose (12May07)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef SIMPLEALLOCATOR_H
#define SIMPLEALLOCATOR_H
#include "pandabase.h"
#include "linkedListNode.h"
class SimpleAllocatorBlock;
////////////////////////////////////////////////////////////////////
// Class : SimpleAllocator
// Description : An implementation of a very simple block allocator.
// This class can allocate ranges of nonnegative
// integers within a specified upper limit; it uses a
// simple first-fit algorithm to find the next available
// space.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA SimpleAllocator : public LinkedListNode {
PUBLISHED:
INLINE SimpleAllocator(size_t max_size);
~SimpleAllocator();
SimpleAllocatorBlock *alloc(size_t size);
INLINE size_t get_total_size() const;
INLINE size_t get_max_size() const;
INLINE void set_max_size(size_t max_size);
void output(ostream &out) const;
void write(ostream &out) const;
private:
// This is implemented as a linked-list chain of allocated blocks.
// Free blocks are implicit. Blocks are kept in sorted order from
// beginning to end. Allocating a block means creating a new entry
// in the chain wherever it may fit; freeing a block means simply
// removing the allocated block from the chain. With this simple
// approach, there is no need to merge adjacent free blocks to
// straighten out fragmentation, since free blocks are not stored.
// However, it does mean we have to walk through a list of adjacent
// allocated blocks in order to find the free blocks.
size_t _total_size;
size_t _max_size;
friend class SimpleAllocatorBlock;
};
////////////////////////////////////////////////////////////////////
// Class : SimpleAllocatorBlock
// Description : A single block as returned from
// SimpleAllocator::alloc().
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA SimpleAllocatorBlock : public LinkedListNode {
private:
INLINE SimpleAllocatorBlock(SimpleAllocator *alloc,
size_t start, size_t size);
PUBLISHED:
INLINE ~SimpleAllocatorBlock();
INLINE void free();
INLINE SimpleAllocator *get_allocator() const;
INLINE size_t get_start() const;
INLINE size_t get_size() const;
INLINE bool is_free() const;
void output(ostream &out) const;
private:
SimpleAllocator *_allocator;
size_t _start;
size_t _size;
friend class SimpleAllocator;
};
INLINE ostream &operator << (ostream &out, const SimpleAllocator &obj) {
obj.output(out);
return out;
}
INLINE ostream &operator << (ostream &out, const SimpleAllocatorBlock &obj) {
obj.output(out);
return out;
}
#include "simpleAllocator.I"
#endif

View File

@ -0,0 +1,18 @@
// Filename: vertexDataSaveFile.I
// Created by: drose (12May07)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,204 @@
// Filename: vertexDataSaveFile.cxx
// Created by: drose (12May07)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "vertexDataSaveFile.h"
////////////////////////////////////////////////////////////////////
// Function: VertexDataSaveFile::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
VertexDataSaveFile::
VertexDataSaveFile(const Filename &directory, const string &prefix,
size_t max_size) :
_allocator(max_size)
{
// Try to open and lock a writable temporary filename.
int index = 0;
while (true) {
++index;
ostringstream strm;
strm << prefix << "_" << index << ".dat";
string basename = strm.str();
_filename = Filename(directory, basename);
string os_specific = _filename.to_os_specific();
#ifdef _WIN32
// Windows case.
_handle = CreateFile(os_specific.c_str(), GENERIC_READ | GENERIC_WRITE,
0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE | FILE_FLAG_RANDOM_ACCESS,
NULL);
if (_handle == INVALID_HANDLE_VALUE) {
// Couldn't open the file. Either the directory was bad, or the
// file was locked.
DWORD err = GetLastError();
if (err == ERROR_SHARING_VIOLATION) {
// Try the next file.
break;
}
// File couldn't be opened; permission problem or bogus directory.
// TODO: handle this
}
#else
// Posix case.
_fd = open(os_specific.c_str(), O_RDWR | O_CREAT, 0666);
nassertv(_fd != -1); // TODO: handle this.
// Now try to lock the file, so we can be sure that no other
// process is simultaneously writing to the same save file.
int result = lockf(_fd, F_TLOCK, 0);
if (result == 0) {
// We've got the file. Truncate it first, for good measure, in
// case there's an old version of the file we picked up.
ftruncate(_fd, 0);
// On Unix, it's safe to unlink (delete) the temporary file after
// it's been opened. The file remains open, but disappears from
// the directory. This ensures it won't accidentally get left
// behind should this process crash without closing and deleting
// the file cleanly.
//unlink(os_specific.c_str());
//_filename = Filename();
break;
}
// Try the next file.
close(_fd);
#endif // _WIN32
}
}
////////////////////////////////////////////////////////////////////
// Function: VertexDataSaveFile::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
VertexDataSaveFile::
~VertexDataSaveFile() {
#ifdef _WIN32
if (_handle != NULL) {
CloseHandle(_handle);
}
#else
if (_fd != -1) {
close(_fd);
}
#endif // _WIN32
if (!_filename.empty()) {
_filename.unlink();
}
}
////////////////////////////////////////////////////////////////////
// Function: VertexDataSaveFile::write_data
// Access: Public
// Description: Writes a block of data to the file, and returns a
// handle to the block handle. Returns NULL if the data
// cannot be written (e.g. no remaining space on the
// file).
////////////////////////////////////////////////////////////////////
SimpleAllocatorBlock *VertexDataSaveFile::
write_data(const unsigned char *data, size_t size) {
SimpleAllocatorBlock *block = _allocator.alloc(size);
if (block != (SimpleAllocatorBlock *)NULL) {
#ifdef _WIN32
if (SetFilePointer(_handle, block->get_start(), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
gobj_cat.error()
<< "Error seeking to position " << block->get_start() << " in save file.\n";
return false;
}
DWORD bytes_written;
if (!WriteFile(_handle, data, size, &bytes_written, NULL) ||
bytes_written != size) {
gobj_cat.error()
<< "Error writing " << size << " bytes to save file. Disk full?\n";
delete block;
return NULL;
}
#else
// Posix case.
if (lseek(_fd, block->get_start(), SEEK_SET) == -1) {
gobj_cat.error()
<< "Error seeking to position " << block->get_start() << " in save file.\n";
return false;
}
ssize_t result = write(_fd, data, size);
if (result != (ssize_t)size) {
gobj_cat.error()
<< "Error writing " << size << " bytes to save file. Disk full?\n";
delete block;
return NULL;
}
#endif // _WIN32
}
return block;
}
////////////////////////////////////////////////////////////////////
// Function: VertexDataSaveFile::read_data
// Access: Public
// Description: Reads a block of data from the file, and returns true
// on success, false on failure.
////////////////////////////////////////////////////////////////////
bool VertexDataSaveFile::
read_data(unsigned char *data, size_t size, SimpleAllocatorBlock *block) {
nassertr(size == block->get_size(), false);
#ifdef _WIN32
if (SetFilePointer(_handle, block->get_start(), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
gobj_cat.error()
<< "Error seeking to position " << block->get_start() << " in save file.\n";
return false;
}
DWORD bytes_read;
if (!ReadFile(_handle, data, size, &bytes_read, NULL) ||
bytes_read != size) {
gobj_cat.error()
<< "Error writing " << size << " bytes to save file. Disk full?\n";
delete block;
return NULL;
}
#else
// Posix case.
if (lseek(_fd, block->get_start(), SEEK_SET) == -1) {
gobj_cat.error()
<< "Error seeking to position " << block->get_start() << " in save file.\n";
return false;
}
ssize_t result = read(_fd, data, size);
if (result != (ssize_t)size) {
gobj_cat.error()
<< "Error reading " << size << " bytes from save file.\n";
return false;
}
#endif // _WIN32
return true;
}

View File

@ -0,0 +1,61 @@
// Filename: vertexDataSaveFile.h
// Created by: drose (12May07)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef VERTEXDATASAVEFILE_H
#define VERTEXDATASAVEFILE_H
#include "pandabase.h"
#include "simpleAllocator.h"
#include "filename.h"
#if defined(_WIN32)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
////////////////////////////////////////////////////////////////////
// Class : VertexDataSaveFile
// Description : A temporary file to hold the vertex data that has
// been evicted from memory and written to disk. All
// vertex data arrays are written into one large flat
// file.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA VertexDataSaveFile {
public:
VertexDataSaveFile(const Filename &directory, const string &prefix,
size_t max_size);
~VertexDataSaveFile();
SimpleAllocatorBlock *write_data(const unsigned char *data, size_t size);
bool read_data(unsigned char *data, size_t size,
SimpleAllocatorBlock *block);
private:
SimpleAllocator _allocator;
Filename _filename;
#ifdef _WIN32
HANDLE _handle;
#else
int _fd; // Posix file descriptor
#endif // _WIN32
};
#include "vertexDataSaveFile.I"
#endif