[glom] C++11: Replace Glib::Regex with std::regex.



commit b9879fc9a42397c541b190dfc3a1e07b0051dca4
Author: Murray Cumming <murrayc murrayc com>
Date:   Tue Sep 1 11:55:01 2015 +0200

    C++11: Replace Glib::Regex with std::regex.
    
    Annoyingly:
    * the std::regex API can't just give us a vector of
    matches.
    * It lets us iterate through the matches, but not with a
    range-based for loop.
    * We have to iterate over sub-matches. I guess it could be useful
    to know what top-level strings are being used.
    * Iterating doesn't work normally because the first (0) sub match
    is really the full parent match.

 Makefile_tests.am                                  |    6 +
 glom/libglom/connectionpool_backends/mysql_self.cc |    1 -
 .../connectionpool_backends/postgres_self.cc       |  149 ++++++++++++--------
 .../connectionpool_backends/postgres_self.h        |    6 +
 tests/import/test_parsing.cc                       |   15 +-
 tests/test_postgres_version_regexes.cc             |   52 +++++++
 6 files changed, 162 insertions(+), 67 deletions(-)
---
diff --git a/Makefile_tests.am b/Makefile_tests.am
index f61b64d..94b1c17 100644
--- a/Makefile_tests.am
+++ b/Makefile_tests.am
@@ -27,6 +27,7 @@ check_PROGRAMS =                                              \
        tests/test_document_autosave                    \
        tests/test_field_file_format                    \
        tests/test_parsing_time                 \
+       tests/test_postgres_version_regexes \
        tests/test_signal_reemit                        \
        tests/python/test_load_python_library\
        tests/python/test_python_module \
@@ -68,6 +69,7 @@ TESTS =       tests/test_document_load        \
        tests/test_field_file_format \
        tests/test_field_file_format_in_locales.sh \
        tests/test_parsing_time \
+  tests/test_postgres_version_regexes \
        tests/test_signal_reemit \
        tests/test_dtd_file_validation.sh \
        tests/test_glade_file_validation.sh \
@@ -184,6 +186,10 @@ tests_test_parsing_time_SOURCES = tests/test_parsing_time.cc
 tests_test_parsing_time_LDADD = $(tests_ldadd)
 tests_test_parsing_time_CPPFLAGS = $(tests_cppflags)
 
+tests_test_postgres_version_regexes_SOURCES = tests/test_postgres_version_regexes.cc
+tests_test_postgres_version_regexes_LDADD = $(tests_ldadd)
+tests_test_postgres_version_regexes_CPPFLAGS = $(tests_cppflags)
+
 tests_test_signal_reemit_SOURCES = tests/test_signal_reemit.cc
 tests_test_signal_reemit_LDADD = $(LIBGLOM_LIBS)
 tests_test_signal_reemit_CPPFLAGS = $(tests_cppflags)
diff --git a/glom/libglom/connectionpool_backends/mysql_self.cc 
b/glom/libglom/connectionpool_backends/mysql_self.cc
index c9ca163..c63c0e2 100644
--- a/glom/libglom/connectionpool_backends/mysql_self.cc
+++ b/glom/libglom/connectionpool_backends/mysql_self.cc
@@ -31,7 +31,6 @@
 #include <glibmm/miscutils.h>
 #include <glibmm/stringutils.h>
 #include <glibmm/timer.h>
-#include <glibmm/regex.h>
 #include <glibmm/main.h>
 #include <glibmm/shell.h>
 #include <glibmm/i18n.h>
diff --git a/glom/libglom/connectionpool_backends/postgres_self.cc 
b/glom/libglom/connectionpool_backends/postgres_self.cc
index 9d13ba9..ec954c7 100644
--- a/glom/libglom/connectionpool_backends/postgres_self.cc
+++ b/glom/libglom/connectionpool_backends/postgres_self.cc
@@ -29,13 +29,13 @@
 #include <glibmm/convert.h>
 #include <glibmm/miscutils.h>
 #include <glibmm/stringutils.h>
