Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- function LinkedList() {
- "use strict";
- this.meta = {
- current: {
- address: undefined,
- position: -1,
- },
- list: {
- length: 0,
- nodesCreated: 0, // debug
- nodesDeleted: 0, // debug
- first: undefined,
- get last() { return this.first?.pointers.previousNode; },
- },
- };
- this.add = addNodeFn(this);
- this.addNodes = addMultipleNodesFn(this);
- this.append = appendNodeFn(this);
- this.appendNodes = appendMultipleNodesFn(this);
- this.prepend = prependNodeFn(this);
- this.prependNodes = prependMultipleNodesFn(this);
- this.delete = deleteNodeFn(this);
- this.deleteNodes = deleteMultipleNodesFn(this);
- this.trimStart = trimStartMultipleNodesFn(this);
- this.trimEnd = trimEndMultipleNodesFn(this);
- this.node = getNodeFn(this);
- this.previous = previousNodeFn(this);
- this.next = nextNodeFn(this);
- this.jump = jumpMultipleNodesFn(this);
- this.at = atNodeFn(this);
- this.setFirst = setFirstNodeFn(this);
- Object.defineProperty(this, 'data',
- { get: function() { return this.meta.current.address?.content.data; },
- set: function(data) {
- if (this.meta.current.address) this.meta.current.address.content.data = data; } });
- Object.defineProperty(this, 'info', { get: function() {
- console.log(`Length: ${ this.meta.list.length }\nCreated Nodes: ${ this.meta.list.nodesCreated }\nDeleted Nodes: ` +
- `${ this.meta.list.nodesDeleted }\nCurrent Position: ${ this.meta.current.position }`); return; } });
- function addNodeFn(anchor) {
- const current = anchor.meta.current;
- const list = anchor.meta.list;
- let previousNode;
- let nextNode;
- return function (data) {
- const currentNode = {
- pointers: {},
- content: { data },
- get data() { return this.content.data; },
- set data(data) { this.content.data = data; },
- get 'list-position'() { return current.position; },
- get 'list-position(debug)'() { return getLocationNode(anchor, currentNode)(); }, //debug
- };
- if (list.length) {
- previousNode = current.address;
- nextNode = current.address.pointers.nextNode;
- } else {
- previousNode = nextNode = list.first = currentNode;
- }
- currentNode.pointers.previousNode = previousNode;
- currentNode.pointers.nextNode = nextNode;
- nextNode.pointers.previousNode = currentNode;
- previousNode.pointers.nextNode = currentNode;
- copyMethodsFn(currentNode, anchor);
- list.nodesCreated++; // debug
- list.length++;
- current.position++;
- return (current.address = currentNode);
- };
- }
- function appendNodeFn(anchor) {
- const current = anchor.meta.current;
- const list = anchor.meta.list;
- return function (data) {
- current.address = list.last;
- current.position = list.length - 1;
- return addNodeFn(anchor)(data);
- };
- }
- function prependNodeFn(anchor) {
- const current = anchor.meta.current;
- const list = anchor.meta.list;
- return function (data) {
- current.address = list.last;
- current.position = -1;
- return (list.first = addNodeFn(anchor)(data));
- };
- }
- function addMultipleNodesFn(anchor) {
- const current = anchor.meta.current;
- return function (...args) {
- switch (parseArgumentsFn(...args)) {
- case 'empty':
- args[0] = 1;
- case 'number':
- while (args[0]--) { addNodeFn(anchor)(); }
- break;
- case 'array':
- args.reverse();
- while (args.length) { addNodeFn(anchor)(args.pop()); }
- }
- return current.address;
- };
- }
- function appendMultipleNodesFn(anchor) {
- const current = anchor.meta.current;
- const list = anchor.meta.list;
- return function (...args) {
- current.address = list.last;
- current.position = list.length - 1;
- return addMultipleNodesFn(anchor)(...args);
- };
- }
- function prependMultipleNodesFn(anchor) {
- const current = anchor.meta.current;
- const list = anchor.meta.list;
- const pinpoint = saveCurrentStateFn(anchor);
- return function (...args) {
- pinpoint(true);
- current.address = list.last;
- current.position = -1;
- addMultipleNodesFn(anchor)(...args);
- list.first = pinpoint('after-last');
- return current.address;
- };
- }
- function parseArgumentsFn(...args) {
- switch (args.length) {
- case 0:
- return 'empty';
- case 1:
- if (isNaturalNumber(args[0])) { return 'number'; }
- default:
- return 'array';
- }
- }
- function deleteNodeFn(anchor) {
- const list = anchor.meta.list;
- return function () {
- if (!list.length) { return undefined; }
- return removeNodeFn(anchor, false);
- };
- }
- function deleteMultipleNodesFn(anchor) {
- const current = anchor.meta.current;
- const list = anchor.meta.list;
- return function (amount) {
- if (list.length && isNaturalNumber(amount)) {
- removeMultipleNodesFn(anchor, amount, true);
- return current.address;
- }
- return undefined;
- };
- }
- function trimStartMultipleNodesFn(anchor) {
- const current = anchor.meta.current;
- const list = anchor.meta.list;
- return function (amount) {
- if (!arguments.length) amount = 1;
- if (list.length && isNaturalNumber(amount)) {
- current.address = list.first;
- current.position = 0;
- removeMultipleNodesFn(anchor, amount, true);
- return current.address;
- }
- return undefined;
- };
- }
- function trimEndMultipleNodesFn(anchor) {
- const current = anchor.meta.current;
- const list = anchor.meta.list;
- return function (amount) {
- if (!arguments.length) amount = 1;
- if (list.length && isNaturalNumber(amount)) {
- current.address = list.last;
- current.position = list.length - 1;
- removeMultipleNodesFn(anchor, amount, false);
- return current.address;
- }
- return undefined;
- };
- }
- function removeNodeFn(anchor, passThrough) {
- const current = anchor.meta.current;
- const list = anchor.meta.list;
- let disconectedNode = disconectNodeFn(current.address);
- [current.address, current.position, list.first] =
- getNewStateFn(current.address, current.position, list.first, passThrough);
- deleteAllNodeProperties(disconectedNode);
- list.length--;
- list.nodesDeleted++; // debug
- return current.address;
- }
- function removeMultipleNodesFn(anchor, amount, passThrough) {
- const current = anchor.meta.current;
- const list = anchor.meta.list;
- amount = amount > list.length ? list.length : amount;
- while (amount--) removeNodeFn(anchor, passThrough);
- return current.address;
- }
- function disconectNodeFn(node) {
- const previousNode = node.pointers.previousNode;
- const nextNode = node.pointers.nextNode;
- previousNode.pointers.nextNode = nextNode;
- nextNode.pointers.previousNode = previousNode;
- return node;
- }
- function getNewStateFn(address, position, first, passThrough = false) {
- switch (true) {
- case (address === first && address.pointers.previousNode === first):
- address = first = undefined;
- position = -1 ;
- break;
- case (address === first):
- address = first = first.pointers.nextNode;
- break;
- case (address.pointers.nextNode === first):
- switch (passThrough) {
- case (true):
- position = 0;
- address = address.pointers.nextNode;
- break;
- case (false):
- position--;
- address = address.pointers.previousNode;
- break;
- }
- break;
- default:
- address = address.pointers.nextNode;
- }
- return [address, position, first];
- }
- function deleteAllNodeProperties(node) {
- let result = true;
- result = (delete node['list-position']) && result;
- result = (delete node['list-position(debug)']) && result;
- result = (delete node.content.data) && result;
- result = (delete node.content) && result;
- result = (delete node.data) && result;
- result = (delete node.pointers.previousNode) && result;
- result = (delete node.pointers.nextNode) && result;
- result = (delete node.pointers) && result;
- result = (delete node.add) && result;
- result = (delete node.addNodes) && result;
- result = (delete node.append) && result;
- result = (delete node.appendNodes) && result;
- result = (delete node.prepend) && result;
- result = (delete node.prependNodes) && result;
- result = (delete node.delete) && result;
- result = (delete node.deleteNodes) && result;
- result = (delete node.trimStart) && result;
- result = (delete node.trimEnd) && result;
- result = (delete node.node) && result;
- result = (delete node.previous) && result;
- result = (delete node.next) && result;
- result = (delete node.jump) && result;
- result = (delete node.at) && result;
- result = (delete node.setFirst) && result;
- return result;
- }
- function setFirstNodeFn(anchor) {
- const current = anchor.meta.current;
- const list = anchor.meta.list;
- return function (node) {
- let condition = Boolean(node) && typeof node === 'object' && 'pointers' in node;
- return arguments.length && !condition ?
- undefined : (list.first = condition ? (current.address = node) : current.address);
- };
- }
- function getNodeFn(anchor) {
- const current = anchor.meta.current;
- return function () {
- return current.address;
- };
- }
- function nextNodeFn(anchor) {
- const current = anchor.meta.current;
- const list = anchor.meta.list;
- return function () {
- if (!list.length) {
- return undefined;
- }
- current.position = (current.position + 1) % list.length;
- return (current.address = current.address.pointers.nextNode);
- };
- }
- function previousNodeFn(anchor) {
- const current = anchor.meta.current;
- const list = anchor.meta.list;
- return function () {
- if (!list.length) {
- return undefined;
- }
- current.position = (current.position || list.length) - 1;
- return (current.address = current.address.pointers.previousNode);
- };
- }
- function jumpMultipleNodesFn(anchor) {
- const list = anchor.meta.list;
- return function (jumps) {
- const condition = Boolean(list.length) && Number.isFinite(jumps);
- return condition ? loopThroughMultipleNodesFn(anchor, jumps) : undefined;
- };
- }
- function atNodeFn(anchor) {
- const list = anchor.meta.list;
- return function (destination) {
- const condition = Boolean(list.length) &&
- Number.isFinite(destination) &&
- (destination < 0 ? ~destination : destination) < list.length;
- if (condition) {
- let jumps = getJumpsToDestinationFn(anchor, destination);
- return loopThroughMultipleNodesFn(anchor, jumps);
- }
- return undefined;
- };
- }
- function getJumpsToDestinationFn(anchor, destination) {
- const current = anchor.meta.current;
- const list = anchor.meta.list;
- let jumps = destination >= 0 ? destination - current.position :
- list.length + destination - current.position;
- return jumps;
- }
- function getDestinationFromJumpsFn(anchor, jumps) {
- const current = anchor.meta.current;
- const list = anchor.meta.list;
- let destination = jumps >= 0 ? (current.position + jumps) % list.length :
- list.length - 1 - (list.length - 1 - current.position - jumps) % list.length;
- return destination;
- }
- function getShortPathFn(anchor, jumps) {
- const current = anchor.meta.current;
- const list = anchor.meta.list;
- const destination = getDestinationFromJumpsFn(anchor, jumps);
- const jumpsFromStart = destination;
- const jumpsFromEnd = destination - (list.length - 1);
- const JumpsFromPosition = destination - current.position;
- const fromStart = jumpsFromStart <= Math.abs(jumpsFromEnd)
- && jumpsFromStart <= Math.abs(JumpsFromPosition);
- const fromEnd = Math.abs(jumpsFromEnd) <= jumpsFromStart
- && Math.abs(jumpsFromEnd) <= Math.abs(JumpsFromPosition);
- let address;
- switch (true) {
- case fromStart:
- address = list.first;
- jumps = jumpsFromStart;
- break;
- case fromEnd:
- address = list.last;
- jumps = jumpsFromEnd;
- break;
- default:
- address = current.address;
- jumps = JumpsFromPosition;
- break;
- }
- console.log( `Starting from ${
- fromStart ? `begin: 0` :
- fromEnd ? `end: ${list.length - 1}` :
- `current position: ${ current.position }` }` +
- `\nJumps: ${ jumps }\nDestination: ${ destination }` ); // debug
- return [address, jumps, destination];
- }
- function loopThroughMultipleNodesFn(anchor, jumps, shortcut = true) {
- const current = anchor.meta.current;
- let destination;
- if (shortcut) {
- [current.address, jumps, destination] = getShortPathFn(anchor, jumps);
- } else {
- destination = getDestinationFromJumpsFn(anchor, jumps);
- }
- switch (true) {
- case (jumps > 0):
- while (jumps--) current.address = current.address.pointers.nextNode;
- break;
- case (jumps < 0):
- while (jumps++) current.address = current.address.pointers.previousNode;
- break;
- }
- current.position = destination;
- return current.address;
- }
- function copyMethodsFn(toObject, fromObject) {
- toObject.add = fromObject.add;
- toObject.addNodes = fromObject.addNodes;
- toObject.append = fromObject.append;
- toObject.appendNodes = fromObject.appendNodes;
- toObject.prepend = fromObject.prepend;
- toObject.prependNodes = fromObject.prependNodes;
- toObject.delete = fromObject.delete;
- toObject.deleteNodes = fromObject.deleteNodes;
- toObject.trimStart = fromObject.trimStart;
- toObject.trimEnd = fromObject.trimEnd;
- toObject.node = fromObject.node
- toObject.previous = fromObject.previous;
- toObject.next = fromObject.next;
- toObject.jump = fromObject.jump;
- toObject.at = fromObject.at;
- toObject.setFirst = fromObject.setFirst;
- return undefined;
- }
- function isNaturalNumber(number) {
- return (Number.isInteger(number) && number > 0);
- }
- function saveCurrentStateFn(anchor) {
- const replica = {
- current: {},
- list: {},
- };
- return function (condition = false) {
- switch (condition) {
- case 'current':
- return replica.current;
- case 'list':
- return replica.list;
- case 'after-last':
- return replica.list.last?.pointers.nextNode || anchor.meta.list.first;
- case (true):
- replica.current.address = anchor.meta.current.address;
- replica.current.position = anchor.meta.current.position;
- replica.list.length = anchor.meta.list.length;
- replica.list.first = anchor.meta.list.first;
- replica.list.last = anchor.meta.list.last;
- case (false):
- return replica;
- }
- return undefined;
- };
- }
- /* Functions for debug */
- function getLocationNode(anchor, currentNode) {
- const list = anchor.meta.list;
- return function () {
- let counter;
- for (counter = 0; currentNode !== list.first; counter++) {
- currentNode = currentNode.pointers.previousNode;
- }
- return counter;
- };
- }
- }
- /* const obj = new LinkedList(); */
Add Comment
Please, Sign In to add comment