IntervalArray.h
上传用户:liguizhu
上传日期:2015-11-01
资源大小:2422k
文件大小:12k
源码类别:

P2P编程

开发平台:

Visual C++

  1. /*
  2.  *  Openmysee
  3.  *
  4.  *  This program is free software; you can redistribute it and/or modify
  5.  *  it under the terms of the GNU General Public License as published by
  6.  *  the Free Software Foundation; either version 2 of the License, or
  7.  *  (at your option) any later version.
  8.  *
  9.  *  This program is distributed in the hope that it will be useful,
  10.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  *  GNU General Public License for more details.
  13.  *
  14.  *  You should have received a copy of the GNU General Public License
  15.  *  along with this program; if not, write to the Free Software
  16.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  17.  *
  18.  */
  19. #pragma once
  20. // 用于表示一个块的区间,start是起始块的ID,size是此区间的大小
  21. // 是一个前闭后开的区间, [start, start+size)
  22. // 实际使用中不会出现size=0的情况,因为只需要表示大小不为零的区间
  23. class BlockInterval {
  24. public:
  25. // 初始化start为非法值
  26. BlockInterval() : start(0xffffffff) {};
  27. BlockInterval(UINT s, UINT ss) : start(s), size(ss) {};
  28. static bool cmp_size(const BlockInterval& i1, const BlockInterval& i2) {
  29. return (i1.size < i2.size);
  30. };
  31. static bool cmp_start(const BlockInterval& i1, const BlockInterval& i2) {
  32. return (i1.start < i2.start);
  33. };
  34. bool operator == (const BlockInterval& a) const {
  35. return (start == a.start && size == a.size);
  36. };
  37. BlockInterval& operator=(const BlockInterval& another) {
  38. start = another.start;
  39. size = another.size;
  40.         return *this;
  41.     }
  42. // 两个区间的 & 操作,结果保存在result中
  43. static void and_op(const BlockInterval& i1, const BlockInterval& i2, BlockInterval& result) {
  44. result.start = max(i1.start, i2.start); // &区间的start
  45. result.size = min(i1.start+i1.size, i2.start+i2.size); // &区间的end,临时使用result.size保存这个值
  46. if(result.size > result.start) // 这两行把result.size当作&区间的end使用
  47. result.size = result.size-result.start;
  48. else
  49. result.size = 0;
  50. };
  51. public:
  52. UINT start; // 起始位置
  53. UINT size; // 区间大小
  54. };
  55. class IntervalArray {
  56. public:
  57. // 构造函数,指定初始化大小
  58. explicit IntervalArray() : m_array(NULL), m_totalsize(0), m_validsize(0) {
  59. };
  60. // 拷贝构造函数
  61. explicit IntervalArray(const IntervalArray& another) : m_array(NULL), m_totalsize(another.m_totalsize), m_validsize(another.m_validsize) {
  62. if(m_totalsize) {
  63. m_array = new BlockInterval[m_totalsize];
  64. memcpy(m_array, another.m_array, m_validsize*sizeof(BlockInterval));
  65. }
  66. };
  67. virtual ~IntervalArray(void) {
  68. m_totalsize = 0;
  69. m_validsize = 0;
  70. delete [] m_array;
  71. m_array = NULL;
  72. };
  73. bool operator == (const IntervalArray& a) const {
  74. if(m_validsize != a.m_validsize)
  75. return false;
  76. if(memcmp(m_array, a.m_array, sizeof(BlockInterval)*m_validsize) != 0)
  77. return false;
  78. return true;
  79. };
  80. IntervalArray& operator=(const IntervalArray& another) {
  81. m_totalsize = m_validsize = another.m_validsize;
  82. delete [] m_array;
  83. m_array = NULL;
  84. if(m_totalsize) {
  85. m_array = new BlockInterval[m_totalsize];
  86. memcpy(m_array, another.m_array, m_validsize*sizeof(BlockInterval));
  87. }
  88.         return *this;
  89. }
  90. // 将another中的区间从m_array中删除
  91. void DeleteArray(const IntervalArray& another) {
  92. for(UINT16 i = 0; i < another.m_validsize; ++i) {
  93. DelInterval(another.m_array[i].start, another.m_array[i].size);
  94. }
  95. }
  96. // 对两个区间作&操作,结果保存在result
  97. // 这个方法效率比较低, 1. 有比遍历更好的比较办法,不必对所有的区间都作&操作
  98. // 2. 生成的区间列表直接就是有序无重叠的,使用AddInterval降低了效率
  99. void AndOperator(const IntervalArray& another, IntervalArray& result) const {
  100. BlockInterval temp;
  101. result.Clear();
  102. for(UINT16 i = 0; i < another.m_validsize; ++i) {
  103. for(UINT16 j = 0; j < m_validsize; ++j) {
  104. BlockInterval::and_op(m_array[j], another.m_array[i], temp);
  105. if(temp.size > 0)
  106. result.AddInterval(temp.start, temp.size);
  107. }
  108. }
  109. }
  110. // 添加一个区间,检查区间的合并
  111. void AddInterval(UINT start, UINT size) {
  112. if(start == UINT_MAX)
  113. return;
  114. assert(size != 0);
  115. if(size == 0)
  116. return;
  117. for(UINT16 i = 0; i < m_validsize; ++i) {
  118. if(m_array[i].start > start) {
  119. if(m_array[i].start > start+size) {
  120. // 在区间i之前添加一个新区间
  121. break;
  122. }
  123. else if(m_array[i].start+m_array[i].size >= start+size) {
  124. // 新的区间和区间i融合,形成新的独立区间,所以直接返回
  125. m_array[i].size += m_array[i].start-start;
  126. m_array[i].start = start;
  127. return;
  128. }
  129. else {
  130. // 新的区间覆盖了区间i,所以删除区间i,递归调用
  131. SafeDelete(i);
  132. AddInterval(start, size);
  133. return;
  134. }
  135. }
  136. else if(m_array[i].start+m_array[i].size >= start) {
  137. if(m_array[i].start+m_array[i].size >= start+size) {
  138. // 新的区间是区间i的子集,直接返回
  139. return;
  140. }
  141. if(i == m_validsize-1 || m_array[i+1].start > start+size) {
  142. // 新的区间和区间i融合,形成新的独立区间,所以直接返回
  143. m_array[i].size = start+size-m_array[i].start;
  144. return;
  145. }
  146. // 新的区间和区间i融合,并且形成的新区间连接了后面的区间,
  147. // 所以删除区间i,把形成的新区间当作要添加的区间,递归调用
  148. // TODO: 或许有更好的办法,但一时想不到
  149. size += start - m_array[i].start;
  150. start = m_array[i].start;
  151. SafeDelete(i);
  152. AddInterval(start, size);
  153. return;
  154. }
  155. }
  156. // 在区间数组的某个位置添加区间
  157. SafeInsert(i, start, size);
  158. return;
  159. };
  160. // 删除一个区间,检查多个区间的删除
  161. void DelInterval(UINT start, UINT size) {
  162. assert(size != 0);
  163. if(size == 0)
  164. return;
  165. for(UINT16 i = 0; i < m_validsize; ++i) {
  166. if(m_array[i].start > start) {
  167. if(m_array[i].start > start+size) {
  168. // 要删除的区间根本不存在
  169. return;
  170. }
  171. else if(m_array[i].start+m_array[i].size > start+size) {
  172. // 要删除的区间包含了区间i的前半部分,后半部分形成新的独立区间
  173. // 区间i的后半部分形成的区间
  174. m_array[i].size = (m_array[i].start+m_array[i].size) - (start+size);
  175. m_array[i].start = start+size;
  176. return;
  177. }
  178. else {
  179. // 要删除的区间覆盖了区间i,所以删除区间i,递归调用
  180. SafeDelete(i);
  181. DelInterval(start, size);
  182. return;
  183. }
  184. }
  185. else if(m_array[i].start+m_array[i].size > start) {
  186. // 区间i最多可能被分为两个区间,分别称之为前一部分和后一部分
  187. // 记录区间i的大小,因为它可能被改变,而后面可能要用到
  188. UINT oldSize = m_array[i].size;
  189. if(m_array[i].start != start) {
  190. // 前一部分非空,令区间i等于其前一部分
  191. m_array[i].size = start-m_array[i].start;
  192. }
  193. if(m_array[i].start+oldSize <= start+size) {
  194. // 后一部分为空
  195. if(m_array[i].start != start) {
  196. // 前一部分非空,递归
  197. DelInterval(start, size);
  198. return;
  199. }
  200. // 前一部分为空,则删除区间i
  201. SafeDelete(i);
  202. return;
  203. }
  204. // 后一部分非空
  205. if(m_array[i].start == start) {
  206. // 前一部分为空,令区间i等于其后一部分
  207. m_array[i].size -= start+size-m_array[i].start;
  208. m_array[i].start = start+size;
  209. return;
  210. }
  211. // 前后均非空,则在区间i之后插入一个新的区间
  212. SafeInsert(i+1, start+size, m_array[i].start+oldSize - (start+size));
  213. return;
  214. }
  215. }
  216. };
  217. // 查找一个block是否存在
  218. bool FindBlock(const UINT blockID) const {
  219. for(UINT16 i = 0; i < m_validsize; ++i) {
  220. if(m_array[i].start > blockID)
  221. return false;
  222. // 注意start+size不在区间之内
  223. else if(m_array[i].start+m_array[i].size > blockID)
  224. return true;
  225. }
  226. return false;
  227. };
  228. // 复制block区间的数组到传入的指针,传入需要的区间个数,返回实际复制的区间个数
  229. // 如果需要的个数小于总个数,则取其中最大的区间
  230. void CopyIntervalArray(BlockInterval* targetArray, UINT8& size) const {
  231. if(!targetArray || size == 0)
  232. return;
  233. if(size >= m_validsize) {
  234. // 因为size >= m_validsize,所以下面的转换不会丢失数据
  235. size = static_cast<UINT8>(m_validsize);
  236. memcpy(targetArray, m_array, size*sizeof(BlockInterval));
  237. }
  238. else {
  239. // 对m_array根据每个BlockInterval的size进行从小到大的排序,然后复制最大的size个到targetArray
  240. // 最后再根据每个BlockInterval的start进行从小到大的排序,恢复m_array和targetArray
  241. std::sort(m_array, m_array+m_validsize, BlockInterval::cmp_size); // 按从大到小的顺序排序
  242. memcpy(targetArray, m_array, size*sizeof(BlockInterval)); // 复制最大的size个
  243. std::sort(m_array, m_array+m_validsize, BlockInterval::cmp_start); // 恢复原来的顺序(按startBlockID从小到大排序)
  244. std::sort(targetArray, targetArray+size, BlockInterval::cmp_start); // 使用正常的顺序(按startBlockID从小到大排序)
  245. }
  246. };
  247. // 清空列表
  248. void Clear() {
  249. m_validsize = 0;
  250. };
  251. // 是否为空
  252. bool IsEmpty() const {
  253. return (m_validsize == 0);
  254. }
  255. // 最大块的ID
  256. UINT GetMaxBlockID() const {
  257. if(m_validsize)
  258. return m_array[m_validsize-1].start+m_array[m_validsize-1].size;
  259. // 返回0表示没有任何块
  260. return 0;
  261. };
  262. // 最小块的ID
  263. UINT GetMinBlockID() const {
  264. if(m_validsize)
  265. return m_array[0].start;
  266. // 返回UINT_MAX表示没有任何块
  267. return UINT_MAX;
  268. }
  269. // 获取有效区间的个数
  270. UINT16 GetValidSize() const {
  271. return m_validsize;
  272. };
  273. // [blockID, blockID+len)中所有已经存在的块数
  274. UINT GetCountInInterval(const UINT blockID, const UINT len) const {
  275. UINT total = 0;
  276. BlockInterval result, in;
  277. in.start = blockID;
  278. in.size = min(len, UINT_MAX-blockID);
  279. for(UINT16 i = 0; i < m_validsize; ++i) {
  280. BlockInterval::and_op(m_array[i], in, result);
  281. total += result.size;
  282. }
  283. return total;
  284. };
  285. // 获取某个Block及其后的连续长度
  286. UINT GetContinousCount(const UINT blockID) const {
  287. for(UINT16 i = 0; i < m_validsize; ++i) {
  288. if(m_array[i].start > blockID)
  289. return 0;
  290. // 注意start+size不在区间之内
  291. else if(m_array[i].start+m_array[i].size > blockID) {
  292. return m_array[i].start+m_array[i].size-blockID;
  293. }
  294. }
  295. return 0;
  296. };
  297. // pop第一个区间
  298. void PopFront(BlockInterval& bi) {
  299. if(m_validsize) {
  300. bi = m_array[0];
  301. SafeDelete(0);
  302. }
  303. else
  304. memset(&bi, 0, sizeof(bi));
  305. }
  306. // 测试代码,打印出当前数组中的项
  307. void Print() const {
  308. printf("nTOTAL: %d, VALID: %d.n", m_totalsize, m_validsize);
  309. for(UINT16 i = 0; i < m_validsize; ++i) {
  310. printf("START: %d, END: %d, SIZE: %d.n", m_array[i].start, m_array[i].start+m_array[i].size, m_array[i].size);
  311. }
  312. }
  313. // 检查区间列表是否有序且无重叠
  314. bool Verify() const {
  315. for(UINT16 i = 0; i < m_validsize; ++i) {
  316. if(m_array[i].size == 0)
  317. return false;
  318. if(UINT_MAX - m_array[i].start < m_array[i].size)
  319. return false;
  320. if(i == m_validsize-1)
  321. break;
  322. if(m_array[i].start + m_array[i].size >= m_array[i+1].start)
  323. return false;
  324. }
  325. return true;
  326. }
  327. protected:
  328. // 在区间数组的某个位置添加区间,必须保证不破坏数组的有序性和无重叠性
  329. void SafeInsert(UINT16 i, UINT start, UINT size) {
  330. assert(m_validsize <= m_totalsize);
  331. assert(i <= m_validsize);
  332. assert(m_validsize <= 0xffff);
  333. // 不能再大了
  334. if(m_validsize == 0xffff)
  335. return;
  336. BlockInterval* temp = m_array;
  337. if(m_totalsize == m_validsize) {
  338. // 如果没有无效区间可以使用,那么需要增加数组大小
  339. // 分配一个空间更大的数组,并把区间i之前的数据复制过去
  340. m_array = new BlockInterval[m_validsize+1];
  341. memcpy(m_array, temp, i*sizeof(BlockInterval));
  342. }
  343. // 区间i及其之后的区间向数组尾部移动一格
  344. memcpy(m_array+i+1, temp+i, (m_validsize-i)*sizeof(BlockInterval));
  345. // 将区间i设置为新的区间
  346. m_array[i].start = start;
  347. m_array[i].size = size;
  348. // 此时m_totalsize和m_validsize尚未增加计数,所以可以用来判断是否增加过区间大小
  349. if(m_totalsize == m_validsize) {
  350. // 删除旧的数组,并增加数组大小的计数
  351. delete [] temp;
  352. ++m_totalsize;
  353. }
  354. // 增加有效区间的计数
  355. ++m_validsize;
  356. assert(m_validsize <= 0xffff);
  357. };
  358. // 删除一个区间,并把后面的区间向前移动,保证传入参数是有效的
  359. void SafeDelete(UINT16 i) {
  360. assert(i < m_validsize);
  361. ::memmove(m_array+i, m_array+i+1, (m_validsize-i-1)*sizeof(BlockInterval));
  362. --m_validsize;
  363. }
  364. private:
  365. // block区间的数组,保证无重叠和有序
  366. BlockInterval* m_array;
  367. // 数组的大小
  368. UINT16 m_totalsize;
  369. // 从数组头部开始有效区间的个数
  370. UINT16 m_validsize;
  371. };