support unordered set/map data structures (fixes #100)
diff --git a/docs/basics.rst b/docs/basics.rst
index 7c2b4ee..53a325e 100644
--- a/docs/basics.rst
+++ b/docs/basics.rst
@@ -222,45 +222,49 @@
an additional extension header to be included). To pass other data structures
as arguments and return values, refer to the section on binding :ref:`classes`.
-+------------------------+--------------------------+-----------------------+
-| Data type | Description | Header file |
-+========================+==========================+=======================+
-| int8_t, uint8_t | 8-bit integers | pybind11/pybind11.h |
-+------------------------+--------------------------+-----------------------+
-| int16_t, uint16_t | 16-bit integers | pybind11/pybind11.h |
-+------------------------+--------------------------+-----------------------+
-| int32_t, uint32_t | 32-bit integers | pybind11/pybind11.h |
-+------------------------+--------------------------+-----------------------+
-| int64_t, uint64_t | 64-bit integers | pybind11/pybind11.h |
-+------------------------+--------------------------+-----------------------+
-| ssize_t, size_t | Platform-dependent size | pybind11/pybind11.h |
-+------------------------+--------------------------+-----------------------+
-| float, double | Floating point types | pybind11/pybind11.h |
-+------------------------+--------------------------+-----------------------+
-| bool | Two-state Boolean type | pybind11/pybind11.h |
-+------------------------+--------------------------+-----------------------+
-| char | Character literal | pybind11/pybind11.h |
-+------------------------+--------------------------+-----------------------+
-| const char * | UTF-8 string literal | pybind11/pybind11.h |
-+------------------------+--------------------------+-----------------------+
-| std::string | STL dynamic UTF-8 string | pybind11/pybind11.h |
-+------------------------+--------------------------+-----------------------+
-| std::pair<T1, T2> | Pair of two custom types | pybind11/pybind11.h |
-+------------------------+--------------------------+-----------------------+
-| std::tuple<....> | Arbitrary tuple of types | pybind11/pybind11.h |
-+------------------------+--------------------------+-----------------------+
-| std::complex<T> | Complex numbers | pybind11/complex.h |
-+------------------------+--------------------------+-----------------------+
-| std::array<T, Size> | STL static array | pybind11/stl.h |
-+------------------------+--------------------------+-----------------------+
-| std::vector<T> | STL dynamic array | pybind11/stl.h |
-+------------------------+--------------------------+-----------------------+
-| std::map<T1, T2> | STL ordered map | pybind11/stl.h |
-+------------------------+--------------------------+-----------------------+
-| std::set<T> | STL ordered set | pybind11/stl.h |
-+------------------------+--------------------------+-----------------------+
-| std::function<...> | STL polymorphic function | pybind11/functional.h |
-+------------------------+--------------------------+-----------------------+
++----------------------------+--------------------------+-----------------------+
+| Data type | Description | Header file |
++============================+==========================+=======================+
+| int8_t, uint8_t | 8-bit integers | pybind11/pybind11.h |
++----------------------------+--------------------------+-----------------------+
+| int16_t, uint16_t | 16-bit integers | pybind11/pybind11.h |
++----------------------------+--------------------------+-----------------------+
+| int32_t, uint32_t | 32-bit integers | pybind11/pybind11.h |
++----------------------------+--------------------------+-----------------------+
+| int64_t, uint64_t | 64-bit integers | pybind11/pybind11.h |
++----------------------------+--------------------------+-----------------------+
+| ssize_t, size_t | Platform-dependent size | pybind11/pybind11.h |
++----------------------------+--------------------------+-----------------------+
+| float, double | Floating point types | pybind11/pybind11.h |
++----------------------------+--------------------------+-----------------------+
+| bool | Two-state Boolean type | pybind11/pybind11.h |
++----------------------------+--------------------------+-----------------------+
+| char | Character literal | pybind11/pybind11.h |
++----------------------------+--------------------------+-----------------------+
+| const char * | UTF-8 string literal | pybind11/pybind11.h |
++----------------------------+--------------------------+-----------------------+
+| std::string | STL dynamic UTF-8 string | pybind11/pybind11.h |
++----------------------------+--------------------------+-----------------------+
+| std::pair<T1, T2> | Pair of two custom types | pybind11/pybind11.h |
++----------------------------+--------------------------+-----------------------+
+| std::tuple<....> | Arbitrary tuple of types | pybind11/pybind11.h |
++----------------------------+--------------------------+-----------------------+
+| std::complex<T> | Complex numbers | pybind11/complex.h |
++----------------------------+--------------------------+-----------------------+
+| std::array<T, Size> | STL static array | pybind11/stl.h |
++----------------------------+--------------------------+-----------------------+
+| std::vector<T> | STL dynamic array | pybind11/stl.h |
++----------------------------+--------------------------+-----------------------+
+| std::map<T1, T2> | STL ordered map | pybind11/stl.h |
++----------------------------+--------------------------+-----------------------+
+| std::unordered_map<T1, T2> | STL unordered map | pybind11/stl.h |
++----------------------------+--------------------------+-----------------------+
+| std::set<T> | STL ordered set | pybind11/stl.h |
++----------------------------+--------------------------+-----------------------+
+| std::unordered_set<T> | STL unordered set | pybind11/stl.h |
++----------------------------+--------------------------+-----------------------+
+| std::function<...> | STL polymorphic function | pybind11/functional.h |
++----------------------------+--------------------------+-----------------------+
.. [#f1] In practice, implementation and binding code will generally be located
diff --git a/include/pybind11/stl.h b/include/pybind11/stl.h
index dcb96e0..1ee2cc4 100644
--- a/include/pybind11/stl.h
+++ b/include/pybind11/stl.h
@@ -10,8 +10,10 @@
#pragma once
#include "pybind11.h"
-#include <map>
#include <set>
+#include <unordered_set>
+#include <map>
+#include <unordered_map>
#include <iostream>
#if defined(_MSC_VER)
@@ -22,77 +24,10 @@
NAMESPACE_BEGIN(pybind11)
NAMESPACE_BEGIN(detail)
-template <typename Type, typename Alloc> struct type_caster<std::vector<Type, Alloc>> {
- typedef std::vector<Type, Alloc> vector_type;
- typedef type_caster<Type> value_conv;
-public:
- bool load(handle src, bool convert) {
- list l(src, true);
- if (!l.check())
- return false;
- value.reserve(l.size());
- value.clear();
- value_conv conv;
- for (auto it : l) {
- if (!conv.load(it, convert))
- return false;
- value.push_back((Type) conv);
- }
- return true;
- }
-
- static handle cast(const vector_type &src, return_value_policy policy, handle parent) {
- list l(src.size());
- size_t index = 0;
- for (auto const &value: src) {
- object value_ = object(value_conv::cast(value, policy, parent), false);
- if (!value_)
- return handle();
- PyList_SET_ITEM(l.ptr(), index++, value_.release().ptr()); // steals a reference
- }
- return l.release();
- }
- PYBIND11_TYPE_CASTER(vector_type, _("list<") + value_conv::name() + _(">"));
-};
-
-template <typename Type, size_t Size> struct type_caster<std::array<Type, Size>> {
- typedef std::array<Type, Size> array_type;
- typedef type_caster<Type> value_conv;
-public:
- bool load(handle src, bool convert) {
- list l(src, true);
- if (!l.check())
- return false;
- if (l.size() != Size)
- return false;
- value_conv conv;
- size_t ctr = 0;
- for (auto it : l) {
- if (!conv.load(it, convert))
- return false;
- value[ctr++] = (Type) conv;
- }
- return true;
- }
-
- static handle cast(const array_type &src, return_value_policy policy, handle parent) {
- list l(Size);
- size_t index = 0;
- for (auto const &value: src) {
- object value_ = object(value_conv::cast(value, policy, parent), false);
- if (!value_)
- return handle();
- PyList_SET_ITEM(l.ptr(), index++, value_.release().ptr()); // steals a reference
- }
- return l.release();
- }
- PYBIND11_TYPE_CASTER(array_type, _("list<") + value_conv::name() + _(">") + _("[") + _<Size>() + _("]"));
-};
-
-template <typename Key, typename Compare, typename Alloc> struct type_caster<std::set<Key, Compare, Alloc>> {
- typedef std::set<Key, Compare, Alloc> type;
+template <typename Type, typename Key> struct set_caster {
+ typedef Type type;
typedef type_caster<Key> key_conv;
-public:
+
bool load(handle src, bool convert) {
pybind11::set s(src, true);
if (!s.check())
@@ -116,12 +51,12 @@
}
return s.release();
}
+
PYBIND11_TYPE_CASTER(type, _("set<") + key_conv::name() + _(">"));
};
-template <typename Key, typename Value, typename Compare, typename Alloc> struct type_caster<std::map<Key, Value, Compare, Alloc>> {
-public:
- typedef std::map<Key, Value, Compare, Alloc> type;
+template <typename Type, typename Key, typename Value> struct map_caster {
+ typedef Type type;
typedef type_caster<Key> key_conv;
typedef type_caster<Value> value_conv;
@@ -156,6 +91,85 @@
PYBIND11_TYPE_CASTER(type, _("dict<") + key_conv::name() + _(", ") + value_conv::name() + _(">"));
};
+template <typename Type, typename Alloc> struct type_caster<std::vector<Type, Alloc>> {
+ typedef std::vector<Type, Alloc> vector_type;
+ typedef type_caster<Type> value_conv;
+
+ bool load(handle src, bool convert) {
+ list l(src, true);
+ if (!l.check())
+ return false;
+ value.reserve(l.size());
+ value.clear();
+ value_conv conv;
+ for (auto it : l) {
+ if (!conv.load(it, convert))
+ return false;
+ value.push_back((Type) conv);
+ }
+ return true;
+ }
+
+ static handle cast(const vector_type &src, return_value_policy policy, handle parent) {
+ list l(src.size());
+ size_t index = 0;
+ for (auto const &value: src) {
+ object value_ = object(value_conv::cast(value, policy, parent), false);
+ if (!value_)
+ return handle();
+ PyList_SET_ITEM(l.ptr(), index++, value_.release().ptr()); // steals a reference
+ }
+ return l.release();
+ }
+ PYBIND11_TYPE_CASTER(vector_type, _("list<") + value_conv::name() + _(">"));
+};
+
+template <typename Type, size_t Size> struct type_caster<std::array<Type, Size>> {
+ typedef std::array<Type, Size> array_type;
+ typedef type_caster<Type> value_conv;
+
+ bool load(handle src, bool convert) {
+ list l(src, true);
+ if (!l.check())
+ return false;
+ if (l.size() != Size)
+ return false;
+ value_conv conv;
+ size_t ctr = 0;
+ for (auto it : l) {
+ if (!conv.load(it, convert))
+ return false;
+ value[ctr++] = (Type) conv;
+ }
+ return true;
+ }
+
+ static handle cast(const array_type &src, return_value_policy policy, handle parent) {
+ list l(Size);
+ size_t index = 0;
+ for (auto const &value: src) {
+ object value_ = object(value_conv::cast(value, policy, parent), false);
+ if (!value_)
+ return handle();
+ PyList_SET_ITEM(l.ptr(), index++, value_.release().ptr()); // steals a reference
+ }
+ return l.release();
+ }
+ PYBIND11_TYPE_CASTER(array_type, _("list<") + value_conv::name() + _(">") + _("[") + _<Size>() + _("]"));
+};
+
+template <typename Key, typename Compare, typename Alloc> struct type_caster<std::set<Key, Compare, Alloc>>
+ : set_caster<std::set<Key, Compare, Alloc>, Key> { };
+
+template <typename Key, typename Hash, typename Equal, typename Alloc> struct type_caster<std::unordered_set<Key, Hash, Equal, Alloc>>
+ : set_caster<std::unordered_set<Key, Hash, Equal, Alloc>, Key> { };
+
+template <typename Key, typename Value, typename Compare, typename Alloc> struct type_caster<std::map<Key, Value, Compare, Alloc>>
+ : map_caster<std::map<Key, Value, Compare, Alloc>, Key, Value> { };
+
+template <typename Key, typename Value, typename Hash, typename Equal, typename Alloc> struct type_caster<std::unordered_map<Key, Value, Hash, Equal, Alloc>>
+ : map_caster<std::unordered_map<Key, Value, Hash, Equal, Alloc>, Key, Value> { };
+
NAMESPACE_END(detail)
inline std::ostream &operator<<(std::ostream &os, const handle &obj) {