@akashbabu/node-dll
Advanced tools
Comparing version 1.1.0 to 2.0.0
240
dist/dll.js
@@ -8,25 +8,53 @@ (function (global, factory) { | ||
class DLLItem { | ||
constructor(value, prev = null, next = null) { | ||
this.value = value; | ||
constructor(data, prev = null, next = null) { | ||
this.data = data; | ||
this.prev = prev; | ||
this.next = next; | ||
} | ||
setValue(value) { | ||
this.value = value; | ||
} | ||
class DLLItemAccessRestrictor { | ||
/** | ||
* Grants all the access on the given dllItem | ||
* | ||
* @param accessRestrictedDllItem dll item whose access is restricted | ||
* | ||
* @returns all access granted dll item | ||
*/ | ||
grantAccess(accessRestrictedDllItem) { | ||
return accessRestrictedDllItem.__dllItem__; | ||
} | ||
getValue() { | ||
return this.value; | ||
/** | ||
* Revokes write access to `prev` & `next` properties | ||
* | ||
* @param dllItem a node in the dll chain | ||
* | ||
* @returns Access restricted dll item | ||
*/ | ||
revokeAccess(dllItem) { | ||
return new AccessRestrictedDLLItem(dllItem); | ||
} | ||
setPrev(dllItem) { | ||
this.prev = dllItem; | ||
} | ||
class AccessRestrictedDLLItem { | ||
constructor(dllItem) { | ||
this.dllItem = dllItem; | ||
this.dllItemAccessRestrictor = new DLLItemAccessRestrictor(); | ||
this.__dllItem__ = dllItem; | ||
} | ||
getPrev() { | ||
return this.prev; | ||
get data() { | ||
return this.dllItem.data; | ||
} | ||
setNext(dllItem) { | ||
this.next = dllItem; | ||
set data(dt) { | ||
this.dllItem.data = dt; | ||
} | ||
getNext() { | ||
return this.next; | ||
get prev() { | ||
return this.dllItem.prev | ||
? this.dllItemAccessRestrictor.revokeAccess(this.dllItem.prev) | ||
: null; | ||
} | ||
get next() { | ||
return this.dllItem.next | ||
? this.dllItemAccessRestrictor.revokeAccess(this.dllItem.next) | ||
: null; | ||
} | ||
} | ||
@@ -36,22 +64,18 @@ | ||
constructor() { | ||
this.length = 0; | ||
this.head = null; | ||
this.tail = null; | ||
this.state = this.getFreshState(); | ||
this.dllItemAccessRestrictor = new DLLItemAccessRestrictor(); | ||
} | ||
/** | ||
* Returns the first item in the list | ||
* | ||
* @returns first item | ||
*/ | ||
getHead() { | ||
return this.head; | ||
get head() { | ||
return this.state.head | ||
? this.dllItemAccessRestrictor.revokeAccess(this.state.head) | ||
: null; | ||
} | ||
/** | ||
* Returns the last item in the list | ||
* | ||
* @returns last item | ||
*/ | ||
getTail() { | ||
return this.tail; | ||
get tail() { | ||
return this.state.tail | ||
? this.dllItemAccessRestrictor.revokeAccess(this.state.tail) | ||
: null; | ||
} | ||
get length() { | ||
return this.state.length; | ||
} | ||
/** | ||
@@ -65,7 +89,10 @@ * Removes and returns the first | ||
shift() { | ||
const dllItem = this.getHead(); | ||
let dllItem = this.state.head; | ||
if (!(dllItem instanceof DLLItem)) | ||
return undefined; | ||
this.remove(dllItem); | ||
return dllItem.getValue(); | ||
const value = dllItem.data; | ||
// for gc | ||
dllItem = null; | ||
return value; | ||
} | ||
@@ -83,28 +110,35 @@ /** | ||
unshift(data) { | ||
const currHead = this.getHead(); | ||
const currHead = this.state.head; | ||
const dllItem = new DLLItem(data, null, currHead); | ||
this.head = dllItem; | ||
this.state.head = dllItem; | ||
if (currHead instanceof DLLItem) { | ||
currHead.setPrev(dllItem); | ||
currHead.prev = dllItem; | ||
// if HEAD is not set | ||
// then its an empty list | ||
} | ||
else { | ||
this.tail = dllItem; | ||
this.state.tail = dllItem; | ||
} | ||
this.length++; | ||
this.state.length++; | ||
} | ||
/** | ||
* Iterate through the entire DLL chain | ||
* just like Array.forEach() | ||
* | ||
* @param cb | ||
* @param cb iterator callback | ||
*/ | ||
forEach(cb) { | ||
let dllItem = this.getHead(); | ||
let i = 0; | ||
while (dllItem) { | ||
cb(dllItem.getValue(), i++); | ||
dllItem = dllItem.getNext(); | ||
} | ||
// gc | ||
dllItem = null; | ||
this.iterate((dllItem, i) => { | ||
cb(dllItem.data, i); | ||
}); | ||
} | ||
/** | ||
* Iterates through the entire DLL chain | ||
* and returns the result array, just | ||
* like Array.map() | ||
* | ||
* @param cb iterator callback | ||
* | ||
* @returns the result array just like Array.map() | ||
*/ | ||
map(cb) { | ||
@@ -127,16 +161,42 @@ const mapped = []; | ||
push(data) { | ||
const dllItem = new DLLItem(data, this.tail); | ||
if (this.tail instanceof DLLItem) { | ||
this.tail.setNext(dllItem); | ||
// set this item as the new tail | ||
this.tail = dllItem; | ||
return this.appendAfter(this.state.tail, data); | ||
} | ||
/** | ||
* Appends the given value after the | ||
* specified node | ||
* | ||
* @param node Node to append the new item | ||
* @param data Value for the new node | ||
* | ||
* @returns the newly appended node | ||
*/ | ||
appendAfter(accessRestrictedNode, data) { | ||
let node; | ||
if (accessRestrictedNode === null && this.state.length > 0) { | ||
throw new Error('Invalid Node `null`: DLL is not empty, hence can\'t append to the given node'); | ||
} | ||
else if (accessRestrictedNode instanceof AccessRestrictedDLLItem) { | ||
node = this.dllItemAccessRestrictor.grantAccess(accessRestrictedNode); | ||
} | ||
else { | ||
// if this is the first item in the DLL | ||
// then it would be the head and the tail | ||
// of DLL | ||
this.head = this.tail = dllItem; | ||
node = accessRestrictedNode; | ||
} | ||
this.length++; | ||
return dllItem; | ||
const dllItem = new DLLItem(data); | ||
// if node is null, then it means | ||
// that the list is empty | ||
if (node === null) { | ||
this.state.head = this.state.tail = dllItem; | ||
} | ||
else { | ||
dllItem.prev = node; | ||
dllItem.next = node.next; | ||
node.next = dllItem; | ||
// if the node was a tail node | ||
// then reset the tail node | ||
if (node === this.state.tail) { | ||
this.state.tail = dllItem; | ||
} | ||
} | ||
this.state.length++; | ||
return this.dllItemAccessRestrictor.revokeAccess(dllItem); | ||
} | ||
@@ -148,30 +208,62 @@ /** | ||
*/ | ||
remove(dllItem) { | ||
if (!(dllItem instanceof DLLItem)) | ||
remove(accessRestrictedDllItem) { | ||
let dllItem; | ||
if (accessRestrictedDllItem instanceof AccessRestrictedDLLItem) { | ||
dllItem = this.dllItemAccessRestrictor.grantAccess(accessRestrictedDllItem); | ||
} | ||
else if (accessRestrictedDllItem instanceof DLLItem) { | ||
dllItem = accessRestrictedDllItem; | ||
} | ||
else { | ||
return false; | ||
const prev = dllItem.getPrev(); | ||
const next = dllItem.getNext(); | ||
// If it's NOT HEAD | ||
if (prev instanceof DLLItem) { | ||
prev.setNext(next); | ||
// If it's HEAD | ||
} | ||
// Isolate the node from the chain | ||
if (dllItem.prev) { | ||
dllItem.prev.next = dllItem.next; | ||
} | ||
else { | ||
this.head = next; | ||
// If it's HEAD node | ||
this.state.head = dllItem.next; | ||
} | ||
// If it's NOT TAIL | ||
if (next instanceof DLLItem) { | ||
next.setPrev(prev); | ||
// If it's TAIL | ||
if (dllItem.next) { | ||
dllItem.next.prev = dllItem.prev; | ||
} | ||
else { | ||
this.tail = prev; | ||
// if it's also a TAIL node | ||
this.state.tail = dllItem.prev; | ||
} | ||
this.length--; | ||
this.state.length--; | ||
return true; | ||
} | ||
/** | ||
* Clears the DLL chain | ||
*/ | ||
clear() { | ||
// unlink all the items in the DLL chain | ||
// such it will be garbage collected | ||
// as no reference between them is found | ||
this.iterate((dllItem) => { | ||
dllItem.prev = dllItem.next = null; | ||
}); | ||
this.state = this.getFreshState(); | ||
} | ||
getFreshState() { | ||
return { | ||
length: 0, | ||
head: null, | ||
tail: null, | ||
}; | ||
} | ||
iterate(cb) { | ||
let dllItem = this.state.head; | ||
let i = 0; | ||
while (dllItem) { | ||
cb(dllItem, i++); | ||
dllItem = dllItem.next; | ||
} | ||
} | ||
} | ||
exports.DLL = DLL; | ||
exports.DLLItem = DLLItem; | ||
exports.DLLItem = AccessRestrictedDLLItem; | ||
@@ -178,0 +270,0 @@ Object.defineProperty(exports, '__esModule', { value: true }); |
@@ -1,1 +0,1 @@ | ||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t=t||self).DLL={})}(this,(function(t){"use strict";class e{constructor(t,e=null,s=null){this.value=t,this.prev=e,this.next=s}setValue(t){this.value=t}getValue(){return this.value}setPrev(t){this.prev=t}getPrev(){return this.prev}setNext(t){this.next=t}getNext(){return this.next}}t.DLL=class{constructor(){this.length=0,this.head=null,this.tail=null}getHead(){return this.head}getTail(){return this.tail}shift(){const t=this.getHead();if(t instanceof e)return this.remove(t),t.getValue()}unshift(t){const s=this.getHead(),i=new e(t,null,s);this.head=i,s instanceof e?s.setPrev(i):this.tail=i,this.length++}forEach(t){let e=this.getHead(),s=0;for(;e;)t(e.getValue(),s++),e=e.getNext();e=null}map(t){const e=[];return this.forEach((s,i)=>{e.push(t(s,i))}),e}push(t){const s=new e(t,this.tail);return this.tail instanceof e?(this.tail.setNext(s),this.tail=s):this.head=this.tail=s,this.length++,s}remove(t){if(!(t instanceof e))return!1;const s=t.getPrev(),i=t.getNext();return s instanceof e?s.setNext(i):this.head=i,i instanceof e?i.setPrev(s):this.tail=s,this.length--,!0}},t.DLLItem=e,Object.defineProperty(t,"__esModule",{value:!0})})); | ||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t=t||self).DLL={})}(this,(function(t){"use strict";class e{constructor(t,e=null,s=null){this.data=t,this.prev=e,this.next=s}}class s{grantAccess(t){return t.__dllItem__}revokeAccess(t){return new r(t)}}class r{constructor(t){this.dllItem=t,this.dllItemAccessRestrictor=new s,this.__dllItem__=t}get data(){return this.dllItem.data}set data(t){this.dllItem.data=t}get prev(){return this.dllItem.prev?this.dllItemAccessRestrictor.revokeAccess(this.dllItem.prev):null}get next(){return this.dllItem.next?this.dllItemAccessRestrictor.revokeAccess(this.dllItem.next):null}}t.DLL=class{constructor(){this.state=this.getFreshState(),this.dllItemAccessRestrictor=new s}get head(){return this.state.head?this.dllItemAccessRestrictor.revokeAccess(this.state.head):null}get tail(){return this.state.tail?this.dllItemAccessRestrictor.revokeAccess(this.state.tail):null}get length(){return this.state.length}shift(){let t=this.state.head;if(!(t instanceof e))return;this.remove(t);const s=t.data;return t=null,s}unshift(t){const s=this.state.head,r=new e(t,null,s);this.state.head=r,s instanceof e?s.prev=r:this.state.tail=r,this.state.length++}forEach(t){this.iterate((e,s)=>{t(e.data,s)})}map(t){const e=[];return this.forEach((s,r)=>{e.push(t(s,r))}),e}push(t){return this.appendAfter(this.state.tail,t)}appendAfter(t,s){let n;if(null===t&&this.state.length>0)throw Error("Invalid Node `null`: DLL is not empty, hence can't append to the given node");n=t instanceof r?this.dllItemAccessRestrictor.grantAccess(t):t;const i=new e(s);return null===n?this.state.head=this.state.tail=i:(i.prev=n,i.next=n.next,n.next=i,n===this.state.tail&&(this.state.tail=i)),this.state.length++,this.dllItemAccessRestrictor.revokeAccess(i)}remove(t){let s;if(t instanceof r)s=this.dllItemAccessRestrictor.grantAccess(t);else{if(!(t instanceof e))return!1;s=t}return s.prev?s.prev.next=s.next:this.state.head=s.next,s.next?s.next.prev=s.prev:this.state.tail=s.prev,this.state.length--,!0}clear(){this.iterate(t=>{t.prev=t.next=null}),this.state=this.getFreshState()}getFreshState(){return{length:0,head:null,tail:null}}iterate(t){let e=this.state.head,s=0;for(;e;)t(e,s++),e=e.next}},t.DLLItem=r,Object.defineProperty(t,"__esModule",{value:!0})})); |
240
es/dll.js
class DLLItem { | ||
constructor(value, prev = null, next = null) { | ||
this.value = value; | ||
constructor(data, prev = null, next = null) { | ||
this.data = data; | ||
this.prev = prev; | ||
this.next = next; | ||
} | ||
setValue(value) { | ||
this.value = value; | ||
} | ||
class DLLItemAccessRestrictor { | ||
/** | ||
* Grants all the access on the given dllItem | ||
* | ||
* @param accessRestrictedDllItem dll item whose access is restricted | ||
* | ||
* @returns all access granted dll item | ||
*/ | ||
grantAccess(accessRestrictedDllItem) { | ||
return accessRestrictedDllItem.__dllItem__; | ||
} | ||
getValue() { | ||
return this.value; | ||
/** | ||
* Revokes write access to `prev` & `next` properties | ||
* | ||
* @param dllItem a node in the dll chain | ||
* | ||
* @returns Access restricted dll item | ||
*/ | ||
revokeAccess(dllItem) { | ||
return new AccessRestrictedDLLItem(dllItem); | ||
} | ||
setPrev(dllItem) { | ||
this.prev = dllItem; | ||
} | ||
class AccessRestrictedDLLItem { | ||
constructor(dllItem) { | ||
this.dllItem = dllItem; | ||
this.dllItemAccessRestrictor = new DLLItemAccessRestrictor(); | ||
this.__dllItem__ = dllItem; | ||
} | ||
getPrev() { | ||
return this.prev; | ||
get data() { | ||
return this.dllItem.data; | ||
} | ||
setNext(dllItem) { | ||
this.next = dllItem; | ||
set data(dt) { | ||
this.dllItem.data = dt; | ||
} | ||
getNext() { | ||
return this.next; | ||
get prev() { | ||
return this.dllItem.prev | ||
? this.dllItemAccessRestrictor.revokeAccess(this.dllItem.prev) | ||
: null; | ||
} | ||
get next() { | ||
return this.dllItem.next | ||
? this.dllItemAccessRestrictor.revokeAccess(this.dllItem.next) | ||
: null; | ||
} | ||
} | ||
@@ -29,22 +57,18 @@ | ||
constructor() { | ||
this.length = 0; | ||
this.head = null; | ||
this.tail = null; | ||
this.state = this.getFreshState(); | ||
this.dllItemAccessRestrictor = new DLLItemAccessRestrictor(); | ||
} | ||
/** | ||
* Returns the first item in the list | ||
* | ||
* @returns first item | ||
*/ | ||
getHead() { | ||
return this.head; | ||
get head() { | ||
return this.state.head | ||
? this.dllItemAccessRestrictor.revokeAccess(this.state.head) | ||
: null; | ||
} | ||
/** | ||
* Returns the last item in the list | ||
* | ||
* @returns last item | ||
*/ | ||
getTail() { | ||
return this.tail; | ||
get tail() { | ||
return this.state.tail | ||
? this.dllItemAccessRestrictor.revokeAccess(this.state.tail) | ||
: null; | ||
} | ||
get length() { | ||
return this.state.length; | ||
} | ||
/** | ||
@@ -58,7 +82,10 @@ * Removes and returns the first | ||
shift() { | ||
const dllItem = this.getHead(); | ||
let dllItem = this.state.head; | ||
if (!(dllItem instanceof DLLItem)) | ||
return undefined; | ||
this.remove(dllItem); | ||
return dllItem.getValue(); | ||
const value = dllItem.data; | ||
// for gc | ||
dllItem = null; | ||
return value; | ||
} | ||
@@ -76,28 +103,35 @@ /** | ||
unshift(data) { | ||
const currHead = this.getHead(); | ||
const currHead = this.state.head; | ||
const dllItem = new DLLItem(data, null, currHead); | ||
this.head = dllItem; | ||
this.state.head = dllItem; | ||
if (currHead instanceof DLLItem) { | ||
currHead.setPrev(dllItem); | ||
currHead.prev = dllItem; | ||
// if HEAD is not set | ||
// then its an empty list | ||
} | ||
else { | ||
this.tail = dllItem; | ||
this.state.tail = dllItem; | ||
} | ||
this.length++; | ||
this.state.length++; | ||
} | ||
/** | ||
* Iterate through the entire DLL chain | ||
* just like Array.forEach() | ||
* | ||
* @param cb | ||
* @param cb iterator callback | ||
*/ | ||
forEach(cb) { | ||
let dllItem = this.getHead(); | ||
let i = 0; | ||
while (dllItem) { | ||
cb(dllItem.getValue(), i++); | ||
dllItem = dllItem.getNext(); | ||
} | ||
// gc | ||
dllItem = null; | ||
this.iterate((dllItem, i) => { | ||
cb(dllItem.data, i); | ||
}); | ||
} | ||
/** | ||
* Iterates through the entire DLL chain | ||
* and returns the result array, just | ||
* like Array.map() | ||
* | ||
* @param cb iterator callback | ||
* | ||
* @returns the result array just like Array.map() | ||
*/ | ||
map(cb) { | ||
@@ -120,16 +154,42 @@ const mapped = []; | ||
push(data) { | ||
const dllItem = new DLLItem(data, this.tail); | ||
if (this.tail instanceof DLLItem) { | ||
this.tail.setNext(dllItem); | ||
// set this item as the new tail | ||
this.tail = dllItem; | ||
return this.appendAfter(this.state.tail, data); | ||
} | ||
/** | ||
* Appends the given value after the | ||
* specified node | ||
* | ||
* @param node Node to append the new item | ||
* @param data Value for the new node | ||
* | ||
* @returns the newly appended node | ||
*/ | ||
appendAfter(accessRestrictedNode, data) { | ||
let node; | ||
if (accessRestrictedNode === null && this.state.length > 0) { | ||
throw new Error('Invalid Node `null`: DLL is not empty, hence can\'t append to the given node'); | ||
} | ||
else if (accessRestrictedNode instanceof AccessRestrictedDLLItem) { | ||
node = this.dllItemAccessRestrictor.grantAccess(accessRestrictedNode); | ||
} | ||
else { | ||
// if this is the first item in the DLL | ||
// then it would be the head and the tail | ||
// of DLL | ||
this.head = this.tail = dllItem; | ||
node = accessRestrictedNode; | ||
} | ||
this.length++; | ||
return dllItem; | ||
const dllItem = new DLLItem(data); | ||
// if node is null, then it means | ||
// that the list is empty | ||
if (node === null) { | ||
this.state.head = this.state.tail = dllItem; | ||
} | ||
else { | ||
dllItem.prev = node; | ||
dllItem.next = node.next; | ||
node.next = dllItem; | ||
// if the node was a tail node | ||
// then reset the tail node | ||
if (node === this.state.tail) { | ||
this.state.tail = dllItem; | ||
} | ||
} | ||
this.state.length++; | ||
return this.dllItemAccessRestrictor.revokeAccess(dllItem); | ||
} | ||
@@ -141,28 +201,60 @@ /** | ||
*/ | ||
remove(dllItem) { | ||
if (!(dllItem instanceof DLLItem)) | ||
remove(accessRestrictedDllItem) { | ||
let dllItem; | ||
if (accessRestrictedDllItem instanceof AccessRestrictedDLLItem) { | ||
dllItem = this.dllItemAccessRestrictor.grantAccess(accessRestrictedDllItem); | ||
} | ||
else if (accessRestrictedDllItem instanceof DLLItem) { | ||
dllItem = accessRestrictedDllItem; | ||
} | ||
else { | ||
return false; | ||
const prev = dllItem.getPrev(); | ||
const next = dllItem.getNext(); | ||
// If it's NOT HEAD | ||
if (prev instanceof DLLItem) { | ||
prev.setNext(next); | ||
// If it's HEAD | ||
} | ||
// Isolate the node from the chain | ||
if (dllItem.prev) { | ||
dllItem.prev.next = dllItem.next; | ||
} | ||
else { | ||
this.head = next; | ||
// If it's HEAD node | ||
this.state.head = dllItem.next; | ||
} | ||
// If it's NOT TAIL | ||
if (next instanceof DLLItem) { | ||
next.setPrev(prev); | ||
// If it's TAIL | ||
if (dllItem.next) { | ||
dllItem.next.prev = dllItem.prev; | ||
} | ||
else { | ||
this.tail = prev; | ||
// if it's also a TAIL node | ||
this.state.tail = dllItem.prev; | ||
} | ||
this.length--; | ||
this.state.length--; | ||
return true; | ||
} | ||
/** | ||
* Clears the DLL chain | ||
*/ | ||
clear() { | ||
// unlink all the items in the DLL chain | ||
// such it will be garbage collected | ||
// as no reference between them is found | ||
this.iterate((dllItem) => { | ||
dllItem.prev = dllItem.next = null; | ||
}); | ||
this.state = this.getFreshState(); | ||
} | ||
getFreshState() { | ||
return { | ||
length: 0, | ||
head: null, | ||
tail: null, | ||
}; | ||
} | ||
iterate(cb) { | ||
let dllItem = this.state.head; | ||
let i = 0; | ||
while (dllItem) { | ||
cb(dllItem, i++); | ||
dllItem = dllItem.next; | ||
} | ||
} | ||
} | ||
export { DLL, DLLItem }; | ||
export { DLL, AccessRestrictedDLLItem as DLLItem }; |
240
lib/dll.js
@@ -6,25 +6,53 @@ 'use strict'; | ||
class DLLItem { | ||
constructor(value, prev = null, next = null) { | ||
this.value = value; | ||
constructor(data, prev = null, next = null) { | ||
this.data = data; | ||
this.prev = prev; | ||
this.next = next; | ||
} | ||
setValue(value) { | ||
this.value = value; | ||
} | ||
class DLLItemAccessRestrictor { | ||
/** | ||
* Grants all the access on the given dllItem | ||
* | ||
* @param accessRestrictedDllItem dll item whose access is restricted | ||
* | ||
* @returns all access granted dll item | ||
*/ | ||
grantAccess(accessRestrictedDllItem) { | ||
return accessRestrictedDllItem.__dllItem__; | ||
} | ||
getValue() { | ||
return this.value; | ||
/** | ||
* Revokes write access to `prev` & `next` properties | ||
* | ||
* @param dllItem a node in the dll chain | ||
* | ||
* @returns Access restricted dll item | ||
*/ | ||
revokeAccess(dllItem) { | ||
return new AccessRestrictedDLLItem(dllItem); | ||
} | ||
setPrev(dllItem) { | ||
this.prev = dllItem; | ||
} | ||
class AccessRestrictedDLLItem { | ||
constructor(dllItem) { | ||
this.dllItem = dllItem; | ||
this.dllItemAccessRestrictor = new DLLItemAccessRestrictor(); | ||
this.__dllItem__ = dllItem; | ||
} | ||
getPrev() { | ||
return this.prev; | ||
get data() { | ||
return this.dllItem.data; | ||
} | ||
setNext(dllItem) { | ||
this.next = dllItem; | ||
set data(dt) { | ||
this.dllItem.data = dt; | ||
} | ||
getNext() { | ||
return this.next; | ||
get prev() { | ||
return this.dllItem.prev | ||
? this.dllItemAccessRestrictor.revokeAccess(this.dllItem.prev) | ||
: null; | ||
} | ||
get next() { | ||
return this.dllItem.next | ||
? this.dllItemAccessRestrictor.revokeAccess(this.dllItem.next) | ||
: null; | ||
} | ||
} | ||
@@ -34,22 +62,18 @@ | ||
constructor() { | ||
this.length = 0; | ||
this.head = null; | ||
this.tail = null; | ||
this.state = this.getFreshState(); | ||
this.dllItemAccessRestrictor = new DLLItemAccessRestrictor(); | ||
} | ||
/** | ||
* Returns the first item in the list | ||
* | ||
* @returns first item | ||
*/ | ||
getHead() { | ||
return this.head; | ||
get head() { | ||
return this.state.head | ||
? this.dllItemAccessRestrictor.revokeAccess(this.state.head) | ||
: null; | ||
} | ||
/** | ||
* Returns the last item in the list | ||
* | ||
* @returns last item | ||
*/ | ||
getTail() { | ||
return this.tail; | ||
get tail() { | ||
return this.state.tail | ||
? this.dllItemAccessRestrictor.revokeAccess(this.state.tail) | ||
: null; | ||
} | ||
get length() { | ||
return this.state.length; | ||
} | ||
/** | ||
@@ -63,7 +87,10 @@ * Removes and returns the first | ||
shift() { | ||
const dllItem = this.getHead(); | ||
let dllItem = this.state.head; | ||
if (!(dllItem instanceof DLLItem)) | ||
return undefined; | ||
this.remove(dllItem); | ||
return dllItem.getValue(); | ||
const value = dllItem.data; | ||
// for gc | ||
dllItem = null; | ||
return value; | ||
} | ||
@@ -81,28 +108,35 @@ /** | ||
unshift(data) { | ||
const currHead = this.getHead(); | ||
const currHead = this.state.head; | ||
const dllItem = new DLLItem(data, null, currHead); | ||
this.head = dllItem; | ||
this.state.head = dllItem; | ||
if (currHead instanceof DLLItem) { | ||
currHead.setPrev(dllItem); | ||
currHead.prev = dllItem; | ||
// if HEAD is not set | ||
// then its an empty list | ||
} | ||
else { | ||
this.tail = dllItem; | ||
this.state.tail = dllItem; | ||
} | ||
this.length++; | ||
this.state.length++; | ||
} | ||
/** | ||
* Iterate through the entire DLL chain | ||
* just like Array.forEach() | ||
* | ||
* @param cb | ||
* @param cb iterator callback | ||
*/ | ||
forEach(cb) { | ||
let dllItem = this.getHead(); | ||
let i = 0; | ||
while (dllItem) { | ||
cb(dllItem.getValue(), i++); | ||
dllItem = dllItem.getNext(); | ||
} | ||
// gc | ||
dllItem = null; | ||
this.iterate((dllItem, i) => { | ||
cb(dllItem.data, i); | ||
}); | ||
} | ||
/** | ||
* Iterates through the entire DLL chain | ||
* and returns the result array, just | ||
* like Array.map() | ||
* | ||
* @param cb iterator callback | ||
* | ||
* @returns the result array just like Array.map() | ||
*/ | ||
map(cb) { | ||
@@ -125,16 +159,42 @@ const mapped = []; | ||
push(data) { | ||
const dllItem = new DLLItem(data, this.tail); | ||
if (this.tail instanceof DLLItem) { | ||
this.tail.setNext(dllItem); | ||
// set this item as the new tail | ||
this.tail = dllItem; | ||
return this.appendAfter(this.state.tail, data); | ||
} | ||
/** | ||
* Appends the given value after the | ||
* specified node | ||
* | ||
* @param node Node to append the new item | ||
* @param data Value for the new node | ||
* | ||
* @returns the newly appended node | ||
*/ | ||
appendAfter(accessRestrictedNode, data) { | ||
let node; | ||
if (accessRestrictedNode === null && this.state.length > 0) { | ||
throw new Error('Invalid Node `null`: DLL is not empty, hence can\'t append to the given node'); | ||
} | ||
else if (accessRestrictedNode instanceof AccessRestrictedDLLItem) { | ||
node = this.dllItemAccessRestrictor.grantAccess(accessRestrictedNode); | ||
} | ||
else { | ||
// if this is the first item in the DLL | ||
// then it would be the head and the tail | ||
// of DLL | ||
this.head = this.tail = dllItem; | ||
node = accessRestrictedNode; | ||
} | ||
this.length++; | ||
return dllItem; | ||
const dllItem = new DLLItem(data); | ||
// if node is null, then it means | ||
// that the list is empty | ||
if (node === null) { | ||
this.state.head = this.state.tail = dllItem; | ||
} | ||
else { | ||
dllItem.prev = node; | ||
dllItem.next = node.next; | ||
node.next = dllItem; | ||
// if the node was a tail node | ||
// then reset the tail node | ||
if (node === this.state.tail) { | ||
this.state.tail = dllItem; | ||
} | ||
} | ||
this.state.length++; | ||
return this.dllItemAccessRestrictor.revokeAccess(dllItem); | ||
} | ||
@@ -146,29 +206,61 @@ /** | ||
*/ | ||
remove(dllItem) { | ||
if (!(dllItem instanceof DLLItem)) | ||
remove(accessRestrictedDllItem) { | ||
let dllItem; | ||
if (accessRestrictedDllItem instanceof AccessRestrictedDLLItem) { | ||
dllItem = this.dllItemAccessRestrictor.grantAccess(accessRestrictedDllItem); | ||
} | ||
else if (accessRestrictedDllItem instanceof DLLItem) { | ||
dllItem = accessRestrictedDllItem; | ||
} | ||
else { | ||
return false; | ||
const prev = dllItem.getPrev(); | ||
const next = dllItem.getNext(); | ||
// If it's NOT HEAD | ||
if (prev instanceof DLLItem) { | ||
prev.setNext(next); | ||
// If it's HEAD | ||
} | ||
// Isolate the node from the chain | ||
if (dllItem.prev) { | ||
dllItem.prev.next = dllItem.next; | ||
} | ||
else { | ||
this.head = next; | ||
// If it's HEAD node | ||
this.state.head = dllItem.next; | ||
} | ||
// If it's NOT TAIL | ||
if (next instanceof DLLItem) { | ||
next.setPrev(prev); | ||
// If it's TAIL | ||
if (dllItem.next) { | ||
dllItem.next.prev = dllItem.prev; | ||
} | ||
else { | ||
this.tail = prev; | ||
// if it's also a TAIL node | ||
this.state.tail = dllItem.prev; | ||
} | ||
this.length--; | ||
this.state.length--; | ||
return true; | ||
} | ||
/** | ||
* Clears the DLL chain | ||
*/ | ||
clear() { | ||
// unlink all the items in the DLL chain | ||
// such it will be garbage collected | ||
// as no reference between them is found | ||
this.iterate((dllItem) => { | ||
dllItem.prev = dllItem.next = null; | ||
}); | ||
this.state = this.getFreshState(); | ||
} | ||
getFreshState() { | ||
return { | ||
length: 0, | ||
head: null, | ||
tail: null, | ||
}; | ||
} | ||
iterate(cb) { | ||
let dllItem = this.state.head; | ||
let i = 0; | ||
while (dllItem) { | ||
cb(dllItem, i++); | ||
dllItem = dllItem.next; | ||
} | ||
} | ||
} | ||
exports.DLL = DLL; | ||
exports.DLLItem = DLLItem; | ||
exports.DLLItem = AccessRestrictedDLLItem; |
{ | ||
"name": "@akashbabu/node-dll", | ||
"version": "1.1.0", | ||
"version": "2.0.0", | ||
"description": "DLL(doubly linked list) library for javascript projects", | ||
@@ -9,3 +9,3 @@ "sideEffects": false, | ||
"module": "es/dll.js", | ||
"typings": "types/src/index.d.ts", | ||
"typings": "types/index.d.ts", | ||
"scripts": { | ||
@@ -18,6 +18,8 @@ "_test": "cross-env TS_NODE_FILES=true mocha --require ts-node/register test/**/*.spec.ts", | ||
"coverage": "nyc npm run test", | ||
"build": "rollup -c", | ||
"lint:fix": "tslint --fix --config tslint.json src/index.ts", | ||
"lint": "tslint --config tslint.json src/index.ts", | ||
"tsc:build": "tsc", | ||
"rollup:build": "rollup -c", | ||
"build": "npm run tsc:build && npm run rollup:build", | ||
"pack": "npm run build && npm pack", | ||
"status": "git status", | ||
@@ -48,3 +50,2 @@ "coveralls": "npm run coverage && nyc report --reporter=text-lcov | coveralls" | ||
"coverage", | ||
"tsc:build", | ||
"build", | ||
@@ -80,3 +81,3 @@ "status" | ||
"nodemon": "^2.0.1", | ||
"nyc": "^14.1.1", | ||
"nyc": "^15.0.0-beta.0", | ||
"pre-commit": "^1.2.2", | ||
@@ -83,0 +84,0 @@ "radargun": "^1.0.1", |
@@ -10,5 +10,6 @@ # node-dll [![Coverage Status](https://coveralls.io/repos/github/AkashBabu/node-dll/badge.svg?branch=master)](https://coveralls.io/github/AkashBabu/node-dll?branch=master) [![Build Status](https://travis-ci.com/AkashBabu/node-dll.svg?branch=master)](https://travis-ci.com/AkashBabu/node-dll) [![Maintainability](https://api.codeclimate.com/v1/badges/c7054adbf0195cce8778/maintainability)](https://codeclimate.com/github/AkashBabu/node-dll/maintainability) | ||
Every aspect was desgined and thought carefully to minimize introducing new bugs. | ||
## Documentation | ||
API method name has been carefully chosen to nearly match Array methods, such that learning curve is least and adaptability is higher. But a few methods could not have had a different name and we'd to convince ourselves with those method name. | ||
API method name has been carefully chosen to nearly match Array methods, such that learning curve is least and adaptability is higher. But a few methods couldn't have had a different name and we had to convince ourselves with those method name. | ||
@@ -30,3 +31,3 @@ ### API - DLL | ||
#### .getHead() | ||
#### .head | ||
Returns the first item in the list | ||
@@ -40,6 +41,6 @@ | ||
dll.getHead() // => DLLItem<'test'> | ||
dll.head // => DLLItem<'test'> | ||
``` | ||
#### .getTail() | ||
#### .tail | ||
Returns the last item in the list | ||
@@ -54,3 +55,3 @@ | ||
dll.getTail() // => DLLItem<'test2'> | ||
dll.tail // => DLLItem<'test2'> | ||
``` | ||
@@ -76,3 +77,3 @@ | ||
#### .unshift() | ||
Add the given item to the head of DLL chain | ||
Adds the given item to the head of DLL chain | ||
@@ -127,3 +128,3 @@ Example: | ||
#### .push(data) | ||
Adds the given items to the tail of DLL chain and returns the added item, such that the same can be used to remove the item from the list | ||
Adds the given item to the tail of DLL chain and returns the added item, such that the same can be used to remove the item from the list | ||
@@ -145,2 +146,19 @@ Example: | ||
#### .appendAfter(dllItem, data) | ||
Adds the given item next to the given dllItem in DLL chain and returns the added item, such that the same can be used to remove the item from the list | ||
Example: | ||
```JS | ||
const dll = new DLL() | ||
const item1 = dll.push('test1') | ||
dll.push('test3') | ||
const item2 = dll.appendAfter(item1, 'test2') | ||
item2.data // => 'test2' | ||
dll // => test1 <-> test2 <-> test3 | ||
``` | ||
#### .remove(dllItem) | ||
@@ -164,2 +182,69 @@ Removes the given item from DLL chain and returns true if the removal was successful | ||
#### .clear() | ||
Removes all the items in the DLL chain | ||
Example: | ||
```JS | ||
const dll = new DLL() | ||
dll.push('test1') | ||
dll.push('test2') | ||
dll.length // => 2 | ||
dll.clear() | ||
dll.length // => 0 | ||
``` | ||
### API - DLLItem | ||
DLLItem has a readonly access to `prev` and `next` properties, this is to ensure that the user doesn't change them by mistake, which can introduce bugs and be very hard to debug. | ||
#### .data | ||
Set / get data value on the DLLItem via this property | ||
Example: | ||
```TS | ||
const dll = new DLL<string>() | ||
const dllItem = dll.push('test') | ||
dllItem.data // => 'test' | ||
dllItem.data = 'fake' | ||
const head = dll.head | ||
head.data // => 'test' | ||
``` | ||
#### .prev | ||
Get prev value on the DLLItem via this property | ||
Example: | ||
```TS | ||
const dll = new DLL<string>() | ||
dll.push('test1') | ||
const dllItem = dll.push('test2') | ||
dllItem.data // => 'test2' | ||
dllItem.prev.data // => 'test1' | ||
``` | ||
#### .next | ||
Get next value on the DLLItem via this property | ||
Example: | ||
```TS | ||
const dll = new DLL<string>() | ||
const dllItem = dll.push('test1') | ||
dll.push('test2') | ||
dllItem.data // => 'test1' | ||
dllItem.next.data // => 'test2' | ||
``` | ||
## Contribution | ||
@@ -166,0 +251,0 @@ |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
40298
933
256
1