diff --git a/SimoxUtility/CMakeLists.txt b/SimoxUtility/CMakeLists.txt
index 4d336ca1ca9b22650138c1a3ec2a4914ae84cd15..8e5c50a6de8de92b71c932d438c71de064fda6c6 100644
--- a/SimoxUtility/CMakeLists.txt
+++ b/SimoxUtility/CMakeLists.txt
@@ -101,6 +101,7 @@ SET(INCLUDES
 
     algorithm/advanced.h
     algorithm/apply.hpp
+    algorithm/contains.h
     algorithm/for_each_if.h
     algorithm/fuzzy_find.h
     algorithm/get_map_keys_values.h
diff --git a/SimoxUtility/algorithm.h b/SimoxUtility/algorithm.h
index a4752d98709411b0351ec0376e155c5d794d88a6..bc7252a2cee84dc106b548b5a3e3025bdae0c14e 100644
--- a/SimoxUtility/algorithm.h
+++ b/SimoxUtility/algorithm.h
@@ -3,6 +3,7 @@
 // This file is generated!
 
 #include "algorithm/advanced.h"
+#include "algorithm/contains.h"
 #include "algorithm/for_each_if.h"
 #include "algorithm/fuzzy_find.h"
 #include "algorithm/get_map_keys_values.h"
diff --git a/SimoxUtility/algorithm/contains.h b/SimoxUtility/algorithm/contains.h
new file mode 100644
index 0000000000000000000000000000000000000000..45516257dff2a166ed516779558e4498ef93954c
--- /dev/null
+++ b/SimoxUtility/algorithm/contains.h
@@ -0,0 +1,79 @@
+#pragma once
+
+#include <algorithm>
+#include <functional>
+#include <string>
+#include <map>
+
+
+namespace simox::alg
+{
+
+    // For overloads of `simox::alg::contains` taking `std::string`:
+    // #include <SimoxUtility/algorithm/string/string_tools.h>
+
+    // GENERAL CONTAINERS
+
+    /**
+     * Return true if `value` is an element of `container`, false otherwise.
+     */
+    template <class ContainerT, class ValueT>
+    bool contains(const ContainerT& container, const ValueT& value)
+    {
+        return std::find_if(container.begin(), container.end(), [&value](const auto& v)
+        {
+            return v == value;
+        }) != container.end();
+    }
+
+    /**
+     * Return true if `value` is an element of `container` (as indicated by `predicate`),
+     * false otherwise.
+     */
+    template <class ContainerT, class ValueT, class PredicateT>
+    bool contains(const ContainerT& container, const ValueT& value, const PredicateT& predicate)
+    {
+        return std::find_if(container.begin(), container.end(), [&value, &predicate](const auto& v)
+        {
+            return predicate(v, value);
+        }) != container.end();
+    }
+
+
+    // MAPS
+
+    /**
+     * Return true if `key` is a key in `map`, false otherwise.
+     */
+    template <class K, class V, template<class...> class MapT = std::map, class...Ts>
+    bool contains_key(const MapT<K, V, Ts...>& map, const K& key)
+    {
+        return map.count(key) > 0;
+    }
+
+    /**
+     * Return true if `value` is a value in `map`, false otherwise.
+     */
+    template <class K, class V, template<class...> class MapT = std::map, class...Ts>
+    bool contains_value(const MapT<K, V, Ts...>& map, const V& value)
+    {
+        return std::find_if(map.begin(), map.end(), [&value](const std::pair<K, V>& item)
+        {
+            return item.second == value;
+        }) != map.end();
+    }
+
+
+    // Overloads for string literals (which otherwise don't match the previous definition).
+    template <class V, template<class...> class MapT = std::map, class...Ts>
+    bool contains_key(const MapT<std::string, V, Ts...>& map, const std::string& key)
+    {
+        return map.count(key) > 0;
+    }
+    template <class K, template<class...> class MapT = std::map, class...Ts>
+    bool contains_value(const MapT<K, std::string, Ts...>& map, const std::string& value)
+    {
+        return contains_value<K, std::string>(map, value);
+    }
+
+}