DoubleList.ts 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. export class DoubleList {
  2. head: DoubleListItem | null = null;
  3. tail: DoubleListItem | null = null;
  4. public get isEmpty() {
  5. return this.head == null;
  6. }
  7. public addToTail(data?: any): DoubleListItem {
  8. let item = DoubleListItem.getFromPool(data, 'dont_call_this_function_by_your_self');
  9. this.addItemToTail(item);
  10. return item;
  11. }
  12. public insertToHead(data?: any): DoubleListItem {
  13. let item = DoubleListItem.getFromPool(data, 'dont_call_this_function_by_your_self');
  14. this.insertItemToHead(item);
  15. return item;
  16. }
  17. private addItemToTail(item: DoubleListItem) {
  18. if (!item) {
  19. return;
  20. }
  21. if (item.isLinked) {
  22. throw Error('item must be unlinked.');
  23. }
  24. if (this.head == null) {
  25. this.head = this.tail = item;
  26. item.owner = this;
  27. item.pre = null;
  28. item.next = null;
  29. return;
  30. }
  31. if (!this.tail) {
  32. throw Error('tail can not be nil');
  33. }
  34. this.tail.next = item;
  35. item.pre = this.tail;
  36. this.tail = item;
  37. item.owner = this;
  38. }
  39. private insertItemToHead(item: DoubleListItem) {
  40. if (!item) {
  41. return;
  42. }
  43. if (item.isLinked) {
  44. throw Error('item must be unlinked.');
  45. }
  46. if (this.head == null) {
  47. this.head = this.tail = item;
  48. item.owner = this;
  49. item.pre = null;
  50. item.next = null;
  51. return;
  52. }
  53. this.head.pre = item;
  54. item.next = this.head;
  55. item.owner = this;
  56. this.head = item;
  57. }
  58. public forEach(cb: (v: DoubleListItem) => any) {
  59. if (!cb) {
  60. return;
  61. }
  62. let cur = this.head;
  63. while (cur) {
  64. let next = cur.next;
  65. let needBreak = cb(cur);
  66. if (needBreak) {
  67. return;
  68. }
  69. cur = next;
  70. }
  71. }
  72. clear() {
  73. this.forEach(v => {
  74. v.dispose();
  75. });
  76. }
  77. }
  78. export class DoubleListItem {
  79. public owner: DoubleList | null = null;
  80. public pre: DoubleListItem | null = null;
  81. public next: DoubleListItem | null = null;
  82. public data: any | null = null;
  83. private static _itemPool: DoubleList = new DoubleList();
  84. public static getFromPool(data: any | undefined, args: 'dont_call_this_function_by_your_self'): DoubleListItem {
  85. let item = this._itemPool.tail;
  86. if (item) {
  87. item.removeSelf();
  88. item.data = data;
  89. return item;
  90. }
  91. return new DoubleListItem(data, 'dont_call_this_function_by_your_self');
  92. }
  93. public static putBackToPool(item: DoubleListItem, args: 'dont_call_this_function_by_your_self') {
  94. item.removeSelf();
  95. (this._itemPool as any).addItemToTail(item);
  96. }
  97. constructor(data: any | undefined, args: 'dont_call_this_function_by_your_self') {
  98. this.data = data;
  99. }
  100. get isLinked() {
  101. return this.owner != null;
  102. }
  103. public dispose() {
  104. DoubleListItem.putBackToPool(this, 'dont_call_this_function_by_your_self');
  105. }
  106. private removeSelf() {
  107. if (!this.owner) {
  108. return;
  109. }
  110. if (this.owner.head == this) {
  111. this.owner.head = this.next;
  112. }
  113. if (this.owner.tail == this) {
  114. this.owner.tail = this.pre;
  115. }
  116. if (this.pre) {
  117. this.pre.next = this.next;
  118. }
  119. if (this.next) {
  120. this.next.pre = this.pre;
  121. }
  122. this.owner = null;
  123. this.pre = null;
  124. this.next = null;
  125. }
  126. }