SequenceRangeCollection.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. //------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //------------------------------------------------------------
  4. namespace System.ServiceModel.Channels
  5. {
  6. using System.Collections;
  7. using System.Collections.Generic;
  8. using System.Runtime.Serialization;
  9. using System.Text;
  10. using System.ServiceModel;
  11. abstract class SequenceRangeCollection
  12. {
  13. static EmptyRangeCollection empty = new EmptyRangeCollection();
  14. static LowerComparer lowerComparer = new LowerComparer();
  15. static UpperComparer upperComparer = new UpperComparer();
  16. public abstract SequenceRange this[int index] { get; }
  17. public abstract int Count { get; }
  18. public static SequenceRangeCollection Empty
  19. {
  20. get
  21. {
  22. return empty;
  23. }
  24. }
  25. public abstract bool Contains(Int64 number);
  26. public abstract SequenceRangeCollection MergeWith(Int64 number);
  27. public abstract SequenceRangeCollection MergeWith(SequenceRange range);
  28. static SequenceRangeCollection GeneralCreate(SequenceRange[] sortedRanges)
  29. {
  30. if (sortedRanges.Length == 0)
  31. {
  32. return empty;
  33. }
  34. else if (sortedRanges.Length == 1)
  35. {
  36. return new SingleItemRangeCollection(sortedRanges[0]);
  37. }
  38. else
  39. {
  40. return new MultiItemRangeCollection(sortedRanges);
  41. }
  42. }
  43. static SequenceRangeCollection GeneralMerge(SequenceRange[] sortedRanges, SequenceRange range)
  44. {
  45. if (sortedRanges.Length == 0)
  46. {
  47. return new SingleItemRangeCollection(range);
  48. }
  49. int lowerBound;
  50. if (sortedRanges.Length == 1)
  51. {
  52. // Avoid performance hit of binary search in single range case
  53. if (range.Lower == sortedRanges[0].Upper)
  54. {
  55. lowerBound = 0;
  56. }
  57. else if (range.Lower < sortedRanges[0].Upper)
  58. {
  59. lowerBound = ~0;
  60. }
  61. else
  62. {
  63. lowerBound = ~1;
  64. }
  65. }
  66. else
  67. {
  68. lowerBound = Array.BinarySearch(sortedRanges, new SequenceRange(range.Lower), upperComparer);
  69. }
  70. if (lowerBound < 0)
  71. {
  72. lowerBound = ~lowerBound;
  73. if ((lowerBound > 0) && (sortedRanges[lowerBound - 1].Upper == range.Lower - 1))
  74. {
  75. lowerBound--;
  76. }
  77. if (lowerBound == sortedRanges.Length)
  78. {
  79. SequenceRange[] returnedRanges = new SequenceRange[sortedRanges.Length + 1];
  80. Array.Copy(sortedRanges, returnedRanges, sortedRanges.Length);
  81. returnedRanges[sortedRanges.Length] = range;
  82. return GeneralCreate(returnedRanges);
  83. }
  84. }
  85. int upperBound;
  86. if (sortedRanges.Length == 1)
  87. {
  88. // Avoid performance hit of binary search in single range case
  89. if (range.Upper == sortedRanges[0].Lower)
  90. {
  91. upperBound = 0;
  92. }
  93. else if (range.Upper < sortedRanges[0].Lower)
  94. {
  95. upperBound = ~0;
  96. }
  97. else
  98. {
  99. upperBound = ~1;
  100. }
  101. }
  102. else
  103. {
  104. upperBound = Array.BinarySearch(sortedRanges, new SequenceRange(range.Upper), lowerComparer);
  105. }
  106. if (upperBound < 0)
  107. {
  108. upperBound = ~upperBound;
  109. if (upperBound > 0)
  110. {
  111. if ((upperBound == sortedRanges.Length) || (sortedRanges[upperBound].Lower != range.Upper + 1))
  112. {
  113. upperBound--;
  114. }
  115. }
  116. else if (sortedRanges[0].Lower > range.Upper + 1)
  117. {
  118. SequenceRange[] returnedRanges = new SequenceRange[sortedRanges.Length + 1];
  119. Array.Copy(sortedRanges, 0, returnedRanges, 1, sortedRanges.Length);
  120. returnedRanges[0] = range;
  121. return GeneralCreate(returnedRanges);
  122. }
  123. }
  124. Int64 newLower = (range.Lower < sortedRanges[lowerBound].Lower) ? range.Lower : sortedRanges[lowerBound].Lower;
  125. Int64 newUpper = (range.Upper > sortedRanges[upperBound].Upper) ? range.Upper : sortedRanges[upperBound].Upper;
  126. int rangesRemoved = upperBound - lowerBound + 1;
  127. int rangesRemaining = sortedRanges.Length - rangesRemoved + 1;
  128. if (rangesRemaining == 1)
  129. {
  130. return new SingleItemRangeCollection(newLower, newUpper);
  131. }
  132. else
  133. {
  134. SequenceRange[] returnedRanges = new SequenceRange[rangesRemaining];
  135. Array.Copy(sortedRanges, returnedRanges, lowerBound);
  136. returnedRanges[lowerBound] = new SequenceRange(newLower, newUpper);
  137. Array.Copy(sortedRanges, upperBound + 1, returnedRanges, lowerBound + 1, sortedRanges.Length - upperBound - 1);
  138. return GeneralCreate(returnedRanges);
  139. }
  140. }
  141. public override string ToString()
  142. {
  143. StringBuilder builder = new StringBuilder();
  144. for (int i = 0; i < Count; i++)
  145. {
  146. SequenceRange range = this[i];
  147. if (i > 0)
  148. {
  149. builder.Append(',');
  150. }
  151. builder.Append(range.Lower);
  152. builder.Append('-');
  153. builder.Append(range.Upper);
  154. }
  155. return builder.ToString();
  156. }
  157. class EmptyRangeCollection : SequenceRangeCollection
  158. {
  159. public override SequenceRange this[int index]
  160. {
  161. get
  162. {
  163. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("index"));
  164. }
  165. }
  166. public override int Count
  167. {
  168. get
  169. {
  170. return 0;
  171. }
  172. }
  173. public override bool Contains(Int64 number)
  174. {
  175. return false;
  176. }
  177. public override SequenceRangeCollection MergeWith(Int64 number)
  178. {
  179. return new SingleItemRangeCollection(number, number);
  180. }
  181. public override SequenceRangeCollection MergeWith(SequenceRange range)
  182. {
  183. return new SingleItemRangeCollection(range);
  184. }
  185. }
  186. class MultiItemRangeCollection : SequenceRangeCollection
  187. {
  188. SequenceRange[] ranges;
  189. public MultiItemRangeCollection(SequenceRange[] sortedRanges)
  190. {
  191. this.ranges = sortedRanges;
  192. }
  193. public override SequenceRange this[int index]
  194. {
  195. get
  196. {
  197. if (index < 0 || index >= ranges.Length)
  198. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("index", index,
  199. SR.GetString(SR.ValueMustBeInRange, 0, ranges.Length - 1)));
  200. return this.ranges[index];
  201. }
  202. }
  203. public override int Count
  204. {
  205. get
  206. {
  207. return this.ranges.Length;
  208. }
  209. }
  210. public override bool Contains(Int64 number)
  211. {
  212. if (this.ranges.Length == 0)
  213. {
  214. return false;
  215. }
  216. else if (this.ranges.Length == 1)
  217. {
  218. return this.ranges[0].Contains(number);
  219. }
  220. SequenceRange searchFor = new SequenceRange(number);
  221. int searchValue = Array.BinarySearch(this.ranges, searchFor, lowerComparer);
  222. if (searchValue >= 0)
  223. {
  224. return true;
  225. }
  226. searchValue = ~searchValue;
  227. if (searchValue == 0)
  228. {
  229. return false;
  230. }
  231. return (this.ranges[searchValue - 1].Upper >= number);
  232. }
  233. public override SequenceRangeCollection MergeWith(Int64 number)
  234. {
  235. return MergeWith(new SequenceRange(number));
  236. }
  237. public override SequenceRangeCollection MergeWith(SequenceRange newRange)
  238. {
  239. return GeneralMerge(this.ranges, newRange);
  240. }
  241. }
  242. class SingleItemRangeCollection : SequenceRangeCollection
  243. {
  244. SequenceRange range;
  245. public SingleItemRangeCollection(SequenceRange range)
  246. {
  247. this.range = range;
  248. }
  249. public SingleItemRangeCollection(Int64 lower, Int64 upper)
  250. {
  251. this.range = new SequenceRange(lower, upper);
  252. }
  253. public override SequenceRange this[int index]
  254. {
  255. get
  256. {
  257. if (index != 0)
  258. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("index"));
  259. return this.range;
  260. }
  261. }
  262. public override int Count
  263. {
  264. get
  265. {
  266. return 1;
  267. }
  268. }
  269. public override bool Contains(Int64 number)
  270. {
  271. return this.range.Contains(number);
  272. }
  273. public override SequenceRangeCollection MergeWith(Int64 number)
  274. {
  275. if (number == this.range.Upper + 1)
  276. {
  277. return new SingleItemRangeCollection(range.Lower, number);
  278. }
  279. else
  280. {
  281. return MergeWith(new SequenceRange(number));
  282. }
  283. }
  284. public override SequenceRangeCollection MergeWith(SequenceRange newRange)
  285. {
  286. if (newRange.Lower == this.range.Upper + 1)
  287. {
  288. return new SingleItemRangeCollection(range.Lower, newRange.Upper);
  289. }
  290. else if (this.range.Contains(newRange))
  291. {
  292. return this;
  293. }
  294. else if (newRange.Contains(this.range))
  295. {
  296. return new SingleItemRangeCollection(newRange);
  297. }
  298. else if (newRange.Upper == this.range.Lower - 1)
  299. {
  300. return new SingleItemRangeCollection(newRange.Lower, this.range.Upper);
  301. }
  302. else
  303. {
  304. return GeneralMerge(new SequenceRange[] { this.range }, newRange);
  305. }
  306. }
  307. }
  308. class LowerComparer : IComparer<SequenceRange>
  309. {
  310. public int Compare(SequenceRange x, SequenceRange y)
  311. {
  312. if (x.Lower < y.Lower)
  313. {
  314. return -1;
  315. }
  316. else if (x.Lower > y.Lower)
  317. {
  318. return 1;
  319. }
  320. else
  321. {
  322. return 0;
  323. }
  324. }
  325. }
  326. class UpperComparer : IComparer<SequenceRange>
  327. {
  328. public int Compare(SequenceRange x, SequenceRange y)
  329. {
  330. if (x.Upper < y.Upper)
  331. {
  332. return -1;
  333. }
  334. else if (x.Upper > y.Upper)
  335. {
  336. return 1;
  337. }
  338. else
  339. {
  340. return 0;
  341. }
  342. }
  343. }
  344. }
  345. }