You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					160 lines
				
				2.7 KiB
			
		
		
			
		
	
	
					160 lines
				
				2.7 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								'use strict';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class LRU {
							 | 
						||
| 
								 | 
							
										constructor (max = 0, ttl = 0) {
							 | 
						||
| 
								 | 
							
											this.first = null;
							 | 
						||
| 
								 | 
							
											this.items = Object.create(null);
							 | 
						||
| 
								 | 
							
											this.last = null;
							 | 
						||
| 
								 | 
							
											this.max = max;
							 | 
						||
| 
								 | 
							
											this.size = 0;
							 | 
						||
| 
								 | 
							
											this.ttl = ttl;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										has (key) {
							 | 
						||
| 
								 | 
							
											return key in this.items;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										clear () {
							 | 
						||
| 
								 | 
							
											this.first = null;
							 | 
						||
| 
								 | 
							
											this.items = Object.create(null);
							 | 
						||
| 
								 | 
							
											this.last = null;
							 | 
						||
| 
								 | 
							
											this.size = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											return this;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										delete (key) {
							 | 
						||
| 
								 | 
							
											if (this.has(key)) {
							 | 
						||
| 
								 | 
							
												const item = this.items[key];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												delete this.items[key];
							 | 
						||
| 
								 | 
							
												this.size--;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if (item.prev !== null) {
							 | 
						||
| 
								 | 
							
													item.prev.next = item.next;
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if (item.next !== null) {
							 | 
						||
| 
								 | 
							
													item.next.prev = item.prev;
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if (this.first === item) {
							 | 
						||
| 
								 | 
							
													this.first = item.next;
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if (this.last === item) {
							 | 
						||
| 
								 | 
							
													this.last = item.prev;
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											return this;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										evict (bypass = false) {
							 | 
						||
| 
								 | 
							
											if (bypass || this.size > 0) {
							 | 
						||
| 
								 | 
							
												const item = this.first;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												delete this.items[item.key];
							 | 
						||
| 
								 | 
							
												this.size--;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if (this.size === 0) {
							 | 
						||
| 
								 | 
							
													this.first = null;
							 | 
						||
| 
								 | 
							
													this.last = null;
							 | 
						||
| 
								 | 
							
												} else {
							 | 
						||
| 
								 | 
							
													this.first = item.next;
							 | 
						||
| 
								 | 
							
													this.first.prev = null;
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											return this;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										get (key) {
							 | 
						||
| 
								 | 
							
											let result;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if (this.has(key)) {
							 | 
						||
| 
								 | 
							
												const item = this.items[key];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if (this.ttl > 0 && item.expiry <= new Date().getTime()) {
							 | 
						||
| 
								 | 
							
													this.delete(key);
							 | 
						||
| 
								 | 
							
												} else {
							 | 
						||
| 
								 | 
							
													result = item.value;
							 | 
						||
| 
								 | 
							
													this.set(key, result, true);
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											return result;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										keys () {
							 | 
						||
| 
								 | 
							
											return Object.keys(this.items);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										set (key, value, bypass = false) {
							 | 
						||
| 
								 | 
							
											let item;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if (bypass || this.has(key)) {
							 | 
						||
| 
								 | 
							
												item = this.items[key];
							 | 
						||
| 
								 | 
							
												item.value = value;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if (this.last !== item) {
							 | 
						||
| 
								 | 
							
													const last = this.last,
							 | 
						||
| 
								 | 
							
														next = item.next,
							 | 
						||
| 
								 | 
							
														prev = item.prev;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													if (this.first === item) {
							 | 
						||
| 
								 | 
							
														this.first = item.next;
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													item.next = null;
							 | 
						||
| 
								 | 
							
													item.prev = this.last;
							 | 
						||
| 
								 | 
							
													last.next = item;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													if (prev !== null) {
							 | 
						||
| 
								 | 
							
														prev.next = next;
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													if (next !== null) {
							 | 
						||
| 
								 | 
							
														next.prev = prev;
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											} else {
							 | 
						||
| 
								 | 
							
												if (this.max > 0 && this.size === this.max) {
							 | 
						||
| 
								 | 
							
													this.evict(true);
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												item = this.items[key] = {
							 | 
						||
| 
								 | 
							
													expiry: this.ttl > 0 ? new Date().getTime() + this.ttl : this.ttl,
							 | 
						||
| 
								 | 
							
													key: key,
							 | 
						||
| 
								 | 
							
													prev: this.last,
							 | 
						||
| 
								 | 
							
													next: null,
							 | 
						||
| 
								 | 
							
													value
							 | 
						||
| 
								 | 
							
												};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if (++this.size === 1) {
							 | 
						||
| 
								 | 
							
													this.first = item;
							 | 
						||
| 
								 | 
							
												} else {
							 | 
						||
| 
								 | 
							
													this.last.next = item;
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											this.last = item;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											return this;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									function factory (max = 1000, ttl = 0) {
							 | 
						||
| 
								 | 
							
										if (isNaN(max) || max < 0) {
							 | 
						||
| 
								 | 
							
											throw new TypeError("Invalid max value");
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (isNaN(ttl) || ttl < 0) {
							 | 
						||
| 
								 | 
							
											throw new TypeError("Invalid ttl value");
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return new LRU(max, ttl);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								module.exports = factory;
							 |