| 
									
										
										
										
											2020-10-04 04:40:16 +03:00
										 |  |  | /********************************************************************** | 
					
						
							|  |  |  | *  | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * | 
					
						
							| 
									
										
										
										
											2020-10-09 03:24:25 +03:00
										 |  |  | ***********************************************/ /* c8 ignore next 2 */ | 
					
						
							| 
									
										
										
										
											2020-10-04 04:40:16 +03:00
										 |  |  | ((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define) | 
					
						
							|  |  |  | (function(require){ var module={} // make module AMD/node compatible...
 | 
					
						
							|  |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-07 16:46:59 +03:00
										 |  |  | require('./Map') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-04 04:40:16 +03:00
										 |  |  | var object = require('ig-object') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var UniqueKeyMap =  | 
					
						
							| 
									
										
										
										
											2020-12-22 05:17:39 +03:00
										 |  |  | module.UniqueKeyMap =  | 
					
						
							|  |  |  | object.Constructor('UniqueKeyMap', Map, { | 
					
						
							| 
									
										
										
										
											2020-10-04 04:40:16 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Format:
 | 
					
						
							|  |  |  | 	// 	Map([
 | 
					
						
							|  |  |  | 	// 		[ <elem>, Set([
 | 
					
						
							|  |  |  | 	// 				<original-name>, 
 | 
					
						
							|  |  |  | 	// 				...
 | 
					
						
							|  |  |  | 	// 			]) ],
 | 
					
						
							|  |  |  | 	// 		...
 | 
					
						
							|  |  |  | 	// 	])
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2020-10-07 07:33:58 +03:00
										 |  |  | 	__keys_index: null, | 
					
						
							| 
									
										
										
										
											2020-10-04 17:05:57 +03:00
										 |  |  | 	get __keys(){ | 
					
						
							|  |  |  | 		return (this.__keys_index =  | 
					
						
							|  |  |  | 			this.__keys_index || new Map()) }, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-07 07:33:58 +03:00
										 |  |  | 	// Format:
 | 
					
						
							|  |  |  | 	// 	Map([
 | 
					
						
							|  |  |  | 	// 		[<unique-key>, <orig-key>],
 | 
					
						
							|  |  |  | 	// 		...
 | 
					
						
							|  |  |  | 	// 	])
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	__reverse_index: null, | 
					
						
							|  |  |  | 	get __reverse(){ | 
					
						
							|  |  |  | 		return (this.__reverse_index =  | 
					
						
							|  |  |  | 			this.__reverse_index || new Map()) }, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-04 04:40:16 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-09 03:24:25 +03:00
										 |  |  | 	// Pattern to be used to generate unique key...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2020-10-04 04:40:16 +03:00
										 |  |  | 	__key_pattern__: '$KEY ($COUNT)', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// If true then a value can not be stored under the same key more 
 | 
					
						
							|  |  |  | 	// than once...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// Example:
 | 
					
						
							|  |  |  | 	// 	var u = UniqueKeyMap()
 | 
					
						
							|  |  |  | 	// 	u.set('x', 123)
 | 
					
						
							|  |  |  | 	// 	// if .__unique_key_value__ is true this will have no effect, 
 | 
					
						
							|  |  |  | 	// 	// otherwise 123 will be stored under 'x (1)'
 | 
					
						
							|  |  |  | 	// 	u.set('x', 123)
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	__unique_key_value__: false, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-07 14:48:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-04 04:40:16 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-07 07:33:58 +03:00
										 |  |  | 	// helpers...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	originalKey: function(key){ | 
					
						
							|  |  |  | 		return this.__reverse.get(key) }, | 
					
						
							|  |  |  | 	uniqieKey: function(key){ | 
					
						
							|  |  |  | 		var n = key | 
					
						
							|  |  |  | 		var i = 0 | 
					
						
							|  |  |  | 		while(this.has(n)){ | 
					
						
							|  |  |  | 			i++ | 
					
						
							|  |  |  | 			n = this.__key_pattern__ | 
					
						
							|  |  |  | 				.replace(/\$KEY/, key) | 
					
						
							|  |  |  | 				.replace(/\$COUNT/, i) } | 
					
						
							|  |  |  | 		return n }, | 
					
						
							|  |  |  | 	keysOf: function(elem, mode='original'){ | 
					
						
							|  |  |  | 		// get unique keys...
 | 
					
						
							|  |  |  | 		if(mode == 'unique'){ | 
					
						
							|  |  |  | 			return this | 
					
						
							|  |  |  | 				.entries() | 
					
						
							|  |  |  | 				.reduce(function(res, [k, e]){ | 
					
						
							|  |  |  | 					e === elem | 
					
						
							|  |  |  | 						&& res.push(k) | 
					
						
							|  |  |  | 					return res }, []) } | 
					
						
							|  |  |  | 		// get keys used to set the values...
 | 
					
						
							|  |  |  | 		return [...(this.__keys.get(elem) || [])] }, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-05 14:58:22 +03:00
										 |  |  | 	// NOTE: this will never overwrite a key's value, to overwrite use .reset(..)
 | 
					
						
							| 
									
										
										
										
											2020-10-05 14:35:44 +03:00
										 |  |  | 	set: function(key, elem, return_key=false){ | 
					
						
							| 
									
										
										
										
											2020-10-07 07:33:58 +03:00
										 |  |  | 		// index...
 | 
					
						
							| 
									
										
										
										
											2020-10-04 04:40:16 +03:00
										 |  |  | 		var names | 
					
						
							|  |  |  | 		this.__keys.set(elem,  | 
					
						
							|  |  |  | 			names = this.__keys.get(elem) || new Set()) | 
					
						
							|  |  |  | 		// key/elem already exists...
 | 
					
						
							| 
									
										
										
										
											2020-10-04 17:05:57 +03:00
										 |  |  | 		if(this.__unique_key_value__  | 
					
						
							|  |  |  | 				&& names.has(key)){ | 
					
						
							| 
									
										
										
										
											2020-10-05 14:35:44 +03:00
										 |  |  | 			return return_key ? | 
					
						
							|  |  |  | 				key | 
					
						
							|  |  |  | 				: this } | 
					
						
							| 
									
										
										
										
											2020-10-04 04:40:16 +03:00
										 |  |  | 		names.add(key) | 
					
						
							|  |  |  | 		// add the elem with the unique name...
 | 
					
						
							| 
									
										
										
										
											2020-10-07 07:33:58 +03:00
										 |  |  | 		var n | 
					
						
							| 
									
										
										
										
											2020-10-05 14:35:44 +03:00
										 |  |  | 		var res = object.parentCall( | 
					
						
							|  |  |  | 			UniqueKeyMap.prototype,  | 
					
						
							|  |  |  | 			'set',  | 
					
						
							|  |  |  | 			this,  | 
					
						
							|  |  |  | 			n = this.uniqieKey(key),  | 
					
						
							|  |  |  | 			elem)  | 
					
						
							| 
									
										
										
										
											2020-10-07 07:33:58 +03:00
										 |  |  | 		// reverse index...
 | 
					
						
							|  |  |  | 		this.__reverse.set(n, key) | 
					
						
							| 
									
										
										
										
											2020-10-05 14:35:44 +03:00
										 |  |  | 		return return_key ? | 
					
						
							|  |  |  | 			n | 
					
						
							|  |  |  | 			: res }, | 
					
						
							| 
									
										
										
										
											2020-10-07 07:44:45 +03:00
										 |  |  | 	// NOTE: this will never generate a new name...
 | 
					
						
							|  |  |  | 	reset: function(key, elem){ | 
					
						
							| 
									
										
										
										
											2020-10-07 07:33:58 +03:00
										 |  |  | 		// rewrite...
 | 
					
						
							|  |  |  | 		if(this.has(key)){ | 
					
						
							|  |  |  | 			// remove old elem/key from .__keys...
 | 
					
						
							|  |  |  | 			var o = this.originalKey(key) | 
					
						
							|  |  |  | 			var s = this.__keys.get(this.get(key)) | 
					
						
							|  |  |  | 			s.delete(o) | 
					
						
							|  |  |  | 			s.size == 0 | 
					
						
							|  |  |  | 				&& this.__keys.delete(this.get(key)) | 
					
						
							|  |  |  | 			// add new elem/key to .__keys...
 | 
					
						
							|  |  |  | 			var n | 
					
						
							|  |  |  | 			this.__keys.set(elem, (n = this.__keys.get(elem) || new Set())) | 
					
						
							|  |  |  | 			n.add(o) | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 			return object.parentCall(UniqueKeyMap.prototype, 'set', this, key, elem)  | 
					
						
							|  |  |  | 		// add...
 | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2020-10-07 07:44:45 +03:00
										 |  |  | 			return this.set(key, elem) } }, | 
					
						
							| 
									
										
										
										
											2020-10-04 04:40:16 +03:00
										 |  |  | 	delete: function(key){ | 
					
						
							|  |  |  | 		var s = this.__keys.get(this.get(key)) | 
					
						
							|  |  |  | 		if(s){ | 
					
						
							| 
									
										
										
										
											2020-10-07 07:33:58 +03:00
										 |  |  | 			// XXX will this delete if key is with an index???
 | 
					
						
							|  |  |  | 			//s.delete(key)
 | 
					
						
							|  |  |  | 			s.delete(this.originalKey(key)) | 
					
						
							|  |  |  | 			this.__reverse.delete(key) | 
					
						
							| 
									
										
										
										
											2020-10-04 04:40:16 +03:00
										 |  |  | 			s.size == 0 | 
					
						
							| 
									
										
										
										
											2020-10-07 07:33:58 +03:00
										 |  |  | 				&& this.__keys.delete(this.get(key)) } | 
					
						
							| 
									
										
										
										
											2020-10-04 04:40:16 +03:00
										 |  |  | 		return object.parentCall(UniqueKeyMap.prototype, 'delete', this, key) }, | 
					
						
							| 
									
										
										
										
											2020-10-07 15:09:36 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-07 14:48:47 +03:00
										 |  |  | 	// NOTE: this maintains the item order. This is done by rewriting 
 | 
					
						
							|  |  |  | 	// 		items in sequence, this may be slow and trigger lots of write 
 | 
					
						
							|  |  |  | 	// 		observer callbacks. to avoid this use .unOrderedRename(..)
 | 
					
						
							|  |  |  | 	// XXX do not see how can we avoid rewriting the map if we want to 
 | 
					
						
							| 
									
										
										
										
											2020-10-09 03:24:25 +03:00
										 |  |  | 	// 		keep the order...
 | 
					
						
							| 
									
										
										
										
											2020-10-07 15:09:36 +03:00
										 |  |  | 	orderedRename: function(from, to, return_key=false){ | 
					
						
							| 
									
										
										
										
											2020-10-07 07:33:58 +03:00
										 |  |  | 		var keys = [...this.keys()] | 
					
						
							| 
									
										
										
										
											2020-10-07 07:44:45 +03:00
										 |  |  | 		// rename the element...
 | 
					
						
							| 
									
										
										
										
											2020-10-07 07:33:58 +03:00
										 |  |  | 		var e = this.get(from) | 
					
						
							|  |  |  | 		this.delete(from) | 
					
						
							|  |  |  | 		var n = this.set(to, e, true)  | 
					
						
							|  |  |  | 		// keep order...
 | 
					
						
							|  |  |  | 		keys.splice(keys.indexOf(from), 1, n) | 
					
						
							| 
									
										
										
										
											2020-10-07 16:46:59 +03:00
										 |  |  | 		this.sort(keys) | 
					
						
							| 
									
										
										
										
											2020-10-07 07:33:58 +03:00
										 |  |  | 		return return_key ? | 
					
						
							|  |  |  |    			n | 
					
						
							|  |  |  | 			: this }, | 
					
						
							| 
									
										
										
										
											2020-10-07 15:09:36 +03:00
										 |  |  | 	// NOTE: the renamed item is appended to the map...
 | 
					
						
							| 
									
										
										
										
											2020-10-07 14:48:47 +03:00
										 |  |  | 	unorderedRename: function(from, to, return_key=false){ | 
					
						
							|  |  |  | 		var e = this.get(from) | 
					
						
							|  |  |  | 		this.delete(from) | 
					
						
							|  |  |  | 		return this.set(to, e, return_key) }, | 
					
						
							| 
									
										
										
										
											2020-10-07 15:09:36 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	__unorderd_rename__: false, | 
					
						
							|  |  |  | 	rename: function(from, to, return_key=false){ | 
					
						
							|  |  |  | 		return this.__unorderd_writes__ ? | 
					
						
							|  |  |  | 			this.unorderedRename(...arguments) | 
					
						
							|  |  |  | 			: this.orderedRename(...arguments) }, | 
					
						
							| 
									
										
										
										
											2020-10-04 04:40:16 +03:00
										 |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-26 07:27:23 +03:00
										 |  |  | //---------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // XXX should this be a map???
 | 
					
						
							|  |  |  | // XXX make two variants: ordered and unordered...
 | 
					
						
							| 
									
										
										
										
											2021-01-03 15:57:37 +03:00
										 |  |  | // 		...the ordered variant should have the same API as an array...
 | 
					
						
							| 
									
										
										
										
											2020-12-26 07:27:23 +03:00
										 |  |  | var ObjectWithAutoKeys =  | 
					
						
							|  |  |  | module.ObjectWithAutoKeys =  | 
					
						
							|  |  |  | object.Constructor('ObjectWithAutoKeys', { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	__last_key: null, | 
					
						
							|  |  |  | 	__new_key__: function(value){ | 
					
						
							|  |  |  | 		return (this.__last_key = (this.__last_key || -1) + 1) }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 
 | 
					
						
							|  |  |  | 	// 	.push(value)
 | 
					
						
							|  |  |  | 	// 		-> key
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	.push(value, ..)
 | 
					
						
							|  |  |  | 	// 		-> [key, ..]
 | 
					
						
							| 
									
										
										
										
											2021-01-03 15:57:37 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2020-12-26 07:27:23 +03:00
										 |  |  | 	push: function(...values){ | 
					
						
							|  |  |  | 		var that = this | 
					
						
							|  |  |  | 		var res = values | 
					
						
							|  |  |  | 			.map(function(value){ | 
					
						
							|  |  |  | 				that[that.__new_key__(value)] = value }) | 
					
						
							|  |  |  | 		return values.length == 1 ? | 
					
						
							|  |  |  |    			res.pop() | 
					
						
							|  |  |  | 			: res }, | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-04 04:40:16 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-22 05:17:39 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-04 04:40:16 +03:00
										 |  |  | /********************************************************************** | 
					
						
							|  |  |  | * vim:set ts=4 sw=4 :                               */ return module }) |