-#include <glibmm/regex.h>
 #include <glibmm/main.h>
 #include <glibmm/shell.h>
 #include <glibmm/i18n.h>
 
 #include <sstream> //For stringstream
 #include <iostream>
+#include <regex>
 
 #ifdef G_OS_WIN32
 # include <windows.h>
@@ -225,107 +225,140 @@ Backend::InitErrors PostgresSelfHosted::initialize(const SlotProgress& slot_prog
   return result ? InitErrors::NONE : InitErrors::COULD_NOT_START_SERVER;
 }
 
-Glib::ustring PostgresSelfHosted::get_postgresql_utils_version(const SlotProgress& slot_progress)
+Glib::ustring PostgresSelfHosted::get_postgresql_utils_version_from_string(const std::string& version_output)
 {
   Glib::ustring result;
 
-  const auto command = get_path_to_postgres_executable("pg_ctl") + " --version";
-
-  //The first command does not return, but the second command can check whether it succeeded:
-  std::string output;
-  const auto spawn_result = Glom::Spawn::execute_command_line_and_wait(command, slot_progress, output);
-  if(!spawn_result)
-  {
-    std::cerr << G_STRFUNC << ": Error while attempting to discover the pg_ctl version." << std::endl;
-    return result;
-  }
-
   //Use a regex to get the version number:
-  Glib::RefPtr<Glib::Regex> regex;
-
+  std::regex regex;
+  
   //We want the characters at the end:
-  const gchar VERSION_REGEX[] = "pg_ctl \\(PostgreSQL\\) (.*)";
+  const gchar VERSION_REGEX[] = "pg_ctl \\(PostgreSQL\\) (\\S+)";
 
   try
   {
-    regex = Glib::Regex::create(VERSION_REGEX);
+    regex = std::regex(VERSION_REGEX);
   }
-  catch(const Glib::Error& ex)
+  catch(const std::regex_error& ex)
   {
-    std::cerr << G_STRFUNC << ": Glom: Glib::Regex::create() failed: " << ex.what() << std::endl;
+    std::cerr << G_STRFUNC << ": std::regex constructor() failed: " << ex.what() << std::endl;
     return result;
   }
 
-  if(!regex)
-    return result;
-
-  typedef std::vector<Glib::ustring> type_vec_strings;
-  const type_vec_strings vec = regex->split(output, Glib::REGEX_MATCH_NOTEMPTY);
-  //std::cout << "DEBUG: output == " << output << std::endl;
-  //std::cout << "DEBUG: vec.size() == " << vec.size() << std::endl;
-
   // We get, for instance, "\n" and 8.4.1" and "\n".
-  for(const auto& str : vec)
+  //TODO: Find a way to do a simple range-based for over the regex matches?
+  auto matches_begin = 
+    std::sregex_iterator(version_output.begin(), version_output.end(), regex);
+  auto matches_end = std::sregex_iterator();
+
+  for(auto iter = matches_begin; iter != matches_end; ++iter)
   {
-    if(!str.empty())
-      return str; //Found.
+    const auto match = *iter;
+
+    //We don't use a range-based for loop, so we can more easily
+    //skip the [0] match, which is the full (parent) match:
+    auto sub_matches_begin = match.cbegin();
+    ++sub_matches_begin; //Skip [0], which is the full (parent) match.
+    auto sub_matches_end = match.cend();
+    for(auto sub_iter = sub_matches_begin ; sub_iter != sub_matches_end; ++sub_iter)
+    {
+      const auto& sub = *sub_iter;
+      const auto str = sub.str();
+      //std::cout << "debug: str=" << str << std::endl;
+      if(!str.empty())
+        return str; //Found.
+    }
   }
 
   return result;
 }
 
-float PostgresSelfHosted::get_postgresql_utils_version_as_number(const SlotProgress& slot_progress)
+Glib::ustring PostgresSelfHosted::get_postgresql_utils_version(const SlotProgress& slot_progress)
 {
-  float result = 0;
+  Glib::ustring result;
 
-  const auto version_str = get_postgresql_utils_version(slot_progress);
+  const auto command = get_path_to_postgres_executable("pg_ctl") + " --version";
 
-  Glib::RefPtr<Glib::Regex> regex;
+  //The first command does not return, but the second command can check whether it succeeded:
+  std::string output;
+  const auto spawn_result = Glom::Spawn::execute_command_line_and_wait(command, slot_progress, output);
+  if(!spawn_result)
+  {
+    std::cerr << G_STRFUNC << ": Error while attempting to discover the pg_ctl version." << std::endl;
+    return Glib::ustring();
+  }
+
+  return get_postgresql_utils_version_from_string(output);
+}
+
+float PostgresSelfHosted::get_postgresql_utils_version_as_number_from_string(const std::string& version_str)
+{
+  //std::cout << "debug: " << G_STRFUNC << ": " << version_str << std::endl;
+
+  float result = 0;
+
+  std::regex regex;
 
   //We want the characters at the end:
-  const gchar VERSION_REGEX[] = "^(\\d*)\\.(\\d*)";
+  const gchar VERSION_REGEX[] = "(\\d*)\\.(\\d*)";
 
   try
   {
-    regex = Glib::Regex::create(VERSION_REGEX);
+    regex = std::regex(VERSION_REGEX);
   }
-  catch(const Glib::Error& ex)
+  catch(const std::regex_error& ex)
   {
-    std::cerr << G_STRFUNC << ": Glom: Glib::Regex::create() failed: " << ex.what() << std::endl;
+    std::cerr << G_STRFUNC << ": std::regex constructor() failed: " << ex.what() << std::endl;
     return result;
   }
 
-  if(!regex)
-    return result;
-
-  const auto vec = regex->split(version_str, Glib::REGEX_MATCH_NOTEMPTY);
-  //std::cout << "DEBUG: str == " << version_str << std::endl;
-  //std::cout << "DEBUG: vec.size() == " << vec.size() << std::endl;
-
   //We need to loop over the numbers because we get some "" items that we want to ignore:
   guint count = 0; //We want 2 numbers.
-  for(const auto& str : vec)
-  {
-    //std::cout << "regex item: START" << *iter << "END" << std::endl;
 
-    if(str.empty())
-      continue;
+  auto matches_begin = 
+    std::sregex_iterator(version_str.begin(), version_str.end(), regex);
+  auto matches_end = std::sregex_iterator();
 
-    const auto num = atoi(str.c_str());
-    if(count == 0)
-      result = num;
-    else if(count == 1)
+  for(auto iter = matches_begin; iter != matches_end; ++iter)
+  {
+    const auto match = *iter;
+    //std::cout << "match: START" << match.str() << "END" << std::endl;
+
+    //We don't use a range-based for loop, so we can more easily
+    //skip the [0] match, which is the full (parent) match:
+    auto sub_matches_begin = match.cbegin();
+    ++sub_matches_begin; //Skip [0], which is the full (parent) match.
+    auto sub_matches_end = match.cend();
+    for(auto sub_iter = sub_matches_begin ; sub_iter != sub_matches_end; ++sub_iter)
     {
-      result += (0.1 * num);
-      break;
-    }
+      const auto& sub = *sub_iter;
+      const auto str = sub.str();
+      if(str.empty())
+        continue;
+
+      const auto num = atoi(str.c_str());
+      if(count == 0)
+        result = num;
+      else if(count == 1)
+      {
+        result += (0.1 * num);
+        return result;
+      }
 
-    ++count;
+      ++count;
+    }
   }
 
   return result;
 }
 
