yallist.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. module.exports = Yallist
  2. Yallist.Node = Node
  3. Yallist.create = Yallist
  4. function Yallist (list) {
  5. var self = this
  6. if (!(self instanceof Yallist)) {
  7. self = new Yallist()
  8. }
  9. self.tail = null
  10. self.head = null
  11. self.length = 0
  12. if (list && typeof list.forEach === 'function') {
  13. list.forEach(function (item) {
  14. self.push(item)
  15. })
  16. } else if (arguments.length > 0) {
  17. for (var i = 0, l = arguments.length; i < l; i++) {
  18. self.push(arguments[i])
  19. }
  20. }
  21. return self
  22. }
  23. Yallist.prototype.removeNode = function (node) {
  24. if (node.list !== this) {
  25. throw new Error('removing node which does not belong to this list')
  26. }
  27. var next = node.next
  28. var prev = node.prev
  29. if (next) {
  30. next.prev = prev
  31. }
  32. if (prev) {
  33. prev.next = next
  34. }
  35. if (node === this.head) {
  36. this.head = next
  37. }
  38. if (node === this.tail) {
  39. this.tail = prev
  40. }
  41. node.list.length --
  42. node.next = null
  43. node.prev = null
  44. node.list = null
  45. }
  46. Yallist.prototype.unshiftNode = function (node) {
  47. if (node === this.head) {
  48. return
  49. }
  50. if (node.list) {
  51. node.list.removeNode(node)
  52. }
  53. var head = this.head
  54. node.list = this
  55. node.next = head
  56. if (head) {
  57. head.prev = node
  58. }
  59. this.head = node
  60. if (!this.tail) {
  61. this.tail = node
  62. }
  63. this.length ++
  64. }
  65. Yallist.prototype.pushNode = function (node) {
  66. if (node === this.tail) {
  67. return
  68. }
  69. if (node.list) {
  70. node.list.removeNode(node)
  71. }
  72. var tail = this.tail
  73. node.list = this
  74. node.prev = tail
  75. if (tail) {
  76. tail.next = node
  77. }
  78. this.tail = node
  79. if (!this.head) {
  80. this.head = node
  81. }
  82. this.length ++
  83. }
  84. Yallist.prototype.push = function () {
  85. for (var i = 0, l = arguments.length; i < l; i++) {
  86. push(this, arguments[i])
  87. }
  88. return this.length
  89. }
  90. Yallist.prototype.unshift = function () {
  91. for (var i = 0, l = arguments.length; i < l; i++) {
  92. unshift(this, arguments[i])
  93. }
  94. return this.length
  95. }
  96. Yallist.prototype.pop = function () {
  97. if (!this.tail)
  98. return undefined
  99. var res = this.tail.value
  100. this.tail = this.tail.prev
  101. this.tail.next = null
  102. this.length --
  103. return res
  104. }
  105. Yallist.prototype.shift = function () {
  106. if (!this.head)
  107. return undefined
  108. var res = this.head.value
  109. this.head = this.head.next
  110. this.head.prev = null
  111. this.length --
  112. return res
  113. }
  114. Yallist.prototype.forEach = function (fn, thisp) {
  115. thisp = thisp || this
  116. for (var walker = this.head, i = 0; walker !== null; i++) {
  117. fn.call(thisp, walker.value, i, this)
  118. walker = walker.next
  119. }
  120. }
  121. Yallist.prototype.forEachReverse = function (fn, thisp) {
  122. thisp = thisp || this
  123. for (var walker = this.tail, i = this.length - 1; walker !== null; i--) {
  124. fn.call(thisp, walker.value, i, this)
  125. walker = walker.prev
  126. }
  127. }
  128. Yallist.prototype.get = function (n) {
  129. for (var i = 0, walker = this.head; walker !== null && i < n; i++) {
  130. // abort out of the list early if we hit a cycle
  131. walker = walker.next
  132. }
  133. if (i === n && walker !== null) {
  134. return walker.value
  135. }
  136. }
  137. Yallist.prototype.getReverse = function (n) {
  138. for (var i = 0, walker = this.tail; walker !== null && i < n; i++) {
  139. // abort out of the list early if we hit a cycle
  140. walker = walker.prev
  141. }
  142. if (i === n && walker !== null) {
  143. return walker.value
  144. }
  145. }
  146. Yallist.prototype.map = function (fn, thisp) {
  147. thisp = thisp || this
  148. var res = new Yallist()
  149. for (var walker = this.head; walker !== null; ) {
  150. res.push(fn.call(thisp, walker.value, this))
  151. walker = walker.next
  152. }
  153. return res
  154. }
  155. Yallist.prototype.mapReverse = function (fn, thisp) {
  156. thisp = thisp || this
  157. var res = new Yallist()
  158. for (var walker = this.tail; walker !== null;) {
  159. res.push(fn.call(thisp, walker.value, this))
  160. walker = walker.prev
  161. }
  162. return res
  163. }
  164. Yallist.prototype.reduce = function (fn, initial) {
  165. var acc
  166. var walker = this.head
  167. if (arguments.length > 1) {
  168. acc = initial
  169. } else if (this.head) {
  170. walker = this.head.next
  171. acc = this.head.value
  172. } else {
  173. throw new TypeError('Reduce of empty list with no initial value')
  174. }
  175. for (var i = 0; walker !== null; i++) {
  176. acc = fn(acc, walker.value, i)
  177. walker = walker.next
  178. }
  179. return acc
  180. }
  181. Yallist.prototype.reduceReverse = function (fn, initial) {
  182. var acc
  183. var walker = this.tail
  184. if (arguments.length > 1) {
  185. acc = initial
  186. } else if (this.tail) {
  187. walker = this.tail.prev
  188. acc = this.tail.value
  189. } else {
  190. throw new TypeError('Reduce of empty list with no initial value')
  191. }
  192. for (var i = this.length - 1; walker !== null; i--) {
  193. acc = fn(acc, walker.value, i)
  194. walker = walker.prev
  195. }
  196. return acc
  197. }
  198. Yallist.prototype.toArray = function () {
  199. var arr = new Array(this.length)
  200. for (var i = 0, walker = this.head; walker !== null; i++) {
  201. arr[i] = walker.value
  202. walker = walker.next
  203. }
  204. return arr
  205. }
  206. Yallist.prototype.toArrayReverse = function () {
  207. var arr = new Array(this.length)
  208. for (var i = 0, walker = this.tail; walker !== null; i++) {
  209. arr[i] = walker.value
  210. walker = walker.prev
  211. }
  212. return arr
  213. }
  214. Yallist.prototype.slice = function (from, to) {
  215. to = to || this.length
  216. if (to < 0) {
  217. to += this.length
  218. }
  219. from = from || 0
  220. if (from < 0) {
  221. from += this.length
  222. }
  223. var ret = new Yallist()
  224. if (to < from || to < 0) {
  225. return ret
  226. }
  227. if (from < 0) {
  228. from = 0
  229. }
  230. if (to > this.length) {
  231. to = this.length
  232. }
  233. for (var i = 0, walker = this.head; walker !== null && i < from; i++) {
  234. walker = walker.next
  235. }
  236. for (; walker !== null && i < to; i++, walker = walker.next) {
  237. ret.push(walker.value)
  238. }
  239. return ret
  240. }
  241. Yallist.prototype.sliceReverse = function (from, to) {
  242. to = to || this.length
  243. if (to < 0) {
  244. to += this.length
  245. }
  246. from = from || 0
  247. if (from < 0) {
  248. from += this.length
  249. }
  250. var ret = new Yallist()
  251. if (to < from || to < 0) {
  252. return ret
  253. }
  254. if (from < 0) {
  255. from = 0
  256. }
  257. if (to > this.length) {
  258. to = this.length
  259. }
  260. for (var i = this.length, walker = this.tail; walker !== null && i > to; i--) {
  261. walker = walker.prev
  262. }
  263. for (; walker !== null && i > from; i--, walker = walker.prev) {
  264. ret.push(walker.value)
  265. }
  266. return ret
  267. }
  268. Yallist.prototype.reverse = function () {
  269. var head = this.head
  270. var tail = this.tail
  271. for (var walker = head; walker !== null; walker = walker.prev) {
  272. var p = walker.prev
  273. walker.prev = walker.next
  274. walker.next = p
  275. }
  276. this.head = tail
  277. this.tail = head
  278. return this
  279. }
  280. function push (self, item) {
  281. self.tail = new Node(item, self.tail, null, self)
  282. if (!self.head) {
  283. self.head = self.tail
  284. }
  285. self.length ++
  286. }
  287. function unshift (self, item) {
  288. self.head = new Node(item, null, self.head, self)
  289. if (!self.tail) {
  290. self.tail = self.head
  291. }
  292. self.length ++
  293. }
  294. function Node (value, prev, next, list) {
  295. if (!(this instanceof Node)) {
  296. return new Node(value, prev, next, list)
  297. }
  298. this.list = list
  299. this.value = value
  300. if (prev) {
  301. prev.next = this
  302. this.prev = prev
  303. } else {
  304. this.prev = null
  305. }
  306. if (next) {
  307. next.prev = this
  308. this.next = next
  309. } else {
  310. this.next = null
  311. }
  312. }