Repository: cython/cython

Issue:
Return type of unordered_map erase methods should be iterator not void
The return type of unordered_map erase methods should be `iterator` not `void`, like in `vector`.

https://github.com/cython/cython/blob/master/Cython/Includes/libcpp/unordered_map.pxd#L45

C++ reference: http://en.cppreference.com/w/cpp/container/unordered_map/erase



Discussion:
Thanks. We'd welcome a PR with a test :). 

Ok, working on that :)

Created a PR for this https://github.com/cython/cython/pull/1490
I think it would be good to add more tests for `erase` method on other data structures.

Also, because `unordered_map` is from C++11, I don't know if it will compile on all platforms.

I added `-std=c++11` to `CXXFLAGS`

``` diff
(dev) carlos@macbookair:~/code/cython$ git diff HEAD
diff --git a/runtests.py b/runtests.py
index 0e0abf5..01f44a2 100755
--- a/runtests.py
+++ b/runtests.py
@@ -423,6 +423,7 @@ class build_ext(_build_ext):
                 compiler_obj = self.compiler
             if ext.language == 'c++':
                 compiler_obj.compiler_so.remove('-Wstrict-prototypes')
+                compiler_obj.compiler_so.append('-std=c++11')
             if CCACHE:
                 compiler_obj.compiler_so = CCACHE + compiler_obj.compiler_so
             if getattr(ext, 'openmp', None) and compiler_obj.compiler_type == 'msvc':
(dev) carlos@macbookair:~/code/cython$ 
```


Resolving patch:
diff --git a/runtests.py b/runtests.py
--- a/runtests.py
+++ b/runtests.py
@@ -71,7 +71,7 @@ def __nonzero__(self):
 
 from distutils.command.build_ext import build_ext as _build_ext
 from distutils import sysconfig
-
+from distutils import ccompiler
 _to_clean = []
 
 @atexit.register
@@ -240,7 +240,6 @@ def update_openmp_extension(ext):
 
     if flags:
         compile_flags, link_flags = flags
-
         ext.extra_compile_args.extend(compile_flags.split())
         ext.extra_link_args.extend(link_flags.split())
         return ext
@@ -249,21 +248,32 @@ def update_openmp_extension(ext):
 
     return EXCLUDE_EXT
 
-def get_openmp_compiler_flags(language):
+def update_cpp11_extension(ext):
     """
-    As of gcc 4.2, it supports OpenMP 2.5. Gcc 4.4 implements 3.0. We don't
-    (currently) check for other compilers.
+        update cpp11 extensions that will run on versions of gcc >4.8
+    """
+    gcc_version = get_gcc_version(ext.language)
+    compiler_version = gcc_version.group(1)
+    if gcc_version is not None:
+        compiler_version = gcc_version.group(1)
+        if float(compiler_version) > 4.8:
+            ext.extra_compile_args.extend("-std=c++11")
+        return ext    
+    return EXCLUDE_EXT
 
-    returns a two-tuple of (CFLAGS, LDFLAGS) to build the OpenMP extension
+
+def get_gcc_version(language):
+    """
+        finds gcc version using Popen
     """
     if language == 'cpp':
         cc = sysconfig.get_config_var('CXX')
     else:
         cc = sysconfig.get_config_var('CC')
+    if not cc:
+       cc = ccompiler.get_default_compiler()
 
     if not cc:
-        if sys.platform == 'win32':
-            return '/openmp', ''
         return None
 
     # For some reason, cc can be e.g. 'gcc -pthread'
@@ -272,7 +282,6 @@ def get_openmp_compiler_flags(language):
     # Force english output
     env = os.environ.copy()
     env['LC_MESSAGES'] = 'C'
-
     matcher = re.compile(r"gcc version (\d+\.\d+)").search
     try:
         p = subprocess.Popen([cc, "-v"], stderr=subprocess.PIPE, env=env)
@@ -282,12 +291,25 @@ def get_openmp_compiler_flags(language):
                       (language, os.strerror(sys.exc_info()[1].errno), cc))
         return None
     _, output = p.communicate()
-
     output = output.decode(locale.getpreferredencoding() or 'ASCII', 'replace')
-
     gcc_version = matcher(output)
+    return gcc_version
+
+
+def get_openmp_compiler_flags(language):
+    """
+    As of gcc 4.2, it supports OpenMP 2.5. Gcc 4.4 implements 3.0. We don't
+    (currently) check for other compilers.
+
+    returns a two-tuple of (CFLAGS, LDFLAGS) to build the OpenMP extension
+    """
+    gcc_version = get_gcc_version(language)
+
     if not gcc_version:
-        return None # not gcc - FIXME: do something about other compilers
+        if sys.platform == 'win32':
+            return '/openmp', ''
+        else:
+            return None # not gcc - FIXME: do something about other compilers
 
     # gcc defines "__int128_t", assume that at least all 64 bit architectures have it
     global COMPILER_HAS_INT128
@@ -313,6 +335,7 @@ def get_openmp_compiler_flags(language):
 EXT_EXTRAS = {
     'tag:numpy' : update_numpy_extension,
     'tag:openmp': update_openmp_extension,
+    'tag:cpp11': update_cpp11_extension,
     'tag:trace' : update_linetrace_extension,
 }
 


Test patch:
diff --git a/tests/run/cpp_stl_cpp11.pyx b/tests/run/cpp_stl_cpp11.pyx
new file mode 100644
--- /dev/null
+++ b/tests/run/cpp_stl_cpp11.pyx
@@ -0,0 +1,30 @@
+# mode: run
+# tag: cpp, werror, cpp11
+# distutils: extra_compile_args=-std=c++0x
+
+import sys
+from libcpp.unordered_map cimport unordered_map
+from libcpp.pair cimport pair
+
+def test_unordered_map_functionality():
+    """
+    >>> test_unordered_map_functionality()
+    'pass'
+    """
+    cdef:
+        unordered_map[int, int] int_map = unordered_map[int,int]()
+        pair[int, int] pair_insert = pair[int, int](1, 2)
+        unordered_map[int,int].iterator iterator = int_map.begin()
+        pair[unordered_map[int,int].iterator, bint] pair_iter  = int_map.insert(pair_insert)
+    assert int_map[1] == 2
+    assert int_map.size() == 1
+    assert int_map.erase(1) == 1 # returns number of elements erased
+    assert int_map.size() == 0
+    int_map[1] = 2
+    assert int_map.size() == 1
+    assert int_map[1] == 2
+    iterator = int_map.find(1)
+    assert int_map.erase(iterator) == int_map.end()
+    return "pass"
+
+