+float PostgresSelfHosted::get_postgresql_utils_version_as_number(const SlotProgress& slot_progress)
+{
+  const std::string version_str = get_postgresql_utils_version(slot_progress);
+
+  return get_postgresql_utils_version_as_number_from_string(version_str);
+}
+
 
 Backend::StartupErrors PostgresSelfHosted::startup(const SlotProgress& slot_progress, bool network_shared)
 {
diff --git a/glom/libglom/connectionpool_backends/postgres_self.h 
b/glom/libglom/connectionpool_backends/postgres_self.h
index 1bd09f4..608e7ff 100644
--- a/glom/libglom/connectionpool_backends/postgres_self.h
+++ b/glom/libglom/connectionpool_backends/postgres_self.h
@@ -54,6 +54,12 @@ public:
    */
   static bool install_postgres(const SlotProgress& slot_progress);
 
+  ///This is public so it can be tested:
+  static Glib::ustring get_postgresql_utils_version_from_string(const std::string& version_output);
+
+  ///This is public so it can be tested:
+  static float get_postgresql_utils_version_as_number_from_string(const std::string& version_str);
+
 private:
   virtual InitErrors initialize(const SlotProgress& slot_progress, const Glib::ustring& initial_username, 
const Glib::ustring& password, bool network_shared = false);
 
diff --git a/tests/import/test_parsing.cc b/tests/import/test_parsing.cc
index 16f5edb..755c949 100644
--- a/tests/import/test_parsing.cc
+++ b/tests/import/test_parsing.cc
@@ -1,13 +1,12 @@
 #include <glom/import_csv/csv_parser.h>
 #include <tests/import/utils.h>
-//#include <glibmm/regex.h>
 #include <giomm/file.h>
 #include <glibmm/convert.h>
 #include <glibmm/miscutils.h>
-#include <glibmm/regex.h>
 #include <glibmm/init.h>
 #include <giomm/init.h>
 #include <iostream>
+#include <regex>
 #include <cstdlib>
 
 namespace
@@ -51,26 +50,26 @@ void print_tokens()
 // Check that a string (or regex) exists in the parsed tokens.
 bool check_tokens(const std::string& regex)
 {
-  Glib::RefPtr<Glib::Regex> check;
+  std::regex check;
 
   try
   {
-    check = Glib::Regex::create(regex);
+    check = std::regex(regex);
   }
-  catch(const Glib::Error& ex)
+  catch(const std::regex_error& ex)
   {
-    std::cerr << G_STRFUNC << ": Glib::Regex::create() failed: " << ex.what() << std::endl;
+    std::cerr << G_STRFUNC << ": std::regex constructor failed: " << ex.what() << std::endl;
     return false;
   }
 
-  if(!check && 0 == get_tokens_instance().size())
+  if(get_tokens_instance().empty())
     return false;
 
   for(type_tokens::const_iterator iter = get_tokens_instance().begin();
        iter != get_tokens_instance().end();
        ++iter)
   {
-    if(check->match(*iter))
+    if(std::regex_match(*iter, check))
       return true;
   }
 
diff --git a/tests/test_postgres_version_regexes.cc b/tests/test_postgres_version_regexes.cc
new file mode 100644
index 0000000..96232b6
--- /dev/null
+++ b/tests/test_postgres_version_regexes.cc
@@ -0,0 +1,52 @@
+/* Glom
+ *
+ * Copyright (C) 2015 Openismus GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+
+#include <glom/libglom/init.h>
+#include <glom/libglom/connectionpool_backends/postgres_self.h>
+#include <iostream>
+
+static bool test_postgres_utils_version()
+{
+  const auto str = 
Glom::ConnectionPoolBackends::PostgresSelfHosted::get_postgresql_utils_version_from_string("pg_ctl 
(PostgreSQL) 9.4.4");
+  //std::cout << "debug: str: " << str << std::endl;
+  return str == "9.4.4";
+}
+
+static bool test_postgres_utils_version_as_number()
+{
+  const auto number = 
Glom::ConnectionPoolBackends::PostgresSelfHosted::get_postgresql_utils_version_as_number_from_string("pg_ctl 
(PostgreSQL) 9.4.4");
+  //std::cout << "debug: number: " << number << std::endl;
+  return number == 9.4f;
+}
+
+int main()
+{
+  Glom::libglom_init();
+
+  if(! test_postgres_utils_version())
+    return EXIT_FAILURE;
+
+  if(!test_postgres_utils_version_as_number())
+    return EXIT_FAILURE;
+
+  Glom::libglom_deinit();
+
+  return EXIT_SUCCESS;
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]