?? buffer.cpp
字號:
#include <stdio.h>
#include <string.h>
#include <fstream.h>
// 功能:實現buffer.h中的各個緩沖類的函數
#include "buffer.h"
#include "cbuffer.h"
DOUBLE defaulterr = 1e-8; // 缺省的誤差調整值
int doadjust = 1; // 決定數據是否根據誤差值自動向整數靠擾,
// 其實是向小數點后三位靠擾
/* 下面的六個指針分別初始化指向產生六個緩沖區長度為空的六個
緩沖區,其中兩個實數緩沖區,兩個長整數緩沖區,兩個復數緩沖區
其中實數,長整數和復數這三種數據類型的每一種都有磁盤和內存兩種
緩沖區。如果數據較小時可以存放在內存中,而數據量很大時則存放在
臨時文件構成的磁盤緩沖區中。這六個空緩沖區并不真正用來存放數據,
而是用來產生出新的與自己一樣的緩沖區,因為它們都是抽象類buffer的
子類,所以都將被settomemory函數或者settodisk函數賦給三個buffer類的
指針,使得getnewbuffer,getnewcbuffer和getnewlbuffer三個函數能夠從這些
緩沖區中用抽象類函數產生同樣類型的緩沖區。
總的想法是,在以后編寫的計算各種矩陣或者行列式,或者其它的大量
數據的運算時,只要調用一次settomemroy或者settodisk函數,那么用戶
不必改寫一行代碼,就可以照算不誤,而存儲媒體已經改變。
*/
static membuffer *memorybuffer = new membuffer; // 實數內存緩沖區指針
static diskbuffer *diskfilebuffer = new diskbuffer; // 實數磁盤緩沖區指針
static lmembuffer *memorylbuffer = new lmembuffer; // 長整數內存緩沖區指針
static ldiskbuffer *diskfilelbuffer = new ldiskbuffer; // 長整數磁盤緩沖區指針
static memcbuffer *memorycbuffer = new memcbuffer; // 復數內存緩沖區指針
static diskcbuffer *diskfilecbuffer = new diskcbuffer; // 復數磁盤緩沖區指針
/* 以下三個缺省緩沖區指針為全局變量,用戶可以定義自己的緩沖區
類,并在產生靜態實例變量后將其指針賦予它們 */
buffer *defbuffer = memorybuffer; // 缺省實數緩沖區指針
lbuffer *deflbuffer = memorylbuffer; // 缺省長整數緩沖區指針
cbuffer *defcbuffer = memorycbuffer; // 缺省復數緩沖區指針
/* 產生一個新的容量為n個實數的實數緩沖區,返回此緩沖區指針,
緩沖區的類型與defbuffer指向的變量的子類類型相同 */
buffer * getnewbuffer(size_t n){
return defbuffer->newbuf(n);
}
/* 產生一個新的容量為n個長整數的長整數緩沖區,返回此緩沖區指針,
緩沖區的類型與deflbuffer指向的變量的子類類型相同 */
lbuffer * getnewlbuffer(size_t n){
return deflbuffer->newbuf(n);
}
/* 產生一個新的容量為n個復數的復數緩沖區,返回此緩沖區指針,
緩沖區的類型與defcbuffer指向的變量的子類類型相同 */
cbuffer * getnewcbuffer(size_t n){
return defcbuffer->newbuf(n);
}
// 將各實數,長整數和復數的缺省的緩沖區指針指向相應的磁盤緩沖區指針
void settodisk()
{
defbuffer = diskfilebuffer;
deflbuffer = diskfilelbuffer;
defcbuffer = diskfilecbuffer;
}
// 將各實數,長整數和復數的缺省的緩沖區指針指向相應的內存緩沖區指針
void settomemory()
{
defbuffer = memorybuffer;
deflbuffer = memorylbuffer;
defcbuffer = memorycbuffer;
}
ostream& operator<<(ostream& o, buffer& b)
{
size_t maxitem = 5;
for(size_t i=0; i<b.len(); i++) {
o << b[i] << '\t';
if(((i+1) % maxitem)==0)
o << endl;
}
o << endl;
return o;
}
// 將實數緩沖區的第n個實數的值設為d,并返回一個實數緩沖區的
// 指針,此指針一般就是指向自己,而在一個緩沖區的引用數多于一個時
// 此函數將先克隆出一個新的緩沖區,此新的緩沖區的引用數為1,并對此
// 新的緩沖區的第n個實數的值設為d,然后返加新緩沖區的指針
buffer* buffer::set(size_t n, DOUBLE d)
{
// 如調整標志設置,則調整
if(doadjust) adjust(d);
if(refnum == 1) { // 如果引用數為1,則將第n個實數的值設為d,并返回自己
// 的指針
retrieve(n) = d;
return this;
}
refnum --; // 引用數大于1,因此將本緩沖區的引用數減1
buffer * b;
b = clone(); // 克隆一個內容同自己一樣的新緩沖區
(b->retrieve(n)) = d; // 將新緩沖區的第n個實數的值設為d
return b; // 返回新緩沖區的指針
}
buffer* membuffer::clone() // 克隆一個內容和自己一樣的實數內存緩沖區,并返回其指針
{
buffer* b;
b = new membuffer(length); // 建立一個新的實數內存緩沖區,尺寸和自己的一樣
if(length > 0) // 如果自己有內容,將全部拷貝到新產生的緩沖區中
for(size_t i=0; i<length; i++)
(b->retrieve(i)) = (*this)[i];
return b;
}
// 實數磁盤緩沖區構造函數
diskbuffer::diskbuffer(size_t lth):buffer(),length(lth),n(0)
{
tempfp = tmpfile(); // 打開一新的臨時文件,指針賦給tempfp
}
// 實數磁盤緩沖區的析構函數
diskbuffer::~diskbuffer()
{
fclose(tempfp); // 關閉臨時文件
}
void diskbuffer::alloc(size_t num) // 將磁盤緩沖區重新定為尺寸為num
{
length = num;
if(!tempfp) // 如果臨時文件尚未打開,則打開臨時文件
tempfp = tmpfile();
n = 0; // 當前緩沖區指針設在開始,就是0處
}
void diskbuffer::release() // 釋放磁盤緩沖區
{
fclose(tempfp); // 關閉臨時文件
buf = 0.0;
length = 0;
}
DOUBLE& diskbuffer::retrieve(size_t i) // 返回實數磁盤緩沖區的第i個實數
{
long off;
off = n*sizeof(DOUBLE); // 計算出當前指針n對應的文件的偏移量
fseek(tempfp, off, SEEK_SET); // 移動文件指針到給定的偏移量處
fwrite(&buf, sizeof(DOUBLE), 1, tempfp); // 將當前的buf中值寫到文件中
off = i*sizeof(DOUBLE); // 計算第i個實數在文件的什么位置
fseek(tempfp, off, SEEK_SET); // 移動文件指針到給定的偏移量處
fread(&buf, sizeof(DOUBLE), 1, tempfp); // 讀回所需的實數值到buf中
n = i; // 并將n改為i
return buf; // 返回讀出的實數的引用
}
buffer* diskbuffer::clone() // 克隆一個新的內容與自己一樣的實數磁盤緩沖區
{
buffer* b;
b = new diskbuffer(length); // 定位產生一個與自己長度一樣的新緩沖區
if(length > 0) // 如果長度大于0,則自己的內容拷貝到新緩沖區
for(size_t i=0; i<length; i++)
(b->retrieve(i)) = (*this)[i];
return b; // 返回新緩沖區的指針
}
// 將第n個長整數的值設為v,如果緩沖區的引用數大于1,
// 則會先克隆出新的緩沖區,然后再進行操作,并返回新緩沖區的指針
lbuffer* lbuffer::set(size_t n, long v)
{
if(refnum == 1) { // 引用數為1
retrieve(n) = v; // 將第n個長整數的值設為v
return this; // 返回自己
}
refnum --; // 引用數大于1,引用數減1
lbuffer * b;
b = clone(); // 克隆出新的內容一樣的長整數緩沖區
(b->retrieve(n)) = v; // 將新緩沖區的第n個長整數值設為v
return b; // 返回新緩沖區的指針
}
ostream& operator<<(ostream& o, lbuffer& b)
{
size_t maxitem = 5;
for(size_t i=0; i<b.len(); i++) {
o << b[i] << '\t';
if(((i+1) % maxitem)==0)
o << endl;
}
o << endl;
return o;
}
lbuffer* lmembuffer::clone() // 克隆一個內容一新的長整數內存緩存區
{
lbuffer* b;
b = new lmembuffer(length); // 產生長度與自己一樣的長整數緩存區
if(length > 0) // 如果長度大于0,則將自己的內容拷貝過去
for(size_t i=0; i<length; i++)
(b->retrieve(i)) = (*this)[i];
return b; // 返回新緩存區的指針
}
// 長整數磁盤緩存區的構造函數
ldiskbuffer::ldiskbuffer(size_t lth):lbuffer(),length(lth),n(0)
{
tempfp = tmpfile(); // 打開臨時文件
}
// 長整數磁盤緩存區的析構函靈敏
ldiskbuffer::~ldiskbuffer()
{
fclose(tempfp); // 關閉臨時文件
}
// 將長度定改為num
void ldiskbuffer::alloc(size_t num)
{
length = num;
if(!tempfp) // 如臨時文件尚未打開,則打開
tempfp = tmpfile();
n = 0;
}
// 長整數磁盤緩存區釋放
void ldiskbuffer::release()
{
fclose(tempfp); // 關閉臨時文件
buf = 0;
length = 0;
}
// 檢索第i個值的引用
long& ldiskbuffer::retrieve(size_t i)
{
long off;
off = n*sizeof(long); // 先將當前的內容保存
fseek(tempfp, off, SEEK_SET);
fwrite(&buf, sizeof(long), 1, tempfp);
off = i*sizeof(long); // 再取出第i個長整數到buf中
fseek(tempfp, off, SEEK_SET);
fread(&buf, sizeof(long), 1, tempfp);
n = i;
return buf;
}
// 克隆一個和內容和自己一樣的長整數磁盤緩存區
lbuffer* ldiskbuffer::clone()
{
lbuffer* b;
b = new ldiskbuffer(length); // 產生長度和自己一樣的緩存區
if(length > 0) // 如果自己內容不為空,拷貝內容到新的緩存區
for(size_t i=0; i<length; i++)
(b->retrieve(i)) = (*this)[i];
return b;
}
DOUBLE adjust(DOUBLE & a) // 將實數調整為最靠近小數點后二位的實數
// 準則:如果一個實數距某個二位小數小于十的負八次冪,則調整為這個小數
// 否則不變
{
DOUBLE b = floor(a*100.0+0.5)/100.0; // b是四舍五入到小數點后二位
if(fabs(b-a)<defaulterr) // 如果舍入誤差極小,則拋棄
a = b;
return a;
}
char * throwmessage(int l, char * f, char * c)
{
static char a[100];
sprintf(a,"file:%s,line:%d\nmessage:%s\n",f,l,c);
return a;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -