Initial Commit. Needs refactored to run tests in parallel. Needs to avoid copying objects into both unordered_maps and reference them instead.
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					run-tests
 | 
				
			||||||
							
								
								
									
										94
									
								
								DualLookup.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								DualLookup.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,94 @@
 | 
				
			|||||||
 | 
					#ifndef DVEREB_DUALLOOKUP_H
 | 
				
			||||||
 | 
					#define DVEREB_DUALLOOKUP_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <unordered_map>
 | 
				
			||||||
 | 
					template <class T>
 | 
				
			||||||
 | 
					class DualLookup {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						DualLookup();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Add a mapped pair to the container
 | 
				
			||||||
 | 
						 *  returns false if it already exists, regardless of direction
 | 
				
			||||||
 | 
						 *   (i.e. value->equivilent is a duplicate of equivilent->value)
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						bool add(T value, T equivilent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* If found, Set result to the mapped value and true is returned.
 | 
				
			||||||
 | 
						 * If not found, result remains unchanged and false is returned.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						bool get(T key, T &result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* If found, return true
 | 
				
			||||||
 | 
						 * else return false */
 | 
				
			||||||
 | 
						bool contains(const T &key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						std::unordered_map<T, T> owner;
 | 
				
			||||||
 | 
						std::unordered_map<T, T> mirror;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// NOTE(dev): These functions actually do the work:
 | 
				
			||||||
 | 
						bool get_single(T key, T &result, const std::unordered_map<T, T> &umap);
 | 
				
			||||||
 | 
						bool contains_single(const T &key, const std::unordered_map<T, T> &umap);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <class T>
 | 
				
			||||||
 | 
					DualLookup<T>::DualLookup()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <class T>
 | 
				
			||||||
 | 
					bool DualLookup<T>::add(T value, T equivilent)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						// already exists
 | 
				
			||||||
 | 
						if(owner.find(value) != owner.end() || mirror.find(value) != mirror.end())
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						if(owner.find(equivilent) != owner.end() || mirror.find(equivilent) != mirror.end())
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						owner.insert({value, equivilent});
 | 
				
			||||||
 | 
						mirror.insert({equivilent, value});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <class T>
 | 
				
			||||||
 | 
					bool DualLookup<T>::get(T key, T &result)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if(get_single(key, result, owner))
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						if(get_single(key, result, mirror))
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return false; // didn't find it
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <class T>
 | 
				
			||||||
 | 
					bool DualLookup<T>::contains(const T &key)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if(contains_single(key, owner))
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						if(contains_single(key, mirror))
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return false; // didn't find it
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <class T>
 | 
				
			||||||
 | 
					bool DualLookup<T>::get_single(T key, T &result, const std::unordered_map<T, T> &umap)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						auto i = umap.find(key);
 | 
				
			||||||
 | 
						if(i == umap.end())
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						result = i->second;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <class T>
 | 
				
			||||||
 | 
					bool DualLookup<T>::contains_single(const T &key, const std::unordered_map<T, T> &umap)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return umap.find(key) != umap.end();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										5
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					test: run-tests
 | 
				
			||||||
 | 
						./run-tests
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					run-tests: tests-main.cpp main.cpp DualLookup.h
 | 
				
			||||||
 | 
						clang++ -std=c++11 tests-main.cpp main.cpp -o run-tests
 | 
				
			||||||
							
								
								
									
										60
									
								
								main.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								main.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,60 @@
 | 
				
			|||||||
 | 
					#include "catch.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "DualLookup.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_CASE("all tests", "all") {
 | 
				
			||||||
 | 
						DualLookup<int> container;
 | 
				
			||||||
 | 
						DualLookup<std::string> string_container;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SECTION ("allow add") {
 | 
				
			||||||
 | 
							REQUIRE(container.add(1, 2));
 | 
				
			||||||
 | 
							REQUIRE(string_container.add("1", "2"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							SECTION ("no duplicates") {
 | 
				
			||||||
 | 
								REQUIRE_FALSE(container.add(1, 2));
 | 
				
			||||||
 | 
								REQUIRE_FALSE(container.add(2, 1));
 | 
				
			||||||
 | 
								REQUIRE_FALSE(container.add(1, 3));
 | 
				
			||||||
 | 
								REQUIRE_FALSE(container.add(2, 3));
 | 
				
			||||||
 | 
								REQUIRE_FALSE(container.add(3, 1));
 | 
				
			||||||
 | 
								REQUIRE_FALSE(container.add(3, 2));
 | 
				
			||||||
 | 
								REQUIRE_FALSE(string_container.add("1", "2"));
 | 
				
			||||||
 | 
								REQUIRE_FALSE(string_container.add("2", "1"));
 | 
				
			||||||
 | 
								REQUIRE_FALSE(string_container.add("1", "3"));
 | 
				
			||||||
 | 
								REQUIRE_FALSE(string_container.add("2", "3"));
 | 
				
			||||||
 | 
								REQUIRE_FALSE(string_container.add("3", "1"));
 | 
				
			||||||
 | 
								REQUIRE_FALSE(string_container.add("3", "2"));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							SECTION ("searches") {
 | 
				
			||||||
 | 
								bool        rtn;
 | 
				
			||||||
 | 
								int         container_result;
 | 
				
			||||||
 | 
								std::string string_container_result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								SECTION ("found and not found") {
 | 
				
			||||||
 | 
									REQUIRE(container.contains(1));
 | 
				
			||||||
 | 
									REQUIRE(string_container.contains("1"));
 | 
				
			||||||
 | 
									REQUIRE_FALSE(container.contains(10));
 | 
				
			||||||
 | 
									REQUIRE_FALSE(string_container.contains("10"));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								SECTION ("not found in container and unedited") {
 | 
				
			||||||
 | 
									container_result = 10;
 | 
				
			||||||
 | 
									string_container_result = "10";
 | 
				
			||||||
 | 
									REQUIRE_FALSE(container.get(20, container_result));
 | 
				
			||||||
 | 
									REQUIRE(container_result == 10);
 | 
				
			||||||
 | 
									REQUIRE_FALSE(string_container.get("20", string_container_result));
 | 
				
			||||||
 | 
									REQUIRE(string_container_result == "10");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								SECTION ("in container and set") {
 | 
				
			||||||
 | 
									container_result = 0;
 | 
				
			||||||
 | 
									REQUIRE(container.get(1, container_result));
 | 
				
			||||||
 | 
									REQUIRE(container_result == 2);
 | 
				
			||||||
 | 
									REQUIRE(string_container.get("1", string_container_result));
 | 
				
			||||||
 | 
									REQUIRE(string_container_result == "2");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										2
									
								
								tests-main.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								tests-main.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					#define CATCH_CONFIG_MAIN
 | 
				
			||||||
 | 
					#include "catch.hpp"
 | 
				
			||||||
		Reference in New Issue
	
	Block a user