mirror of https://github.com/CGAL/cgal
1032 lines
26 KiB
C++
1032 lines
26 KiB
C++
// Copyright (c) 1998 ETH Zurich (Switzerland).
|
|
// All rights reserved.
|
|
//
|
|
// This file is part of CGAL (www.cgal.org); you may redistribute it under
|
|
// the terms of the Q Public License version 1.0.
|
|
// See the file LICENSE.QPL distributed with CGAL.
|
|
//
|
|
// Licensees holding a valid commercial license may use this file in
|
|
// accordance with the commercial license agreement provided with the software.
|
|
//
|
|
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
|
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
//
|
|
// $Source$
|
|
// $Revision$ $Date$
|
|
// $Name$
|
|
//
|
|
// Author(s) : Gabriele Neyer<neyer@inf.ethz.ch>
|
|
#ifndef __CACHE_H__
|
|
#define __CACHE_H__
|
|
#ifdef CGAL_D_DOGN_Cache
|
|
#define CGAL_DOGN_Cache(cmd) cmd
|
|
#else
|
|
#define CGAL_DOGN_Cache(cmd)
|
|
#endif
|
|
|
|
#include <CGAL/basic.h>
|
|
#include <ctime>
|
|
#include <fstream>
|
|
#include <cstring>
|
|
#include <cassert>
|
|
|
|
CGAL_BEGIN_NAMESPACE
|
|
|
|
//first written element in the data file. It stores implicitly
|
|
//a list of deleted elements by link pfirst. The element pfirst
|
|
//points to then stores a link to the next deleted element.
|
|
//plast always keeps the end of file position.
|
|
class Theader{
|
|
public:
|
|
typedef ptrdiff_t difference_type;
|
|
int pfirst; //position of first deleted element
|
|
int plast; //end of file position
|
|
int number_of_elements;
|
|
// size_t size(void) { return 3*sizeof(int)+3; }
|
|
size_t size(void) { return 3*sizeof(int); }
|
|
Theader() : pfirst(-1), plast(0), number_of_elements(0) {}
|
|
|
|
void read(char **s){
|
|
int sint=(int)sizeof(int);
|
|
char *from_int=new char[sint];
|
|
int i,r=0;
|
|
for (i=0; i<sint; i++)
|
|
from_int[i] = (*s)[i];
|
|
r += sint;
|
|
pfirst=*((int *)from_int);
|
|
|
|
for (i=0; i<sint; i++)
|
|
from_int[i] = (*s)[i+r];
|
|
r += sint;
|
|
plast=*((int *)from_int);
|
|
|
|
for (i=0; i<sint; i++)
|
|
from_int[i] = (*s)[i+r];
|
|
number_of_elements=*((int *)from_int);
|
|
CGAL_DOGN_Cache(
|
|
std::cerr << "Theader number of elements:"
|
|
<< number_of_elements << std::endl;
|
|
)
|
|
delete[] from_int;
|
|
}
|
|
void write (char **s) {
|
|
int sint=(int)sizeof(int);
|
|
char *from_int=new char[sint];
|
|
int i,r=0;
|
|
memcpy(from_int,(char *)(&pfirst),sint);
|
|
for (i=0; i<sint; i++){
|
|
(*s)[i] = from_int[i];
|
|
}
|
|
r += sint;
|
|
memcpy(from_int, (char *)(&plast),sint);
|
|
for (i=0; i<sint; i++)
|
|
(*s)[i+r] = from_int[i];
|
|
r += sint;
|
|
memcpy(from_int, (char *)(&number_of_elements),sint);
|
|
for (i=0; i<sint; i++)
|
|
(*s)[i+r] = from_int[i];
|
|
r += sint;
|
|
delete[] from_int;
|
|
CGAL_DOGN_Cache(
|
|
std::cerr << "Theader number of elements:"
|
|
<< number_of_elements << std::endl;
|
|
)
|
|
}
|
|
};
|
|
|
|
//Every stored item is associated with such a struct.
|
|
//Here we store if the element is still valid. If it is
|
|
//not valid a pointer to the next non valid element is
|
|
//stored (pnext).
|
|
class Telem {
|
|
public:
|
|
typedef ptrdiff_t difference_type;
|
|
bool dirty; //true if the element has to be written on disk
|
|
bool deleted;
|
|
int pnext;
|
|
time_t t;
|
|
|
|
// size_t size(void)
|
|
// { return 2*sizeof(bool) + sizeof(int) + sizeof(time_t)+4; }
|
|
size_t size(void) { return 2*sizeof(bool) + sizeof(int) + sizeof(time_t);}
|
|
void read(char **s){
|
|
int sint=(int)sizeof(int);
|
|
int sbool=(int)sizeof(bool);
|
|
int stime_t=(int)sizeof(time_t);
|
|
|
|
char *from_bool=new char[sbool];
|
|
char *from_int=new char[sint];
|
|
char *from_time_t=new char[stime_t];
|
|
int i,r=0;
|
|
for (i=0; i<sbool; i++)
|
|
from_bool[i] = (*s)[i];
|
|
r += sbool;
|
|
dirty=*(reinterpret_cast<bool *>(from_bool));
|
|
|
|
for (i=0; i<sbool; i++)
|
|
from_bool[i] = (*s)[i+r];
|
|
r += sbool;
|
|
deleted=*(reinterpret_cast<bool *>(from_bool));
|
|
|
|
for (i=0; i<sint; i++)
|
|
from_int[i] = (*s)[i+r];
|
|
r += sint;
|
|
pnext=*((int *)from_int);
|
|
|
|
for (i=0; i<stime_t; i++)
|
|
from_time_t[i] = (*s)[i+r];
|
|
r += stime_t;
|
|
t=(int)from_time_t;
|
|
|
|
delete[] from_int;
|
|
delete[] from_bool;
|
|
delete[] from_time_t;
|
|
}
|
|
|
|
void write (char **s) {
|
|
int sint=(int)sizeof(int);
|
|
int sbool=(int)sizeof(bool);
|
|
int stime_t=(int)sizeof(time_t);
|
|
|
|
char *from_bool=new char[sbool];
|
|
char *from_int=new char[sint];
|
|
char *from_time_t=new char[stime_t];
|
|
int i,r=0;
|
|
memcpy(from_bool,(char *)(&dirty),sbool);
|
|
for (i=0; i<sbool; i++)
|
|
(*s)[i] = from_bool[i];
|
|
r += sbool;
|
|
|
|
memcpy(from_bool, (char *)(&deleted), sbool);
|
|
for (i=0; i<sbool; i++)
|
|
(*s)[i+r] = from_bool[i];
|
|
r += sbool;
|
|
|
|
memcpy(from_int,(char *)(&pnext),sint);
|
|
for (i=0; i<sint; i++)
|
|
(*s)[i+r] = from_int[i];
|
|
r += sint;
|
|
|
|
memcpy(from_time_t,(char *)(&t),stime_t);
|
|
for (i=0; i<stime_t; i++)
|
|
(*s)[i+r] = from_time_t[i];
|
|
|
|
delete[] from_int;
|
|
delete[] from_bool;
|
|
delete[] from_time_t;
|
|
}
|
|
|
|
};
|
|
|
|
|
|
struct Buffer_item{
|
|
typedef ptrdiff_t difference_type;
|
|
typedef Buffer_item B_i;
|
|
Telem elem;
|
|
char *raw_data;
|
|
difference_type diskpos;
|
|
B_i *next;
|
|
B_i *prev;
|
|
};
|
|
|
|
|
|
|
|
//Elements of arbitrary types T that provide a read and a
|
|
//write function are stored in a file.
|
|
template <const int PagesInMemory>
|
|
class cache{
|
|
public:
|
|
std::fstream XX;
|
|
int IO_pagesize;
|
|
const static int IO_pages=PagesInMemory;
|
|
typedef Buffer_item BufferItem;
|
|
char **header_string;
|
|
char **elem_string;
|
|
int header_size;
|
|
int elem_size;
|
|
BufferItem *buffer_first; //pointer to the first item in the buffer
|
|
BufferItem *buffer_last; //pointer to the last item in the buffer
|
|
typedef size_t size_type;
|
|
typedef ptrdiff_t difference_type;
|
|
Theader header;
|
|
Telem elem;
|
|
cache( int Pagesize){
|
|
header_string = new (char *);
|
|
*header_string= new char[header.size()];
|
|
header_size=header.size();
|
|
elem_string = new (char *);
|
|
*elem_string= new char[elem.size()];
|
|
elem_size=elem.size();
|
|
IO_pagesize=Pagesize;
|
|
//initializiation of the buffer as a doubly connected list.
|
|
//the complete space for all list items is allocated.
|
|
|
|
if(IO_pages >0)
|
|
{
|
|
BufferItem * bi1,*bi2;
|
|
int i;
|
|
buffer_first= bi1 = new BufferItem;
|
|
bi1->raw_data=new char[IO_pagesize];
|
|
bi1->prev=0;
|
|
bi1->elem.dirty=false;
|
|
bi1->elem.deleted=true;
|
|
bi1->diskpos=-1;
|
|
for(i=1;i<IO_pages;i++)
|
|
{
|
|
bi2=new BufferItem;
|
|
bi1->next=bi2;
|
|
bi2->raw_data=new char[IO_pagesize];
|
|
bi2->prev=bi1;
|
|
bi1=bi2;
|
|
bi1->elem.dirty=false;
|
|
bi1->elem.deleted=true;
|
|
bi1->diskpos=-1;
|
|
}
|
|
buffer_last=bi1;
|
|
bi1->next=0;
|
|
}
|
|
}
|
|
|
|
//the file is opend and initialized if it is empty. Otherwise
|
|
//the header of the file which contains the necessary information
|
|
//is retrieved.
|
|
cache( int Pagesize, char* name,
|
|
int m = (std::fstream::binary|std::fstream::in | std::fstream::out))
|
|
{
|
|
header_string = new (char *);
|
|
*header_string= new char[header.size()];
|
|
header_size=header.size();
|
|
elem_string = new (char *);
|
|
*elem_string= new char[elem.size()];
|
|
elem_size=elem.size();
|
|
|
|
//fake the SGI CC - compiler: it does not want to open empty
|
|
//files for reading
|
|
std::fstream fake_open;
|
|
fake_open.open(name,
|
|
std::fstream::app|std::fstream::binary|std::fstream::out);
|
|
if(!fake_open.is_open())
|
|
std::cerr << "fake open is not open";
|
|
else
|
|
std::cerr << "header fake open is open";
|
|
fake_open.close();
|
|
|
|
std::cerr << "cache open called with " << name << std::endl;
|
|
IO_pagesize=Pagesize;
|
|
XX.open(name, m);
|
|
if(!XX.is_open())
|
|
{
|
|
std::cerr << name << "did not open -- this should no more happen";
|
|
}
|
|
XX.seekp(0, std::fstream::end);
|
|
int teller;
|
|
teller = XX.tellp();
|
|
if (teller <= 0) {
|
|
header.plast = 0;
|
|
header.pfirst = -1;
|
|
XX.seekp(0);
|
|
header.write(header_string);
|
|
XX.write(*header_string,header_size);
|
|
CGAL_DOGN_Cache(
|
|
if(!XX)
|
|
std::cerr << "\n\n 1 Failed for fstream \n\n";
|
|
else
|
|
std::cerr << "\n\n 1 Did not fail\n\n";
|
|
)
|
|
}
|
|
XX.seekg(0);
|
|
XX.read(*header_string,header_size);
|
|
header.read(header_string);
|
|
//initializiation of the buffer as a doubly connected list.
|
|
//the complete space for all list items is allocated.
|
|
if(IO_pages >0)
|
|
{
|
|
BufferItem * bi1, *bi2;
|
|
int i;
|
|
buffer_first= bi1 = new BufferItem;
|
|
bi1->raw_data=new char[IO_pagesize];
|
|
bi1->prev=0;
|
|
bi1->elem.dirty=false;
|
|
bi1->elem.deleted=true;
|
|
bi1->diskpos=-1;
|
|
for(i=1;i<IO_pages;i++)
|
|
{
|
|
bi2=new BufferItem;
|
|
bi1->next=bi2;
|
|
bi2->raw_data=new char[IO_pagesize];
|
|
bi2->prev=bi1;
|
|
bi1=bi2;
|
|
bi1->elem.dirty=false;
|
|
bi1->elem.deleted=true;
|
|
bi1->diskpos=-1;
|
|
}
|
|
buffer_last=bi1;
|
|
bi1->next=0;
|
|
CGAL_DOGN_Cache(
|
|
test_buffer_items();
|
|
)
|
|
}
|
|
}
|
|
|
|
//the file is cleaned up if it is empty.
|
|
~cache() {
|
|
close();
|
|
}
|
|
|
|
void close()
|
|
{
|
|
if(header.number_of_elements==0)
|
|
{
|
|
header.pfirst=-1;
|
|
header.plast=0;
|
|
XX.seekp(0);
|
|
XX.clear();
|
|
XX.seekp(0);
|
|
header.write(header_string);
|
|
XX.write(*header_string,header_size);
|
|
CGAL_DOGN_Cache(
|
|
if(!XX)
|
|
std::cerr << "\n\n 2 Failed for fstream \n\n";
|
|
else
|
|
std::cerr << "\n\n 2 Did not fail\n\n";
|
|
)
|
|
}
|
|
else
|
|
{
|
|
XX.seekp(0);
|
|
header.write(header_string);
|
|
XX.write(*header_string,header_size);
|
|
CGAL_DOGN_Cache(
|
|
if(!XX)
|
|
std::cerr << "\n\n 3 Failed for fstream \n\n";
|
|
else
|
|
std::cerr << "\n\n 3 Did not fail\n\n";
|
|
)
|
|
CGAL_DOGN_Cache(
|
|
XX.seekg(0);
|
|
XX.read(*header_string,header_size);
|
|
header.read(header_string);
|
|
)
|
|
}
|
|
if(IO_pages>0)
|
|
{
|
|
BufferItem *bi=buffer_first;
|
|
BufferItem *bi2;
|
|
while(bi!=buffer_last)
|
|
{
|
|
if(bi->elem.dirty) //write to disk
|
|
{
|
|
bi->elem.dirty=false;
|
|
XX.seekp((bi->diskpos)*(elem.size() + IO_pagesize)
|
|
+ header.size());
|
|
bi->elem.write(elem_string);
|
|
XX.write(*elem_string,elem_size);
|
|
XX.seekp((bi->diskpos)*(elem.size() + IO_pagesize)
|
|
+ header.size() + elem.size());
|
|
XX.write(bi->raw_data,IO_pagesize);
|
|
CGAL_DOGN_Cache(
|
|
if(!XX)
|
|
std::cerr << "\n\n 4 Failed for fstream \n\n";
|
|
else
|
|
std::cerr << "\n\n 4 Did not fail\n\n";
|
|
)
|
|
|
|
}
|
|
bi2=bi;
|
|
bi=bi->next;
|
|
delete [] bi2->raw_data;
|
|
delete bi2;
|
|
}
|
|
if(bi->elem.dirty) //write to disk
|
|
{
|
|
bi->elem.dirty=false;
|
|
XX.seekp((bi->diskpos)*(elem.size() + IO_pagesize)
|
|
+ header.size());
|
|
bi->elem.write(elem_string);
|
|
XX.write(*elem_string,elem_size);
|
|
XX.seekp((bi->diskpos)*(elem.size() + IO_pagesize)
|
|
+ elem.size() + header.size());
|
|
XX.write(bi->raw_data,IO_pagesize);
|
|
CGAL_DOGN_Cache(
|
|
if(!XX)
|
|
std::cerr << "\n\n 5 Failed for fstream \n\n";
|
|
else
|
|
std::cerr << "\n\n 5 Did not fail\n\n";
|
|
)
|
|
|
|
}
|
|
delete [] bi->raw_data;
|
|
delete bi;
|
|
}
|
|
XX.close();
|
|
}
|
|
|
|
|
|
|
|
|
|
//same as the constructor.
|
|
void open(char* name,
|
|
int m =(std::fstream::binary|std::fstream::in|std::fstream::out)){
|
|
//close the opened file first.
|
|
std::cerr << "cache open called with " << name << std::endl;
|
|
|
|
if(XX.is_open())
|
|
{
|
|
cerr << "Cache file was already open. then it does not work???";
|
|
close();
|
|
}
|
|
//fake the SGI CC - compiler: it does not want to open empty
|
|
//files for reading
|
|
std::fstream fake_open;
|
|
fake_open.open(name,
|
|
std::fstream::app|std::fstream::binary|std::fstream::out);
|
|
CGAL_DOGN_Cache(
|
|
if(!fake_open.is_open())
|
|
std::cerr << "fake open is not open";
|
|
else
|
|
std::cerr << "header fake open is open";
|
|
)
|
|
fake_open.close();
|
|
|
|
XX.open(name, m);
|
|
if(!XX.is_open()){
|
|
std::cerr << name << "can not be opened";
|
|
}
|
|
XX.seekp(0, std::fstream::end);
|
|
int teller;
|
|
teller = XX.tellp();
|
|
if (teller <= 0) {
|
|
header.plast = 0;
|
|
header.pfirst = -1;
|
|
header.number_of_elements = 0;
|
|
XX.seekp(0);
|
|
header.write(header_string);
|
|
XX.write(*header_string,header_size);
|
|
}
|
|
XX.seekg(0);
|
|
XX.read(*header_string,header_size);
|
|
header.read(header_string);
|
|
}
|
|
|
|
void test_buffer_items()
|
|
{
|
|
if(IO_pages >0)
|
|
{
|
|
BufferItem *bi=buffer_first;
|
|
std::cerr << "BUFFERITEMS::::::::::::::::\n";
|
|
while(bi!=0)
|
|
{
|
|
std::cerr << "bi:" << bi->diskpos
|
|
<< " prev :" << bi->prev
|
|
<< "next :" << bi->next << std::endl;
|
|
bi=bi->next;
|
|
}
|
|
std::cerr << "blast:" << buffer_last->diskpos
|
|
<< " prev :" << buffer_last->prev
|
|
<< "next :" << buffer_last->next << std::endl;
|
|
std::cerr << "BUFFERITEMS::::::END::::::::::\n";
|
|
}
|
|
}
|
|
|
|
BufferItem *find_item(difference_type pos)
|
|
{
|
|
BufferItem *bi=buffer_first;
|
|
while(bi->diskpos!=pos && bi!=buffer_last)
|
|
bi=bi->next;
|
|
if(bi==buffer_last && bi->diskpos!=pos)
|
|
return 0;
|
|
else
|
|
return bi;
|
|
}
|
|
|
|
//an new element is inserted. Its position is returned.
|
|
difference_type get_pos() {
|
|
difference_type pos = header.pfirst;
|
|
Telem oldelem;
|
|
header.number_of_elements++;
|
|
if (pos==-1){
|
|
pos = header.plast;
|
|
header.plast++;
|
|
CGAL_DOGN_Cache(
|
|
if(!XX)
|
|
std::cerr << "\n\n 6a Failed for fstream \n\n";
|
|
else
|
|
std::cerr << "\n\n 6a Did not fail\n\n";
|
|
)
|
|
if(IO_pages<=0)
|
|
{
|
|
XX.seekp(0);
|
|
header.write(header_string);
|
|
XX.write(*header_string,header_size);
|
|
CGAL_DOGN_Cache(
|
|
if(!XX)
|
|
std::cerr << "\n\n 6b Failed for fstream \n\n";
|
|
else
|
|
std::cerr << "\n\n 6b Did not fail\n\n";
|
|
)
|
|
}
|
|
}
|
|
else //write element on an old place ->
|
|
//find out what the pnext of that place ist
|
|
{
|
|
if(IO_pages >0)
|
|
{
|
|
BufferItem *bi;
|
|
if((bi=find_item(pos))!=0){
|
|
header.pfirst=bi->elem.pnext;
|
|
}
|
|
else
|
|
{
|
|
XX.seekg( (pos)*(elem.size() + IO_pagesize) + header.size());
|
|
XX.read(*elem_string,elem_size);
|
|
oldelem.read(elem_string);
|
|
header.pfirst=oldelem.pnext;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
XX.seekg( (pos)*(elem.size() + IO_pagesize) + header.size());
|
|
XX.read(*elem_string,elem_size);
|
|
oldelem.read(elem_string);
|
|
header.pfirst=oldelem.pnext;
|
|
}
|
|
XX.seekp(0);
|
|
header.write(header_string);
|
|
XX.write(*header_string,header_size);
|
|
CGAL_DOGN_Cache(
|
|
if(!XX)
|
|
std::cerr << "\n\n 7 Failed for fstream \n\n";
|
|
else
|
|
std::cerr << "\n\n 7 Did not fail\n\n";
|
|
)
|
|
}
|
|
return pos;
|
|
}
|
|
|
|
bool insert(difference_type pos, char** x) {
|
|
if(IO_pages>0)
|
|
{
|
|
// write buffer_last on disk
|
|
if(buffer_last->elem.dirty)
|
|
{
|
|
CGAL_DOGN_Cache(
|
|
std::cerr << "Write the last element of buffer to disk\n";
|
|
std::cerr << "Write elem at pos: "
|
|
<< (buffer_last->diskpos)*(elem.size()
|
|
+ IO_pagesize) + header.size()
|
|
<< std::endl;
|
|
|
|
)
|
|
buffer_last->elem.dirty=false;
|
|
XX.seekp((buffer_last->diskpos)*(elem.size() + IO_pagesize)
|
|
+ header.size());
|
|
buffer_last->elem.write(elem_string);
|
|
XX.write(*elem_string,elem_size);
|
|
XX.seekp((buffer_last->diskpos)*(elem.size() + IO_pagesize)
|
|
+ elem.size() + header.size());
|
|
XX.write(buffer_last->raw_data,IO_pagesize);
|
|
}
|
|
//write element into buffer_last
|
|
buffer_last->elem.dirty=true;
|
|
buffer_last->elem.deleted=false;
|
|
buffer_last->elem.t=elem.t;
|
|
buffer_last->elem.pnext=elem.pnext;
|
|
buffer_last->elem.dirty=true;
|
|
memcpy(buffer_last->raw_data,*x,IO_pagesize);
|
|
|
|
//change pointers such that the element is the first in buffer
|
|
buffer_last->prev->next=0;
|
|
buffer_last->next=buffer_first;
|
|
buffer_first->prev=buffer_last;
|
|
buffer_first=buffer_last;
|
|
buffer_last=buffer_last->prev;
|
|
buffer_first->prev=0;
|
|
buffer_first->diskpos=pos;
|
|
CGAL_DOGN_Cache(
|
|
test_buffer_items();
|
|
)
|
|
}
|
|
else
|
|
{
|
|
elem.deleted = false;
|
|
elem.dirty=false;
|
|
elem.pnext=-1;
|
|
elem.t=time(&elem.t);
|
|
XX.seekp((pos)*(elem.size() + IO_pagesize) + header.size());
|
|
elem.write(elem_string);
|
|
XX.write(*elem_string,elem_size);
|
|
XX.seekp((pos)*(elem.size() + IO_pagesize) + elem.size()
|
|
+ header.size());
|
|
XX.write(*x,IO_pagesize);
|
|
CGAL_DOGN_Cache(
|
|
if(!XX)
|
|
std::cerr << "\n\n 9 Failed for fstream \n\n";
|
|
else
|
|
std::cerr << "\n\n 9 Did not fail\n\n";
|
|
)
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//returns the number of valid elements in the file.
|
|
difference_type number_of_elements(){
|
|
return header.number_of_elements;
|
|
}
|
|
|
|
|
|
// the element associated with position pos is returned.
|
|
// x has to provide IO_pagesize space for writing
|
|
bool get(difference_type pos, char **x)
|
|
{
|
|
if(pos <0 || pos > header.plast)
|
|
return false;
|
|
else{
|
|
if(IO_pages>0)
|
|
{
|
|
BufferItem *bi;
|
|
if((bi=find_item(pos))!=0){ //element in internal memory
|
|
memcpy(*x,bi->raw_data,IO_pagesize);
|
|
if(bi!=buffer_first)
|
|
{
|
|
if(bi!=buffer_last)
|
|
bi->next->prev=bi->prev;
|
|
else
|
|
buffer_last=bi->prev;
|
|
bi->prev->next=bi->next;
|
|
bi->next=buffer_first;
|
|
bi->prev=0;
|
|
bi->next->prev=bi;
|
|
buffer_first=bi;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CGAL_DOGN_Cache(
|
|
std::cerr << "Element in external memory\n";
|
|
)
|
|
//write buffer_last to disk and read the new element in
|
|
if(buffer_last->elem.dirty)
|
|
{
|
|
buffer_last->elem.dirty=false;
|
|
XX.seekp((buffer_last->diskpos)*(elem.size() + IO_pagesize)
|
|
+ header.size());
|
|
CGAL_DOGN_Cache(
|
|
std::cerr << "Write elem at pos: "
|
|
<< (buffer_last->diskpos)*(elem.size()
|
|
+ IO_pagesize) + header.size()
|
|
<< std::endl;
|
|
std::cerr << "Write data at pos: "
|
|
<< (buffer_last->diskpos)*(elem.size()
|
|
+ IO_pagesize) + header.size()
|
|
+ elem.size()
|
|
<< std::endl;
|
|
)
|
|
buffer_last->elem.write(elem_string);
|
|
XX.write(*elem_string,elem_size);
|
|
XX.seekp((buffer_last->diskpos)*(elem.size() + IO_pagesize)
|
|
+ header.size() + elem.size());
|
|
XX.write(buffer_last->raw_data,IO_pagesize);
|
|
}
|
|
XX.seekg((pos)*(elem.size() + IO_pagesize) + header.size());
|
|
XX.read(*elem_string,elem_size);
|
|
buffer_last->elem.read(elem_string);
|
|
|
|
if(buffer_last->elem.deleted)
|
|
return false;
|
|
XX.seekg((pos)*(elem.size() + IO_pagesize)
|
|
+ header.size()+ elem.size());
|
|
XX.read(*x,IO_pagesize);
|
|
memcpy(buffer_last->raw_data,*x,IO_pagesize);
|
|
buffer_last->diskpos=pos;
|
|
buffer_last->prev->next=0;
|
|
buffer_last->next=buffer_first;
|
|
buffer_first->prev=buffer_last;
|
|
buffer_first=buffer_last;
|
|
buffer_last=buffer_last->prev;
|
|
buffer_first->prev=0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
XX.seekg((pos)*(elem.size() + IO_pagesize) + header.size());
|
|
CGAL_DOGN_Data(
|
|
std::cerr << "*********Get elem at pos: "
|
|
<< (pos)*(elem.size() + IO_pagesize)
|
|
+ header.size()
|
|
<< std::endl;
|
|
std::cerr << "******Get data at pos: "
|
|
<< (pos)*(elem.size() + IO_pagesize)
|
|
+ header.size()+ elem.size()
|
|
<< std::endl;
|
|
)
|
|
XX.read(*elem_string,elem_size);
|
|
elem.read(elem_string);
|
|
if(elem.deleted)
|
|
return false;
|
|
XX.seekg((pos)*(elem.size()+IO_pagesize)+header.size()+elem.size());
|
|
XX.read(*x,IO_pagesize);
|
|
}
|
|
CGAL_DOGN_Cache(
|
|
test_buffer_items();
|
|
)
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// the element at position pos is updated with x.
|
|
bool update(difference_type pos, char **x){
|
|
bool ret = true;
|
|
if(pos <0 || pos > header.plast)
|
|
return false;
|
|
else{
|
|
if(IO_pages>0)
|
|
{
|
|
BufferItem *bi;
|
|
if((bi=find_item(pos))!=0){
|
|
memcpy(bi->raw_data,*x,IO_pagesize);
|
|
bi->elem.dirty=true;
|
|
bi->elem.deleted=false;
|
|
if(bi!=buffer_first) //internal update
|
|
{
|
|
if(bi!=buffer_last)
|
|
bi->next->prev=bi->prev;
|
|
else
|
|
buffer_last=bi->prev;
|
|
bi->prev->next=bi->next;
|
|
bi->next=buffer_first;
|
|
bi->prev=0;
|
|
bi->next->prev=bi;
|
|
buffer_first=bi;
|
|
}
|
|
}
|
|
else //external update
|
|
{
|
|
// write buffer_last to disk, read the new element in
|
|
// and update it
|
|
if(buffer_last->elem.dirty)
|
|
{
|
|
buffer_last->elem.dirty=false;
|
|
XX.seekp((buffer_last->diskpos)*(elem.size() + IO_pagesize)
|
|
+ header.size());
|
|
buffer_last->elem.write(elem_string);
|
|
XX.write(*elem_string,elem_size);
|
|
XX.seekp((buffer_last->diskpos)*(elem.size() + IO_pagesize)
|
|
+ header.size()+ elem.size());
|
|
XX.write(buffer_last->raw_data,IO_pagesize);
|
|
}
|
|
XX.seekg((pos)*(elem.size() + IO_pagesize) + header.size());
|
|
XX.read(*elem_string,elem_size);
|
|
buffer_last->elem.read(elem_string);
|
|
if(buffer_last->elem.deleted)
|
|
{
|
|
CGAL_DOGN_Cache(
|
|
std::cerr << "Warning: element was declared deleted"
|
|
<< std::endl;
|
|
)
|
|
ret = false;
|
|
}
|
|
memcpy(buffer_last->raw_data,*x,IO_pagesize);
|
|
buffer_last->elem.dirty=true;
|
|
buffer_last->diskpos=pos;
|
|
buffer_last->prev->next=0;
|
|
buffer_last->next=buffer_first;
|
|
buffer_first->prev=buffer_last;
|
|
buffer_first=buffer_last;
|
|
buffer_last=buffer_last->prev;
|
|
buffer_first->prev=0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
XX.seekg((pos)*(elem.size() + IO_pagesize) + header.size());
|
|
XX.read(*elem_string,elem_size);
|
|
elem.read(elem_string);
|
|
|
|
if(elem.deleted)
|
|
{
|
|
CGAL_DOGN_Cache(
|
|
std::cerr << "Warning: element was declared deleted"
|
|
<< std::endl;
|
|
)
|
|
ret = false;
|
|
}
|
|
XX.seekp((pos)*(elem.size() + IO_pagesize) + header.size());
|
|
CGAL_DOGN_Cache(
|
|
std::cerr << "******Write elem at pos: "
|
|
<< (pos)*(elem.size() + IO_pagesize)
|
|
+ header.size()
|
|
<< std::endl;
|
|
std::cerr << "******Write data at pos: "
|
|
<< (pos)*(elem.size() + IO_pagesize)
|
|
+ header.size()+ elem.size()
|
|
<< std::endl;
|
|
)
|
|
elem.write(elem_string);
|
|
XX.write(*elem_string,elem_size);
|
|
XX.seekp((pos)*(elem.size() + IO_pagesize) + header.size()
|
|
+ elem.size());
|
|
XX.write(*x,IO_pagesize);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
//the element at position pos is declared deleted. Its free place
|
|
//is stored in the header.
|
|
bool erase(difference_type pos)
|
|
{
|
|
if(pos <0 || pos > header.plast)
|
|
return false;
|
|
else{
|
|
if(IO_pages >0)
|
|
{
|
|
BufferItem *bi;
|
|
if((bi=find_item(pos))!=0) //element is in internal memory
|
|
{
|
|
if(!bi->elem.deleted)
|
|
header.number_of_elements--;
|
|
bi->elem.deleted=true;
|
|
bi->elem.dirty=true;
|
|
bi->elem.pnext=header.pfirst;
|
|
header.pfirst=pos;
|
|
XX.seekp(0);
|
|
header.write(header_string);
|
|
XX.write(*header_string,header_size);
|
|
|
|
// position bi on last position
|
|
if(bi!=buffer_last){
|
|
if(bi!=buffer_first)
|
|
bi->prev->next=bi->next;
|
|
else
|
|
buffer_first=bi->next;
|
|
bi->next->prev=bi->prev;
|
|
bi->prev=buffer_last;
|
|
bi->next=0;
|
|
buffer_last->next=bi;
|
|
buffer_last=bi;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CGAL_DOGN_Cache(
|
|
std::cerr << "Element in external memory\n";
|
|
)
|
|
XX.seekg((pos)*(elem.size() + IO_pagesize) + header.size());
|
|
XX.read(*elem_string,elem_size);
|
|
elem.read(elem_string);
|
|
|
|
if(elem.deleted)
|
|
return false;
|
|
|
|
elem.deleted = true;
|
|
elem.pnext=header.pfirst;
|
|
header.pfirst=pos;
|
|
header.number_of_elements--;
|
|
XX.seekp((pos)*(elem.size() + IO_pagesize) + header.size());
|
|
elem.write(elem_string);
|
|
XX.write(*elem_string,elem_size);
|
|
XX.seekp(0);
|
|
header.write(header_string);
|
|
XX.write(*header_string,header_size);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
XX.seekg((pos)*(elem.size() + IO_pagesize) + header.size());
|
|
XX.read(*elem_string,elem_size);
|
|
elem.read(elem_string);
|
|
|
|
if(elem.deleted)
|
|
return false;
|
|
elem.deleted = true;
|
|
elem.pnext=header.pfirst;
|
|
header.pfirst=pos;
|
|
header.number_of_elements--;
|
|
XX.seekp((pos)*(elem.size() + IO_pagesize) + header.size());
|
|
elem.write(elem_string);
|
|
XX.write(*elem_string,elem_size);
|
|
XX.seekp(0);
|
|
header.write(header_string);
|
|
XX.write(*header_string,header_size);
|
|
}
|
|
}
|
|
CGAL_DOGN_Cache(
|
|
test_buffer_items();
|
|
)
|
|
return true;
|
|
}
|
|
|
|
//returns true if the element at position pos is deleted.
|
|
bool deleted(difference_type pos)
|
|
{
|
|
if(pos <0 || pos > header.plast)
|
|
return true;
|
|
else{
|
|
if(IO_pages>0)
|
|
{
|
|
BufferItem *bi;
|
|
if((bi=find_item(pos))!=0) //element is in internal memory
|
|
if(bi->elem.deleted)
|
|
return true;
|
|
else
|
|
return false;
|
|
else{
|
|
//write buffer_last to disk, read the new element in and update it
|
|
if(buffer_last->elem.dirty)
|
|
{
|
|
buffer_last->elem.dirty=false;
|
|
XX.seekp((buffer_last->diskpos)*(elem.size() + IO_pagesize)
|
|
+ header.size());
|
|
buffer_last->elem.write(elem_string);
|
|
XX.write(*elem_string,elem_size);
|
|
XX.seekp((buffer_last->diskpos)*(elem.size() + IO_pagesize)
|
|
+ header.size()+ elem.size());
|
|
XX.write(buffer_last->raw_data,IO_pagesize);
|
|
}
|
|
XX.seekg((pos)*(elem.size() + IO_pagesize) + header.size());
|
|
XX.read(*elem_string,elem_size);
|
|
buffer_last->elem.read(elem_string);
|
|
if(buffer_last->elem.deleted)
|
|
{
|
|
CGAL_DOGN_Cache(
|
|
std::cerr << "Warning: element was declared deleted"
|
|
<< std::endl;
|
|
)
|
|
ret = false;
|
|
}
|
|
buffer_last->diskpos=pos;
|
|
buffer_last->prev->next=0;
|
|
buffer_last->next=buffer_first;
|
|
buffer_first->prev=buffer_last;
|
|
buffer_first=buffer_last;
|
|
buffer_last=buffer_last->prev;
|
|
buffer_first->prev=0;
|
|
if(buffer_last->elem.deleted)
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
XX.seekg((pos)*(elem.size() + IO_pagesize) + header.size());
|
|
XX.read(*elem_string,elem_size);
|
|
elem.read(elem_string);
|
|
if(elem.deleted)
|
|
return true;
|
|
}
|
|
}
|
|
CGAL_DOGN_Cache(
|
|
test_buffer_items();
|
|
)
|
|
return false;
|
|
}
|
|
};
|
|
|
|
CGAL_END_NAMESPACE
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|