BUFFER.CPP
上传用户:zengbais
上传日期:2022-08-08
资源大小:49k
文件大小:8k
开发平台:

C++ Builder

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <fstream.h>
  4. // 功能:实现buffer.h中的各个缓冲类的函数
  5. #include "buffer.h"
  6. #include "cbuffer.h"
  7. DOUBLE defaulterr = 1e-8;  // 缺省的误差调整值
  8. int doadjust = 1; // 决定数据是否根据误差值自动向整数靠扰,
  9. // 其实是向小数点后三位靠扰
  10. /* 下面的六个指针分别初始化指向产生六个缓冲区长度为空的六个
  11. 缓冲区,其中两个实数缓冲区,两个长整数缓冲区,两个复数缓冲区
  12.   其中实数,长整数和复数这三种数据类型的每一种都有磁盘和内存两种
  13.   缓冲区。如果数据较小时可以存放在内存中,而数据量很大时则存放在
  14.   临时文件构成的磁盘缓冲区中。这六个空缓冲区并不真正用来存放数据,
  15.   而是用来产生出新的与自己一样的缓冲区,因为它们都是抽象类buffer的
  16.   子类,所以都将被settomemory函数或者settodisk函数赋给三个buffer类的
  17.   指针,使得getnewbuffer,getnewcbuffer和getnewlbuffer三个函数能够从这些
  18.   缓冲区中用抽象类函数产生同样类型的缓冲区。
  19.   总的想法是,在以后编写的计算各种矩阵或者行列式,或者其它的大量
  20.   数据的运算时,只要调用一次settomemroy或者settodisk函数,那么用户
  21.   不必改写一行代码,就可以照算不误,而存储媒体已经改变。
  22. */
  23. static membuffer *memorybuffer = new membuffer; // 实数内存缓冲区指针
  24. static diskbuffer *diskfilebuffer = new diskbuffer; // 实数磁盘缓冲区指针
  25. static lmembuffer *memorylbuffer = new lmembuffer; // 长整数内存缓冲区指针
  26. static ldiskbuffer *diskfilelbuffer = new ldiskbuffer; // 长整数磁盘缓冲区指针
  27. static memcbuffer *memorycbuffer = new memcbuffer; // 复数内存缓冲区指针
  28. static diskcbuffer *diskfilecbuffer = new diskcbuffer; // 复数磁盘缓冲区指针
  29. /* 以下三个缺省缓冲区指针为全局变量,用户可以定义自己的缓冲区
  30. 类,并在产生静态实例变量后将其指针赋予它们 */
  31. buffer *defbuffer = memorybuffer; // 缺省实数缓冲区指针
  32. lbuffer *deflbuffer = memorylbuffer; // 缺省长整数缓冲区指针
  33. cbuffer *defcbuffer = memorycbuffer; // 缺省复数缓冲区指针
  34. /* 产生一个新的容量为n个实数的实数缓冲区,返回此缓冲区指针,
  35. 缓冲区的类型与defbuffer指向的变量的子类类型相同 */
  36. buffer * getnewbuffer(size_t n){
  37. return defbuffer->newbuf(n);
  38. }
  39. /* 产生一个新的容量为n个长整数的长整数缓冲区,返回此缓冲区指针,
  40. 缓冲区的类型与deflbuffer指向的变量的子类类型相同 */
  41. lbuffer * getnewlbuffer(size_t n){
  42. return deflbuffer->newbuf(n);
  43. }
  44. /* 产生一个新的容量为n个复数的复数缓冲区,返回此缓冲区指针,
  45. 缓冲区的类型与defcbuffer指向的变量的子类类型相同 */
  46. cbuffer * getnewcbuffer(size_t n){
  47. return defcbuffer->newbuf(n);
  48. }
  49. // 将各实数,长整数和复数的缺省的缓冲区指针指向相应的磁盘缓冲区指针
  50. void settodisk()
  51. {
  52. defbuffer = diskfilebuffer;
  53. deflbuffer = diskfilelbuffer;
  54. defcbuffer = diskfilecbuffer;
  55. }
  56. // 将各实数,长整数和复数的缺省的缓冲区指针指向相应的内存缓冲区指针
  57. void settomemory()
  58. {
  59. defbuffer = memorybuffer;
  60. deflbuffer = memorylbuffer;
  61. defcbuffer = memorycbuffer;
  62. }
  63. ostream& operator<<(ostream& o, buffer& b)
  64. {
  65. size_t maxitem = 5;
  66. for(size_t i=0; i<b.len(); i++) {
  67. o << b[i] << 't';
  68. if(((i+1) % maxitem)==0)
  69. o << endl;
  70. }
  71. o << endl;
  72. return o;
  73. }
  74. // 将实数缓冲区的第n个实数的值设为d,并返回一个实数缓冲区的
  75. // 指针,此指针一般就是指向自己,而在一个缓冲区的引用数多于一个时
  76. // 此函数将先克隆出一个新的缓冲区,此新的缓冲区的引用数为1,并对此
  77. // 新的缓冲区的第n个实数的值设为d,然后返加新缓冲区的指针
  78. buffer* buffer::set(size_t n, DOUBLE d)
  79. {
  80. // 如调整标志设置,则调整
  81. if(doadjust) adjust(d);
  82. if(refnum == 1) { // 如果引用数为1,则将第n个实数的值设为d,并返回自己
  83. // 的指针
  84. retrieve(n) = d;
  85. return this;
  86. }
  87. refnum --; // 引用数大于1,因此将本缓冲区的引用数减1
  88. buffer * b;
  89. b = clone(); // 克隆一个内容同自己一样的新缓冲区
  90. (b->retrieve(n)) = d; // 将新缓冲区的第n个实数的值设为d
  91. return b; // 返回新缓冲区的指针
  92. }
  93. buffer* membuffer::clone() // 克隆一个内容和自己一样的实数内存缓冲区,并返回其指针
  94. {
  95. buffer* b;
  96. b = new membuffer(length); // 建立一个新的实数内存缓冲区,尺寸和自己的一样
  97. if(length > 0) // 如果自己有内容,将全部拷贝到新产生的缓冲区中
  98. for(size_t i=0; i<length; i++)
  99. (b->retrieve(i)) = (*this)[i];
  100. return b;
  101. }
  102. // 实数磁盘缓冲区构造函数
  103. diskbuffer::diskbuffer(size_t lth):buffer(),length(lth),n(0)
  104. {
  105. tempfp = tmpfile(); // 打开一新的临时文件,指针赋给tempfp
  106. }
  107. // 实数磁盘缓冲区的析构函数
  108. diskbuffer::~diskbuffer()
  109. {
  110. fclose(tempfp); // 关闭临时文件
  111. }
  112. void diskbuffer::alloc(size_t num) // 将磁盘缓冲区重新定为尺寸为num
  113. {
  114. length = num;
  115. if(!tempfp)  // 如果临时文件尚未打开,则打开临时文件
  116. tempfp = tmpfile();
  117. n = 0; // 当前缓冲区指针设在开始,就是0处
  118. }
  119. void diskbuffer::release() // 释放磁盘缓冲区
  120. {
  121. fclose(tempfp); // 关闭临时文件
  122. buf = 0.0;
  123. length = 0;
  124. }
  125. DOUBLE& diskbuffer::retrieve(size_t i) // 返回实数磁盘缓冲区的第i个实数
  126. {
  127. long off;
  128. off = n*sizeof(DOUBLE); // 计算出当前指针n对应的文件的偏移量
  129. fseek(tempfp, off, SEEK_SET); // 移动文件指针到给定的偏移量处
  130. fwrite(&buf, sizeof(DOUBLE), 1, tempfp); // 将当前的buf中值写到文件中
  131. off = i*sizeof(DOUBLE); // 计算第i个实数在文件的什么位置
  132. fseek(tempfp, off, SEEK_SET); // 移动文件指针到给定的偏移量处
  133. fread(&buf, sizeof(DOUBLE), 1, tempfp); // 读回所需的实数值到buf中
  134. n = i; // 并将n改为i
  135. return buf; // 返回读出的实数的引用
  136. }
  137. buffer* diskbuffer::clone() // 克隆一个新的内容与自己一样的实数磁盘缓冲区
  138. {
  139. buffer* b;
  140. b = new diskbuffer(length); // 定位产生一个与自己长度一样的新缓冲区
  141. if(length > 0) // 如果长度大于0,则自己的内容拷贝到新缓冲区
  142. for(size_t i=0; i<length; i++)
  143. (b->retrieve(i)) = (*this)[i];
  144. return b; // 返回新缓冲区的指针
  145. }
  146. // 将第n个长整数的值设为v,如果缓冲区的引用数大于1,
  147. // 则会先克隆出新的缓冲区,然后再进行操作,并返回新缓冲区的指针
  148. lbuffer* lbuffer::set(size_t n, long v)
  149. {
  150. if(refnum == 1) { //  引用数为1
  151. retrieve(n) = v; // 将第n个长整数的值设为v
  152. return this; // 返回自己
  153. }
  154. refnum --; // 引用数大于1,引用数减1
  155. lbuffer * b;
  156. b = clone(); // 克隆出新的内容一样的长整数缓冲区
  157. (b->retrieve(n)) = v; // 将新缓冲区的第n个长整数值设为v
  158. return b; // 返回新缓冲区的指针
  159. }
  160. ostream& operator<<(ostream& o, lbuffer& b)
  161. {
  162. size_t maxitem = 5;
  163. for(size_t i=0; i<b.len(); i++) {
  164. o << b[i] << 't';
  165. if(((i+1) % maxitem)==0)
  166. o << endl;
  167. }
  168. o << endl;
  169. return o;
  170. }
  171. lbuffer* lmembuffer::clone() // 克隆一个内容一新的长整数内存缓存区
  172. {
  173. lbuffer* b;
  174. b = new lmembuffer(length); // 产生长度与自己一样的长整数缓存区
  175. if(length > 0) // 如果长度大于0,则将自己的内容拷贝过去
  176. for(size_t i=0; i<length; i++)
  177. (b->retrieve(i)) = (*this)[i];
  178. return b; // 返回新缓存区的指针
  179. }
  180. // 长整数磁盘缓存区的构造函数
  181. ldiskbuffer::ldiskbuffer(size_t lth):lbuffer(),length(lth),n(0)
  182. {
  183. tempfp = tmpfile(); // 打开临时文件
  184. }
  185. // 长整数磁盘缓存区的析构函灵敏
  186. ldiskbuffer::~ldiskbuffer()
  187. {
  188. fclose(tempfp); // 关闭临时文件
  189. }
  190. // 将长度定改为num
  191. void ldiskbuffer::alloc(size_t num)
  192. {
  193. length = num;
  194. if(!tempfp) // 如临时文件尚未打开,则打开
  195. tempfp = tmpfile();
  196. n = 0;
  197. }
  198. // 长整数磁盘缓存区释放
  199. void ldiskbuffer::release()
  200. {
  201. fclose(tempfp); // 关闭临时文件
  202. buf = 0;
  203. length = 0;
  204. }
  205. // 检索第i个值的引用
  206. long& ldiskbuffer::retrieve(size_t i)
  207. {
  208. long off;
  209. off = n*sizeof(long); // 先将当前的内容保存
  210. fseek(tempfp, off, SEEK_SET);
  211. fwrite(&buf, sizeof(long), 1, tempfp);
  212. off = i*sizeof(long); // 再取出第i个长整数到buf中
  213. fseek(tempfp, off, SEEK_SET);
  214. fread(&buf, sizeof(long), 1, tempfp);
  215. n = i;
  216. return buf;
  217. }
  218. // 克隆一个和内容和自己一样的长整数磁盘缓存区
  219. lbuffer* ldiskbuffer::clone()
  220. {
  221. lbuffer* b;
  222. b = new ldiskbuffer(length); // 产生长度和自己一样的缓存区
  223. if(length > 0) // 如果自己内容不为空,拷贝内容到新的缓存区
  224. for(size_t i=0; i<length; i++)
  225. (b->retrieve(i)) = (*this)[i];
  226. return b;
  227. }
  228. DOUBLE adjust(DOUBLE & a) // 将实数调整为最靠近小数点后二位的实数
  229. // 准则:如果一个实数距某个二位小数小于十的负八次幂,则调整为这个小数
  230. // 否则不变
  231. {
  232. DOUBLE b = floor(a*100.0+0.5)/100.0; // b是四舍五入到小数点后二位
  233. if(fabs(b-a)<defaulterr) // 如果舍入误差极小,则抛弃
  234. a = b;
  235. return a;
  236. }
  237. char * throwmessage(int l, char * f, char * c)
  238. {
  239. static char a[100];
  240. sprintf(a,"file:%s,line:%dnmessage:%sn",f,l,c);
  241. return a;
  242. }