added HashList::inject() and HashTable::inject().
improved HashTable::upsert(). added HashList::ensert() and HashTable::ensert(). started porting rbt to RedBlackTree
This commit is contained in:
		| @ -44,7 +44,7 @@ struct HashListHasher | |||||||
| }; | }; | ||||||
|  |  | ||||||
| template<typename T> | template<typename T> | ||||||
| struct HashListComparator | struct HashListEqualer | ||||||
| { | { | ||||||
| 	bool operator() (const T& v1, const T& v2) const | 	bool operator() (const T& v1, const T& v2) const | ||||||
| 	{ | 	{ | ||||||
| @ -76,18 +76,18 @@ struct HashListResizer | |||||||
| /// For a hash value of hc, this->nodes[hc * 2] points to the first node and | /// For a hash value of hc, this->nodes[hc * 2] points to the first node and | ||||||
| /// this->nodes[hc * 2 + 1] ponits to the last node.      | /// this->nodes[hc * 2 + 1] ponits to the last node.      | ||||||
|  |  | ||||||
| template <typename T, typename HASHER = HashListHasher<T>, typename COMPARATOR = HashListComparator<T>, typename RESIZER = HashListResizer > | template <typename T, typename HASHER = HashListHasher<T>, typename EQUALER = HashListEqualer<T>, typename RESIZER = HashListResizer > | ||||||
| class HashList: public Mmged | class HashList: public Mmged | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 	typedef LinkedList<T,COMPARATOR> DatumList; | 	typedef LinkedList<T,EQUALER> DatumList; | ||||||
| 	typedef typename DatumList::Node Node; | 	typedef typename DatumList::Node Node; | ||||||
| 	typedef typename DatumList::Iterator Iterator; | 	typedef typename DatumList::Iterator Iterator; | ||||||
| 	typedef typename DatumList::ConstIterator ConstIterator; | 	typedef typename DatumList::ConstIterator ConstIterator; | ||||||
| 	typedef HashList<T,HASHER,COMPARATOR,RESIZER> SelfType; | 	typedef HashList<T,HASHER,EQUALER,RESIZER> SelfType; | ||||||
|  |  | ||||||
| 	typedef HashListHasher<T> DefaultHasher; | 	typedef HashListHasher<T> DefaultHasher; | ||||||
| 	typedef HashListComparator<T> DefaultComparator; | 	typedef HashListEqualer<T> DefaultEqualer; | ||||||
| 	typedef HashListResizer DefaultResizer; | 	typedef HashListResizer DefaultResizer; | ||||||
|  |  | ||||||
| 	enum | 	enum | ||||||
| @ -304,7 +304,7 @@ protected: | |||||||
| 			do  | 			do  | ||||||
| 			{ | 			{ | ||||||
| 				T& t = np->value; | 				T& t = np->value; | ||||||
| 				if (this->comparator(datum, t)) return np; | 				if (this->equaler(datum, t)) return np; | ||||||
| 				if (np == this->nodes[tail]) break; | 				if (np == this->nodes[tail]) break; | ||||||
| 				np = np->getNextNode (); | 				np = np->getNextNode (); | ||||||
| 			} | 			} | ||||||
| @ -314,10 +314,10 @@ protected: | |||||||
| 		return QSE_NULL; | 		return QSE_NULL; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	template <typename MT, typename MCOMPARATOR> | 	template <typename MT, typename MEQUALER> | ||||||
| 	Node* heterofind_node (const MT& datum, qse_size_t hc) const | 	Node* heterofind_node (const MT& datum, qse_size_t hc) const | ||||||
| 	{ | 	{ | ||||||
| 		MCOMPARATOR is_equal; | 		MEQUALER m_Equaler; | ||||||
|  |  | ||||||
| 		qse_size_t head, tail; | 		qse_size_t head, tail; | ||||||
| 		Node* np; | 		Node* np; | ||||||
| @ -330,7 +330,7 @@ protected: | |||||||
| 			do  | 			do  | ||||||
| 			{ | 			{ | ||||||
| 				T& t = np->value; | 				T& t = np->value; | ||||||
| 				if (is_equal(datum, t)) return np; | 				if (m_Equaler(datum, t)) return np; | ||||||
| 				if (np == this->nodes[tail]) break; | 				if (np == this->nodes[tail]) break; | ||||||
| 				np = np->getNextNode (); | 				np = np->getNextNode (); | ||||||
| 			} | 			} | ||||||
| @ -340,53 +340,6 @@ protected: | |||||||
| 		return QSE_NULL; | 		return QSE_NULL; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	Node* insert_value (const T& datum, bool overwrite = true) |  | ||||||
| 	{ |  | ||||||
| 		qse_size_t hc, head, tail; |  | ||||||
| 		Node* np; |  | ||||||
|  |  | ||||||
| 		hc = this->hasher(datum) % this->node_capacity; |  | ||||||
| 		head = hc << 1; tail = head + 1; |  | ||||||
|  |  | ||||||
| 		np = this->nodes[head]; |  | ||||||
| 		if (np)  |  | ||||||
| 		{ |  | ||||||
| 			do  |  | ||||||
| 			{ |  | ||||||
| 				T& t = np->value; |  | ||||||
| 				if (this->comparator(datum, t))  |  | ||||||
| 				{ |  | ||||||
| 					if (!overwrite) return QSE_NULL; |  | ||||||
| 					t = datum; |  | ||||||
| 					return np; |  | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 				if (np == this->nodes[tail]) break; |  | ||||||
| 				np = np->getNextNode (); |  | ||||||
| 			} |  | ||||||
| 			while (1);  |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if (datum_list->getSize() >= threshold)  |  | ||||||
| 		{ |  | ||||||
| 			this->rehash (); |  | ||||||
| 			hc = this->hasher(datum) % this->node_capacity; |  | ||||||
| 			head = hc << 1; tail = head + 1; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if (nodes[head] == QSE_NULL)  |  | ||||||
| 		{ |  | ||||||
| 			this->nodes[head] = this->datum_list->insert ((Node*)QSE_NULL, datum); |  | ||||||
| 			this->nodes[tail] = this->nodes[head]; |  | ||||||
| 		} |  | ||||||
| 		else  |  | ||||||
| 		{ |  | ||||||
| 			this->nodes[head] = this->datum_list->insert (this->nodes[head], datum); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		return this->nodes[head]; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| public: | public: | ||||||
| 	Node* findNode (const T& datum) | 	Node* findNode (const T& datum) | ||||||
| 	{ | 	{ | ||||||
| @ -412,34 +365,34 @@ public: | |||||||
| 		return &b->value; | 		return &b->value; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	template <typename MT, typename MHASHER, typename MCOMPARATOR> | 	template <typename MT, typename MHASHER, typename MEQUALER> | ||||||
| 	Node* heterofindNode (const MT& datum) | 	Node* heterofindNode (const MT& datum) | ||||||
| 	{ | 	{ | ||||||
| 		MHASHER hash; | 		MHASHER hash; | ||||||
| 		return this->heterofind_node<MT,MCOMPARATOR> (datum, hash(datum) % this->node_capacity); | 		return this->heterofind_node<MT,MEQUALER> (datum, hash(datum) % this->node_capacity); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	template <typename MT, typename MHASHER, typename MCOMPARATOR> | 	template <typename MT, typename MHASHER, typename MEQUALER> | ||||||
| 	const Node* heterofindNode (const MT& datum) const | 	const Node* heterofindNode (const MT& datum) const | ||||||
| 	{ | 	{ | ||||||
| 		MHASHER hash; | 		MHASHER hash; | ||||||
| 		return this->heterofind_node<MT,MCOMPARATOR> (datum, hash(datum) % this->node_capacity); | 		return this->heterofind_node<MT,MEQUALER> (datum, hash(datum) % this->node_capacity); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	template <typename MT, typename MHASHER, typename MCOMPARATOR> | 	template <typename MT, typename MHASHER, typename MEQUALER> | ||||||
| 	T* heterofindValue(const MT& datum) | 	T* heterofindValue(const MT& datum) | ||||||
| 	{ | 	{ | ||||||
| 		MHASHER hash; | 		MHASHER hash; | ||||||
| 		Node* b = this->heterofind_node<MT,MCOMPARATOR> (datum, hash(datum) % this->node_capacity); | 		Node* b = this->heterofind_node<MT,MEQUALER> (datum, hash(datum) % this->node_capacity); | ||||||
| 		if (!b) return QSE_NULL; | 		if (!b) return QSE_NULL; | ||||||
| 		return &b->value; | 		return &b->value; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	template <typename MT, typename MHASHER, typename MCOMPARATOR> | 	template <typename MT, typename MHASHER, typename MEQUALER> | ||||||
| 	const T* heterofindValue(const MT& datum) const | 	const T* heterofindValue(const MT& datum) const | ||||||
| 	{ | 	{ | ||||||
| 		MHASHER hash; | 		MHASHER hash; | ||||||
| 		Node* b = this->heterofind_node<MT,MCOMPARATOR> (datum, hash(datum) % this->node_capacity); | 		Node* b = this->heterofind_node<MT,MEQUALER> (datum, hash(datum) % this->node_capacity); | ||||||
| 		if (!b) return QSE_NULL; | 		if (!b) return QSE_NULL; | ||||||
| 		return &b->value; | 		return &b->value; | ||||||
| 	} | 	} | ||||||
| @ -460,23 +413,82 @@ public: | |||||||
| 		return this->find_node (datum); | 		return this->find_node (datum); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	template <typename MT, typename MHASHER, typename MCOMPARATOR> | 	template <typename MT, typename MHASHER, typename MEQUALER> | ||||||
| 	Node* heterosearch (const MT& datum) | 	Node* heterosearch (const MT& datum) | ||||||
| 	{ | 	{ | ||||||
| 		MHASHER hash; | 		MHASHER hash; | ||||||
| 		return this->heterofind_node<MT,MCOMPARATOR> (datum, hash(datum) % this->node_capacity); | 		return this->heterofind_node<MT,MEQUALER> (datum, hash(datum) % this->node_capacity); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	template <typename MT, typename MHASHER, typename MCOMPARATOR> | 	template <typename MT, typename MHASHER, typename MEQUALER> | ||||||
| 	const Node* heterosearch (const MT& datum) const | 	const Node* heterosearch (const MT& datum) const | ||||||
| 	{ | 	{ | ||||||
| 		MHASHER hash; | 		MHASHER hash; | ||||||
| 		return this->heterofind_node<MT,MCOMPARATOR> (datum, hash(datum) % this->node_capacity); | 		return this->heterofind_node<MT,MEQUALER> (datum, hash(datum) % this->node_capacity); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	Node* inject (const T& datum, int mode, bool* injected = QSE_NULL) | ||||||
|  | 	{ | ||||||
|  | 		qse_size_t hc, head, tail; | ||||||
|  | 		Node* np; | ||||||
|  |  | ||||||
|  | 		hc = this->hasher(datum) % this->node_capacity; | ||||||
|  | 		head = hc << 1; tail = head + 1; | ||||||
|  |  | ||||||
|  | 		np = this->nodes[head]; | ||||||
|  | 		if (np)  | ||||||
|  | 		{ | ||||||
|  | 			do  | ||||||
|  | 			{ | ||||||
|  | 				T& t = np->value; | ||||||
|  | 				if (this->equaler(datum, t))  | ||||||
|  | 				{ | ||||||
|  | 					if (injected) *injected = false; | ||||||
|  | 					if (mode <= -1) return QSE_NULL; // failure | ||||||
|  | 					if (mode >= 1) t = datum; // overwrite | ||||||
|  | 					return np; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				if (np == this->nodes[tail]) break; | ||||||
|  | 				np = np->getNextNode (); | ||||||
|  | 			} | ||||||
|  | 			while (1);  | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (datum_list->getSize() >= threshold)  | ||||||
|  | 		{ | ||||||
|  | 			this->rehash (); | ||||||
|  | 			hc = this->hasher(datum) % this->node_capacity; | ||||||
|  | 			head = hc << 1; tail = head + 1; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (nodes[head] == QSE_NULL)  | ||||||
|  | 		{ | ||||||
|  | 			this->nodes[head] = this->datum_list->insert ((Node*)QSE_NULL, datum); | ||||||
|  | 			this->nodes[tail] = this->nodes[head]; | ||||||
|  | 		} | ||||||
|  | 		else  | ||||||
|  | 		{ | ||||||
|  | 			this->nodes[head] = this->datum_list->insert (this->nodes[head], datum); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (injected) *injected = true; | ||||||
|  | 		return this->nodes[head]; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	Node* insert (const T& datum) | 	Node* insert (const T& datum) | ||||||
| 	{ | 	{ | ||||||
| 		return this->insert_value (datum, false); | 		return this->inject (datum, -1, QSE_NULL); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	Node* ensert (const T& datum) | ||||||
|  | 	{ | ||||||
|  | 		return this->inject (datum, 0, QSE_NULL); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	Node* upsert (const T& datum) | ||||||
|  | 	{ | ||||||
|  | 		return this->inject (datum, 1, QSE_NULL); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	Node* update (const T& datum) | 	Node* update (const T& datum) | ||||||
| @ -486,11 +498,6 @@ public: | |||||||
| 		return node; | 		return node; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	Node* upsert (const T& datum) |  | ||||||
| 	{ |  | ||||||
| 		return this->insert_value (datum, true); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	int remove (const T& datum) | 	int remove (const T& datum) | ||||||
| 	{ | 	{ | ||||||
| 		qse_size_t hc, head, tail; | 		qse_size_t hc, head, tail; | ||||||
| @ -505,7 +512,7 @@ public: | |||||||
| 			do  | 			do  | ||||||
| 			{ | 			{ | ||||||
| 				T& t = np->value; | 				T& t = np->value; | ||||||
| 				if (this->comparator(datum, t))  | 				if (this->equaler(datum, t))  | ||||||
| 				{ | 				{ | ||||||
| 					if (this->nodes[head] == this->nodes[tail]) | 					if (this->nodes[head] == this->nodes[tail]) | ||||||
| 					{ | 					{ | ||||||
| @ -534,13 +541,13 @@ public: | |||||||
| 		return -1; | 		return -1; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	template <typename MT, typename MHASHER, typename MCOMPARATOR> | 	template <typename MT, typename MHASHER, typename MEQUALER> | ||||||
| 	int heteroremove (const MT& datum) | 	int heteroremove (const MT& datum) | ||||||
| 	{ | 	{ | ||||||
| 		MHASHER hash; | 		MHASHER hash; | ||||||
| 		qse_size_t hc = hash(datum) % this->node_capacity; | 		qse_size_t hc = hash(datum) % this->node_capacity; | ||||||
|  |  | ||||||
| 		Node* np = this->heterofind_node<MT,MCOMPARATOR> (datum, hc); | 		Node* np = this->heterofind_node<MT,MEQUALER> (datum, hc); | ||||||
| 		if (np) | 		if (np) | ||||||
| 		{ | 		{ | ||||||
| 			qse_size_t head, tail; | 			qse_size_t head, tail; | ||||||
| @ -614,7 +621,7 @@ protected: | |||||||
| 	mutable qse_size_t threshold; | 	mutable qse_size_t threshold; | ||||||
| 	qse_size_t         load_factor; | 	qse_size_t         load_factor; | ||||||
| 	HASHER             hasher; | 	HASHER             hasher; | ||||||
| 	COMPARATOR         comparator; | 	EQUALER            equaler; | ||||||
| 	RESIZER            resizer; | 	RESIZER            resizer; | ||||||
|  |  | ||||||
| 	void rehash ()  | 	void rehash ()  | ||||||
|  | |||||||
| @ -44,7 +44,7 @@ struct HashTableHasher | |||||||
| }; | }; | ||||||
|  |  | ||||||
| template<typename T> | template<typename T> | ||||||
| struct HashTableComparator | struct HashTableEqualer | ||||||
| { | { | ||||||
| 	// it must return true if two values are equal | 	// it must return true if two values are equal | ||||||
| 	bool operator() (const T& v1, const T& v2) const | 	bool operator() (const T& v1, const T& v2) const | ||||||
| @ -55,15 +55,15 @@ struct HashTableComparator | |||||||
|  |  | ||||||
| typedef HashListResizer HashTableResizer; | typedef HashListResizer HashTableResizer; | ||||||
|  |  | ||||||
| template <typename K, typename V, typename HASHER = HashTableHasher<K>, typename COMPARATOR = HashTableComparator<K>, typename RESIZER = HashTableResizer> | template <typename K, typename V, typename HASHER = HashTableHasher<K>, typename EQUALER = HashTableEqualer<K>, typename RESIZER = HashTableResizer> | ||||||
| class HashTable: public Mmged | class HashTable: public Mmged | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 	typedef Association<K,V> Pair; | 	typedef Association<K,V> Pair; | ||||||
| 	typedef HashTable<K,V,HASHER,COMPARATOR,RESIZER> SelfType; | 	typedef HashTable<K,V,HASHER,EQUALER,RESIZER> SelfType; | ||||||
|  |  | ||||||
| 	typedef HashTableHasher<K> DefaultHasher; | 	typedef HashTableHasher<K> DefaultHasher; | ||||||
| 	typedef HashTableComparator<K> DefaultComparator; | 	typedef HashTableEqualer<K> DefaultEqualer; | ||||||
| 	typedef HashTableResizer DefaultResizer; | 	typedef HashTableResizer DefaultResizer; | ||||||
|  |  | ||||||
| 	struct PairHasher | 	struct PairHasher | ||||||
| @ -75,35 +75,35 @@ public: | |||||||
| 		} | 		} | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	struct PairComparator | 	struct PairEqualer | ||||||
| 	{ | 	{ | ||||||
| 		qse_size_t operator() (const Pair& p1, const Pair& p2) const | 		qse_size_t operator() (const Pair& p1, const Pair& p2) const | ||||||
| 		{ | 		{ | ||||||
| 			COMPARATOR comparator; | 			EQUALER equaler; | ||||||
| 			return comparator (p1.key, p2.key); | 			return equaler (p1.key, p2.key); | ||||||
| 		} | 		} | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	struct PairHeteroComparator | 	struct PairHeteroEqualer | ||||||
| 	{ | 	{ | ||||||
| 		qse_size_t operator() (const K& p1, const Pair& p2) const | 		qse_size_t operator() (const K& p1, const Pair& p2) const | ||||||
| 		{ | 		{ | ||||||
| 			COMPARATOR is_equal; | 			EQUALER equaler; | ||||||
| 			return is_equal (p1, p2.key); | 			return equaler (p1, p2.key); | ||||||
| 		} | 		} | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	template <typename MK, typename MCOMPARATOR> | 	template <typename MK, typename MEQUALER> | ||||||
| 	struct MHeteroComparator | 	struct MHeteroEqualer | ||||||
| 	{ | 	{ | ||||||
| 		qse_size_t operator() (const MK& p1, const Pair& p2) const | 		qse_size_t operator() (const MK& p1, const Pair& p2) const | ||||||
| 		{ | 		{ | ||||||
| 			MCOMPARATOR is_equal; | 			MEQUALER mequaler; | ||||||
| 			return is_equal (p1, p2.key); | 			return mequaler (p1, p2.key); | ||||||
| 		} | 		} | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	typedef HashList<Pair,PairHasher,PairComparator,RESIZER> PairList; | 	typedef HashList<Pair,PairHasher,PairEqualer,RESIZER> PairList; | ||||||
| 	typedef typename PairList::Node PairNode; | 	typedef typename PairList::Node PairNode; | ||||||
| 	typedef typename PairList::Iterator Iterator; | 	typedef typename PairList::Iterator Iterator; | ||||||
| 	typedef typename PairList::ConstIterator ConstIterator; | 	typedef typename PairList::ConstIterator ConstIterator; | ||||||
| @ -180,6 +180,13 @@ public: | |||||||
| 		return this->pair_list.getTailNode (); | 		return this->pair_list.getTailNode (); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	Pair* inject (const K& key, const V& value, int mode, bool* injected = QSE_NULL) | ||||||
|  | 	{ | ||||||
|  | 		PairNode* node = this->pair_list.inject (Pair(key, value), mode, injected); | ||||||
|  | 		if (!node) return QSE_NULL; | ||||||
|  | 		return &node->value; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	Pair* insert (const K& key, const V& value) | 	Pair* insert (const K& key, const V& value) | ||||||
| 	{ | 	{ | ||||||
| 		PairNode* node = this->pair_list.insert (Pair(key, value)); | 		PairNode* node = this->pair_list.insert (Pair(key, value)); | ||||||
| @ -187,20 +194,38 @@ public: | |||||||
| 		return &node->value; | 		return &node->value; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	Pair* upsert (const K& key, const V& value) | 	Pair* ensert (const K& key, const V& value) | ||||||
| 	{ | 	{ | ||||||
| 		PairNode* node = this->pair_list.upsert (Pair(key, value)); | 		PairNode* node = this->pair_list.ensert (Pair(key, value)); | ||||||
| 		if (!node) return QSE_NULL; | 		if (!node) return QSE_NULL; | ||||||
| 		return &node->value; | 		return &node->value; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	Pair* upsert (const K& key, const V& value) | ||||||
|  | 	{ | ||||||
|  | 		//PairNode* node = this->pair_list.upsert (Pair(key, value)); | ||||||
|  | 		//if (!node) return QSE_NULL; | ||||||
|  | 		//return &node->value; | ||||||
|  |  | ||||||
|  | 		// Don't call pair_list.upsert() to make sure that the 'key' object | ||||||
|  | 		// itself remains identical after potential update operation.  | ||||||
|  | 		// pair_list.upsert() changes the Pair object as a whole. so this | ||||||
|  | 		// trick is required. | ||||||
|  | 		bool injected; | ||||||
|  | 		PairNode* node = this->pair_list.inject (Pair(key, value), 0, &injected); | ||||||
|  | 		QSE_ASSERT (node != QSE_NULL); | ||||||
|  | 		Pair& pair = node->value; | ||||||
|  | 		if (injected) pair.value = value; | ||||||
|  | 		return &pair; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	Pair* update (const K& key, const V& value) | 	Pair* update (const K& key, const V& value) | ||||||
| 	{ | 	{ | ||||||
| 		//PairNode* node = this->pair_list.update (Pair(key, value)); | 		//PairNode* node = this->pair_list.update (Pair(key, value)); | ||||||
| 		//if (!node) return QSE_NULL; | 		//if (!node) return QSE_NULL; | ||||||
| 		//return &node->value; | 		//return &node->value; | ||||||
|  |  | ||||||
| 		PairNode* node = this->pair_list.template heterofindNode<K,HASHER,PairHeteroComparator> (key); | 		PairNode* node = this->pair_list.template heterofindNode<K,HASHER,PairHeteroEqualer> (key); | ||||||
| 		if (!node) return QSE_NULL; | 		if (!node) return QSE_NULL; | ||||||
| 		Pair& pair = node->value; | 		Pair& pair = node->value; | ||||||
| 		pair.value = value; | 		pair.value = value; | ||||||
| @ -210,7 +235,7 @@ public: | |||||||
| 	Pair* search (const K& key) | 	Pair* search (const K& key) | ||||||
| 	{ | 	{ | ||||||
| 		//PairNode* node = this->pair_list.update (Pair(key)); | 		//PairNode* node = this->pair_list.update (Pair(key)); | ||||||
| 		PairNode* node = this->pair_list.template heterofindNode<K,HASHER,PairHeteroComparator> (key); | 		PairNode* node = this->pair_list.template heterofindNode<K,HASHER,PairHeteroEqualer> (key); | ||||||
| 		if (!node) return QSE_NULL; | 		if (!node) return QSE_NULL; | ||||||
| 		return &node->value; | 		return &node->value; | ||||||
| 	} | 	} | ||||||
| @ -218,32 +243,32 @@ public: | |||||||
| 	int remove (const K& key) | 	int remove (const K& key) | ||||||
| 	{ | 	{ | ||||||
| 		//return this->pair_list.remove (Pair(key)); | 		//return this->pair_list.remove (Pair(key)); | ||||||
| 		return this->pair_list.template heteroremove<K,HASHER,PairHeteroComparator> (key); | 		return this->pair_list.template heteroremove<K,HASHER,PairHeteroEqualer> (key); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	template <typename MK, typename MHASHER, typename MCOMPARATOR> | 	template <typename MK, typename MHASHER, typename MEQUALER> | ||||||
| 	Pair* heterosearch (const MK& key) | 	Pair* heterosearch (const MK& key) | ||||||
| 	{ | 	{ | ||||||
| 		typedef MHeteroComparator<MK,MCOMPARATOR> MComparator; | 		typedef MHeteroEqualer<MK,MEQUALER> MEqualer; | ||||||
| 		PairNode* node = this->pair_list.template heterosearch<MK,MHASHER,MComparator> (key); | 		PairNode* node = this->pair_list.template heterosearch<MK,MHASHER,MEqualer> (key); | ||||||
| 		if (!node) return QSE_NULL; | 		if (!node) return QSE_NULL; | ||||||
| 		return &node->value; | 		return &node->value; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	template <typename MK, typename MHASHER, typename MCOMPARATOR> | 	template <typename MK, typename MHASHER, typename MEQUALER> | ||||||
| 	const Pair* heterosearch (const MK& key) const | 	const Pair* heterosearch (const MK& key) const | ||||||
| 	{ | 	{ | ||||||
| 		typedef MHeteroComparator<MK,MCOMPARATOR> MComparator; | 		typedef MHeteroEqualer<MK,MEQUALER> MEqualer; | ||||||
| 		PairNode* node = this->pair_list.template heterosearch<MK,MHASHER,MComparator> (key); | 		PairNode* node = this->pair_list.template heterosearch<MK,MHASHER,MEqualer> (key); | ||||||
| 		if (!node) return QSE_NULL; | 		if (!node) return QSE_NULL; | ||||||
| 		return &node->value; | 		return &node->value; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	template <typename MK, typename MHASHER, typename MCOMPARATOR> | 	template <typename MK, typename MHASHER, typename MEQUALER> | ||||||
| 	int heteroremove (const MK& key) | 	int heteroremove (const MK& key) | ||||||
| 	{ | 	{ | ||||||
| 		typedef MHeteroComparator<MK,MCOMPARATOR> MComparator; | 		typedef MHeteroEqualer<MK,MEQUALER> MEqualer; | ||||||
| 		return this->pair_list.template heteroremove<MK,MHASHER,MComparator> (key); | 		return this->pair_list.template heteroremove<MK,MHASHER,MEqualer> (key); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	void clear (bool clear_mpool = false) | 	void clear (bool clear_mpool = false) | ||||||
|  | |||||||
| @ -34,14 +34,14 @@ | |||||||
| QSE_BEGIN_NAMESPACE(QSE) | QSE_BEGIN_NAMESPACE(QSE) | ||||||
| ///////////////////////////////// | ///////////////////////////////// | ||||||
|  |  | ||||||
| template <typename T, typename COMPARATOR> class LinkedList; | template <typename T, typename EQUALER> class LinkedList; | ||||||
|  |  | ||||||
| template <typename T, typename COMPARATOR>  | template <typename T, typename EQUALER>  | ||||||
| class LinkedListNode | class LinkedListNode | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 	friend class LinkedList<T,COMPARATOR>; | 	friend class LinkedList<T,EQUALER>; | ||||||
| 	typedef LinkedListNode<T,COMPARATOR> SelfType; | 	typedef LinkedListNode<T,EQUALER> SelfType; | ||||||
|  |  | ||||||
| 	T value; // you can use this variable or accessor functions below | 	T value; // you can use this variable or accessor functions below | ||||||
|  |  | ||||||
| @ -79,12 +79,12 @@ protected: | |||||||
| 	} | 	} | ||||||
| }; | }; | ||||||
|  |  | ||||||
| template <typename T, typename COMPARATOR, typename NODE, typename GET_T> | template <typename T, typename EQUALER, typename NODE, typename GET_T> | ||||||
| class LinkedListIterator { | class LinkedListIterator { | ||||||
| public: | public: | ||||||
| 	friend class LinkedList<T,COMPARATOR>; | 	friend class LinkedList<T,EQUALER>; | ||||||
| 	typedef NODE Node; | 	typedef NODE Node; | ||||||
| 	typedef LinkedListIterator<T,COMPARATOR,NODE,GET_T> SelfType; | 	typedef LinkedListIterator<T,EQUALER,NODE,GET_T> SelfType; | ||||||
|  |  | ||||||
| 	LinkedListIterator (): current(QSE_NULL) {} | 	LinkedListIterator (): current(QSE_NULL) {} | ||||||
| 	LinkedListIterator (Node* node): current(node) {} | 	LinkedListIterator (Node* node): current(node) {} | ||||||
| @ -178,7 +178,7 @@ protected: | |||||||
| }; | }; | ||||||
|  |  | ||||||
| template<typename T> | template<typename T> | ||||||
| struct LinkedListComparator | struct LinkedListEqualer | ||||||
| { | { | ||||||
| 	// it must return true if two values are equal | 	// it must return true if two values are equal | ||||||
| 	bool operator() (const T& v1, const T& v2) const | 	bool operator() (const T& v1, const T& v2) const | ||||||
| @ -188,17 +188,17 @@ struct LinkedListComparator | |||||||
| }; | }; | ||||||
|  |  | ||||||
| /// | /// | ||||||
| /// The LinkedList<T,COMPARATOR> class provides a template for a doubly-linked list. | /// The LinkedList<T,EQUALER> class provides a template for a doubly-linked list. | ||||||
| /// | /// | ||||||
| template <typename T, typename COMPARATOR = LinkedListComparator<T> > class LinkedList: public Mmged | template <typename T, typename EQUALER = LinkedListEqualer<T> > class LinkedList: public Mmged | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 	typedef LinkedList<T,COMPARATOR> SelfType; | 	typedef LinkedList<T,EQUALER> SelfType; | ||||||
| 	typedef LinkedListNode<T,COMPARATOR> Node; | 	typedef LinkedListNode<T,EQUALER> Node; | ||||||
| 	typedef LinkedListIterator<T,COMPARATOR,Node,T> Iterator; | 	typedef LinkedListIterator<T,EQUALER,Node,T> Iterator; | ||||||
| 	typedef LinkedListIterator<T,COMPARATOR,const Node,const T> ConstIterator; | 	typedef LinkedListIterator<T,EQUALER,const Node,const T> ConstIterator; | ||||||
|  |  | ||||||
| 	typedef LinkedListComparator<T> DefaultComparator; | 	typedef LinkedListEqualer<T> DefaultEqualer; | ||||||
|  |  | ||||||
| 	enum  | 	enum  | ||||||
| 	{ | 	{ | ||||||
| @ -270,7 +270,7 @@ public: | |||||||
|  |  | ||||||
| 	bool isEmpty () const  | 	bool isEmpty () const  | ||||||
| 	{ | 	{ | ||||||
| 		return this->node_count == 0; | 		return this->node_count <= 0; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/// The insertNode() function inserts an externally created \a node | 	/// The insertNode() function inserts an externally created \a node | ||||||
| @ -576,7 +576,7 @@ public: | |||||||
| 	{ | 	{ | ||||||
| 		for (Node* p = this->head_node; p; p = p->next)  | 		for (Node* p = this->head_node; p; p = p->next)  | ||||||
| 		{ | 		{ | ||||||
| 			if (this->comparator (value, p->value)) return p; | 			if (this->equaler (value, p->value)) return p; | ||||||
| 		} | 		} | ||||||
| 		return QSE_NULL; | 		return QSE_NULL; | ||||||
| 	} | 	} | ||||||
| @ -585,7 +585,7 @@ public: | |||||||
| 	{ | 	{ | ||||||
| 		for (Node* p = tail_node; p; p = p->prev)  | 		for (Node* p = tail_node; p; p = p->prev)  | ||||||
| 		{ | 		{ | ||||||
| 			if (this->comparator (value, p->value)) return p; | 			if (this->equaler (value, p->value)) return p; | ||||||
| 		} | 		} | ||||||
| 		return QSE_NULL; | 		return QSE_NULL; | ||||||
| 	} | 	} | ||||||
| @ -594,7 +594,7 @@ public: | |||||||
| 	{ | 	{ | ||||||
| 		for (Node* p = head; p; p = p->next) | 		for (Node* p = head; p; p = p->next) | ||||||
| 		{ | 		{ | ||||||
| 			if (this->comparator (value, p->value)) return p; | 			if (this->equaler (value, p->value)) return p; | ||||||
| 		} | 		} | ||||||
| 		return QSE_NULL; | 		return QSE_NULL; | ||||||
| 	} | 	} | ||||||
| @ -603,7 +603,7 @@ public: | |||||||
| 	{ | 	{ | ||||||
| 		for (Node* p = tail; p; p = p->prev)  | 		for (Node* p = tail; p; p = p->prev)  | ||||||
| 		{ | 		{ | ||||||
| 			if (this->comparator (value, p->value)) return p; | 			if (this->equaler (value, p->value)) return p; | ||||||
| 		} | 		} | ||||||
| 		return QSE_NULL; | 		return QSE_NULL; | ||||||
| 	} | 	} | ||||||
| @ -613,7 +613,7 @@ public: | |||||||
| 		qse_size_t index = 0; | 		qse_size_t index = 0; | ||||||
| 		for (Node* p = this->head_node; p; p = p->next)  | 		for (Node* p = this->head_node; p; p = p->next)  | ||||||
| 		{ | 		{ | ||||||
| 			if (this->comparator (value, p->value)) return index; | 			if (this->equaler (value, p->value)) return index; | ||||||
| 			index++; | 			index++; | ||||||
| 		} | 		} | ||||||
| 		return INVALID_INDEX; | 		return INVALID_INDEX; | ||||||
| @ -625,7 +625,7 @@ public: | |||||||
| 		for (Node* p = tail_node; p; p = p->prev)  | 		for (Node* p = tail_node; p; p = p->prev)  | ||||||
| 		{ | 		{ | ||||||
| 			index--; | 			index--; | ||||||
| 			if (this->comparator (value, p->value)) return index; | 			if (this->equaler (value, p->value)) return index; | ||||||
| 		} | 		} | ||||||
| 		return INVALID_INDEX; | 		return INVALID_INDEX; | ||||||
| 	} | 	} | ||||||
| @ -696,7 +696,7 @@ public: | |||||||
|  |  | ||||||
| protected: | protected: | ||||||
| 	Mpool       mp; | 	Mpool       mp; | ||||||
| 	COMPARATOR  comparator; | 	EQUALER     equaler; | ||||||
| 	Node*       head_node; | 	Node*       head_node; | ||||||
| 	Node*       tail_node; | 	Node*       tail_node; | ||||||
| 	qse_size_t  node_count; | 	qse_size_t  node_count; | ||||||
|  | |||||||
| @ -52,6 +52,7 @@ pkginclude_HEADERS = \ | |||||||
| if ENABLE_CXX | if ENABLE_CXX | ||||||
| pkginclude_HEADERS += \ | pkginclude_HEADERS += \ | ||||||
| 	Mmgr.hpp StdMmgr.hpp HeapMmgr.hpp Mmged.hpp \ | 	Mmgr.hpp StdMmgr.hpp HeapMmgr.hpp Mmged.hpp \ | ||||||
| 	Mpool.hpp Association.hpp LinkedList.hpp HashList.hpp HashTable.hpp | 	Mpool.hpp Association.hpp LinkedList.hpp HashList.hpp HashTable.hpp \ | ||||||
|  | 	RedBlackTree.hpp | ||||||
| endif | endif | ||||||
|  |  | ||||||
|  | |||||||
| @ -52,7 +52,8 @@ build_triplet = @build@ | |||||||
| host_triplet = @host@ | host_triplet = @host@ | ||||||
| @ENABLE_CXX_TRUE@am__append_1 = \ | @ENABLE_CXX_TRUE@am__append_1 = \ | ||||||
| @ENABLE_CXX_TRUE@	Mmgr.hpp StdMmgr.hpp HeapMmgr.hpp Mmged.hpp \ | @ENABLE_CXX_TRUE@	Mmgr.hpp StdMmgr.hpp HeapMmgr.hpp Mmged.hpp \ | ||||||
| @ENABLE_CXX_TRUE@	Mpool.hpp Association.hpp LinkedList.hpp HashList.hpp HashTable.hpp | @ENABLE_CXX_TRUE@	Mpool.hpp Association.hpp LinkedList.hpp HashList.hpp HashTable.hpp \ | ||||||
|  | @ENABLE_CXX_TRUE@	RedBlackTree.hpp | ||||||
|  |  | ||||||
| subdir = include/qse/cmn | subdir = include/qse/cmn | ||||||
| DIST_COMMON = $(am__pkginclude_HEADERS_DIST) $(srcdir)/Makefile.am \ | DIST_COMMON = $(am__pkginclude_HEADERS_DIST) $(srcdir)/Makefile.am \ | ||||||
| @ -92,7 +93,7 @@ am__pkginclude_HEADERS_DIST = alg.h chr.h cp949.h cp950.h dir.h dll.h \ | |||||||
| 	sll.h slmb.h str.h task.h time.h tio.h tmr.h tre.h uni.h uri.h \ | 	sll.h slmb.h str.h task.h time.h tio.h tmr.h tre.h uni.h uri.h \ | ||||||
| 	utf8.h xma.h Mmgr.hpp StdMmgr.hpp HeapMmgr.hpp Mmged.hpp \ | 	utf8.h xma.h Mmgr.hpp StdMmgr.hpp HeapMmgr.hpp Mmged.hpp \ | ||||||
| 	Mpool.hpp Association.hpp LinkedList.hpp HashList.hpp \ | 	Mpool.hpp Association.hpp LinkedList.hpp HashList.hpp \ | ||||||
| 	HashTable.hpp | 	HashTable.hpp RedBlackTree.hpp | ||||||
| am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; | am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; | ||||||
| am__vpath_adj = case $$p in \ | am__vpath_adj = case $$p in \ | ||||||
|     $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ |     $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ | ||||||
|  | |||||||
							
								
								
									
										166
									
								
								qse/include/qse/cmn/RedBlackTree.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								qse/include/qse/cmn/RedBlackTree.hpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,166 @@ | |||||||
|  | /* | ||||||
|  |  * $Id$ | ||||||
|  |  * | ||||||
|  |     Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved. | ||||||
|  |  | ||||||
|  |     Redistribution and use in source and binary forms, with or without | ||||||
|  |     modification, are permitted provided that the following conditions | ||||||
|  |     are met: | ||||||
|  |     1. Redistributions of source code must retain the above copyright | ||||||
|  |        notice, this list of conditions and the following disclaimer. | ||||||
|  |     2. Redistributions in binary form must reproduce the above copyright | ||||||
|  |        notice, this list of conditions and the following disclaimer in the | ||||||
|  |        documentation and/or other materials provided with the distribution. | ||||||
|  |  | ||||||
|  |     THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR | ||||||
|  |     IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||||||
|  |     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||||||
|  |     IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||||||
|  |     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||||||
|  |     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||||
|  |     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||||
|  |     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||||
|  |     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||||||
|  |     THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #ifndef _QSE_CMN_REDBLACKTREE_HPP_ | ||||||
|  | #define _QSE_CMN_REDBLACKTREE_HPP_ | ||||||
|  |  | ||||||
|  | #include <qse/Types.hpp> | ||||||
|  | #include <qse/cmn/Mpool.hpp> | ||||||
|  |  | ||||||
|  | ///////////////////////////////// | ||||||
|  | QSE_BEGIN_NAMESPACE(QSE) | ||||||
|  | ///////////////////////////////// | ||||||
|  |  | ||||||
|  | template <typename T>  | ||||||
|  | class RedBlackTreeNode | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	friend class RedBlackTree<T>; | ||||||
|  | 	typedef RedBlackTreeNode<T> SelfType; | ||||||
|  |  | ||||||
|  | 	enum | ||||||
|  | 	{ | ||||||
|  | 		RED, | ||||||
|  | 		BLACK | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	T value; // you can use this variable or accessor functions below | ||||||
|  |  | ||||||
|  | protected: | ||||||
|  | 	SelfType* parent; | ||||||
|  | 	SelfType* child[2]; // left and right | ||||||
|  |  | ||||||
|  | public: | ||||||
|  | 	T& getValue () { return this->value; } | ||||||
|  | 	const T& getValue () const { return this->value; } | ||||||
|  | 	void setValue (const T& v) { this->value = v; } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename T> | ||||||
|  | struct RedBlackTreeComparator | ||||||
|  | { | ||||||
|  | 	int operator() (const T& v1, const T& v2) const | ||||||
|  | 	{ | ||||||
|  | 		return (v1 > v2)? 1:  | ||||||
|  | 		       (v1 < v2)? -1: 0; | ||||||
|  | 	} | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template <typename T, typename COMPARATOR = RedBlackTreeComparator<T> > | ||||||
|  | class RedBlackTree: public Mmged | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	typedef RedBlackTree<T,COMPARATOR> SelfType; | ||||||
|  |  | ||||||
|  | 	typedef RedBlackTreeHasher<T> DefaultHasher; | ||||||
|  | 	typedef RedBlackTreeComparator<T> DefaultComparator; | ||||||
|  |  | ||||||
|  | 	RedBlackTree | ||||||
|  | 		Mmgr* mmgr = QSE_NULL, | ||||||
|  | 		qse_size_t mpb_size = 0): Mmged(mmgr) | ||||||
|  | 	{ | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	RedBlackTree (const RedBlackTree& rbt) | ||||||
|  | 	{ | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	~RedBlackTree () | ||||||
|  | 	{ | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	RedBlackTree& operator= (const RedBlackTree& rbt) | ||||||
|  | 	{ | ||||||
|  | 		/* TODO */ | ||||||
|  | 		return *this; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	Mpool& getMpool () | ||||||
|  | 	{ | ||||||
|  | 		return this->mp; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	const Mpool& getMpool () const | ||||||
|  | 	{ | ||||||
|  | 		return this->mp; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	qse_size_t getSize () const  | ||||||
|  | 	{ | ||||||
|  | 		return this->node_count; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	bool isEmpty () const  | ||||||
|  | 	{ | ||||||
|  | 		return this->node_count <= 0; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | public: | ||||||
|  |  | ||||||
|  | 	Node* inject (const T& datum, int mode, bool* injected = QSE_NULL) | ||||||
|  | 	{ | ||||||
|  | 		return QSE_NULL; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	Node* insert (const T& datum) | ||||||
|  | 	{ | ||||||
|  | 		return this->inject (datum, -1, QSE_NULL); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	Node* ensert (const T& datum) | ||||||
|  | 	{ | ||||||
|  | 		return this->inject (datum, 0, QSE_NULL); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	Node* upsert (const T& datum) | ||||||
|  | 	{ | ||||||
|  | 		return this->inject (datum, 1, QSE_NULL); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | #if 0 | ||||||
|  | 	Node* update (const T& datum) | ||||||
|  | 	{ | ||||||
|  | 		Node* node = this->find_node (datum); | ||||||
|  | 		if (node) node->value = datum; | ||||||
|  | 		return node; | ||||||
|  | 	} | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | protected: | ||||||
|  | 	Mpool      mp; | ||||||
|  | 	COMPARATOR comparator; | ||||||
|  |  | ||||||
|  | 	Node       xnil; // internal node to present nil  | ||||||
|  | 	Node*      root; // root node. | ||||||
|  | 	qse_size_t node_count; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ///////////////////////////////// | ||||||
|  | QSE_END_NAMESPACE(QSE) | ||||||
|  | ///////////////////////////////// | ||||||
|  |  | ||||||
|  | #endif | ||||||
		Reference in New Issue
	
	Block a user