yallist.js 7.2 KB

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