[niepce] base: add fwk::option<> and use it in PropertyBag



commit d7ba6c44a80c338008f00e25d648430043d28ca4
Author: Hubert Figuière <hub figuiere net>
Date:   Tue Mar 14 00:01:21 2017 -0400

    base: add fwk::option<> and use it in PropertyBag

 .gitignore                            |    1 +
 src/fwk/base/Makefile.am              |    9 +++-
 src/fwk/base/option.hpp               |   72 +++++++++++++++++++++++++++++++++
 src/fwk/base/propertybag.cpp          |    9 ++--
 src/fwk/base/propertybag.hpp          |    5 +-
 src/fwk/base/t/testoption.cpp         |   67 ++++++++++++++++++++++++++++++
 src/fwk/toolkit/metadatawidget.cpp    |   16 ++++----
 src/niepce/modules/map/mapmodule.cpp  |   11 +++--
 src/niepce/ui/selectioncontroller.cpp |   15 ++++---
 9 files changed, 178 insertions(+), 27 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index 86cbb14..a525378 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,6 +42,7 @@ src/fwk/base/testgeometry
 src/fwk/base/testfractions
 src/fwk/base/testdate
 src/fwk/base/testmap
+src/fwk/base/testoption
 src/fwk/base/testpropertybag
 src/fwk/utils/test_db
 src/fwk/utils/test_db2
diff --git a/src/fwk/base/Makefile.am b/src/fwk/base/Makefile.am
index 4015ac4..b855bfa 100644
--- a/src/fwk/base/Makefile.am
+++ b/src/fwk/base/Makefile.am
@@ -8,10 +8,10 @@ noinst_LIBRARIES = libfwkbase.a
 
 
 TESTS = testmoniker testgeometry testfractions testdate testmap\
-       testpropertybag
+       testoption testpropertybag
 
 check_PROGRAMS = testmoniker testgeometry testfractions testdate testmap\
-       testpropertybag
+       testoption testpropertybag
 
 testdate_SOURCES = t/testdate.cpp
 testdate_LDADD = libfwkbase.a \
@@ -33,6 +33,10 @@ testmap_SOURCES = t/testmap.cpp
 testmap_LDADD = libfwkbase.a \
        @FRAMEWORK_LIBS@
 
+testoption_SOURCES = t/testoption.cpp
+testoption_LDADD = libfwkbase.a \
+       @FRAMEWORK_LIBS@
+
 testpropertybag_SOURCES = t/testpropertybag.cpp
 testpropertybag_LDADD = libfwkbase.a \
        @FRAMEWORK_LIBS@
@@ -47,5 +51,6 @@ libfwkbase_a_SOURCES = colour.hpp colour.cpp \
        singleton.hpp \
        util.hpp \
        map.hpp \
+       option.hpp \
        propertybag.hpp propertybag.cpp \
        $(NULL)
diff --git a/src/fwk/base/option.hpp b/src/fwk/base/option.hpp
new file mode 100644
index 0000000..76df967
--- /dev/null
+++ b/src/fwk/base/option.hpp
@@ -0,0 +1,72 @@
+/* -*- mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode:nil; -*- */
+/*
+ * niepce - fwk/base/option.hpp
+ *
+ * Copyright (C) 2017 Hubert Figuière
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+// an option<> template class inspired by Rust
+
+#pragma once
+
+#include <stdexcept>
+
+namespace fwk {
+
+template<class T>
+class Option
+{
+public:
+  typedef T data_type;
+
+  Option()
+    : m_none(true)
+  {
+  }
+  Option(T&& data)
+    : m_none(false)
+    , m_data(data)
+  {
+  }
+  Option(const T& data)
+    : m_none(false)
+    , m_data(data)
+  {
+  }
+  template<class... Args>
+  Option(Args&&... args)
+    : m_none(false)
+    , m_data(args...)
+  {
+  }
+
+  T&& unwrap()
+  {
+    if (m_none) {
+      throw std::runtime_error("none option value");
+    }
+    m_none = true;
+    return std::move(m_data);
+  }
+  bool empty() const
+  { return m_none; }
+private:
+  bool m_none;
+  T m_data;
+};
+
+
+}
diff --git a/src/fwk/base/propertybag.cpp b/src/fwk/base/propertybag.cpp
index 61eccf4..64b6072 100644
--- a/src/fwk/base/propertybag.cpp
+++ b/src/fwk/base/propertybag.cpp
@@ -1,7 +1,7 @@
 /*
  * niepce - fwk/base/propertybag.cpp
  *
- * Copyright (C) 2011-2013 Hubert Figuiere
+ * Copyright (C) 2011-2017 Hubert Figuiere
  *
  * 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
@@ -55,15 +55,14 @@ bool PropertyBag::set_value_for_property(PropertyIndex idx, const PropertyValue
     return removed;
 }
 
-/** return true if a property is found */
-bool PropertyBag::get_value_for_property(PropertyIndex idx, PropertyValue & value) const
+/** return an option */
+fwk::Option<PropertyValue> PropertyBag::get_value_for_property(PropertyIndex idx) const
 {
     _Map::const_iterator iter = m_bag.find(idx);
     if(iter == m_bag.end()) {
         return false;
     }
-    value = iter->second;
-    return true;
+    return fwk::Option<PropertyValue>(iter->second);
 }
 
 bool PropertyBag::has_value_for_property(PropertyIndex idx) const
diff --git a/src/fwk/base/propertybag.hpp b/src/fwk/base/propertybag.hpp
index 74d2aa5..111689a 100644
--- a/src/fwk/base/propertybag.hpp
+++ b/src/fwk/base/propertybag.hpp
@@ -29,6 +29,7 @@
 #include <boost/variant.hpp>
 
 #include "fwk/base/date.hpp"
+#include "fwk/base/option.hpp"
 
 namespace fwk {
 
@@ -88,8 +89,8 @@ public:
 
     /** return true if a property was removed prior to insertion */
     bool set_value_for_property(PropertyIndex idx, const PropertyValue & value);
-    /** return true if a property is found */
-    bool get_value_for_property(PropertyIndex idx, PropertyValue & value) const;
+    /** return property or an empty option */
+    fwk::Option<PropertyValue> get_value_for_property(PropertyIndex idx) const;
     /** return true if property exist */
     bool has_value_for_property(PropertyIndex idx) const;
     /** return true if the property was removed */
diff --git a/src/fwk/base/t/testoption.cpp b/src/fwk/base/t/testoption.cpp
new file mode 100644
index 0000000..015df02
--- /dev/null
+++ b/src/fwk/base/t/testoption.cpp
@@ -0,0 +1,67 @@
+/*
+ * niepce - fwk/base/t/testoption.cpp
+ *
+ * Copyright (C) 2017 Hubert Figuiere
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+/** @brief unit test for option */
+
+#include <boost/test/minimal.hpp>
+
+#include <stdlib.h>
+
+#include <string>
+
+#include "fwk/base/option.hpp"
+
+int test_main( int, char *[] )             // note the name!
+{
+  fwk::Option<std::string> result;
+
+  // Default, option is empty
+  BOOST_CHECK(result.empty());
+  bool unwrapped = false;
+  try {
+    result.unwrap();
+    unwrapped = true;
+  } catch(std::runtime_error&) {
+    BOOST_CHECK(true);
+  } catch(...) {
+    BOOST_CHECK(false);
+  }
+  BOOST_CHECK(!unwrapped);
+  BOOST_CHECK(result.empty());
+
+  // Option with value
+  result = fwk::Option<std::string>("hello world");
+  BOOST_CHECK(!result.empty());
+  BOOST_CHECK(result.unwrap() == "hello world");
+  BOOST_CHECK(result.empty());
+  // try unwrapping again
+  unwrapped = false;
+  try {
+    result.unwrap();
+    unwrapped = true;
+  } catch(std::runtime_error&) {
+    BOOST_CHECK(true);
+  } catch(...) {
+    BOOST_CHECK(false);
+  }
+  BOOST_CHECK(!unwrapped);
+  BOOST_CHECK(result.empty());
+
+  return 0;
+}
+
diff --git a/src/fwk/toolkit/metadatawidget.cpp b/src/fwk/toolkit/metadatawidget.cpp
index c3f98fd..6852312 100644
--- a/src/fwk/toolkit/metadatawidget.cpp
+++ b/src/fwk/toolkit/metadatawidget.cpp
@@ -1,7 +1,7 @@
 /*
  * niepce - fwk/toolkit/metadatawidget.cpp
  *
- * Copyright (C) 2008-2013 Hubert Figuiere
+ * Copyright (C) 2008-2017 Hubert Figuiere
  *
  * 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
@@ -241,9 +241,9 @@ void MetaDataWidget::set_data_source(const fwk::PropertyBag & properties)
 
     const MetaDataFormat * current = m_fmt->formats;
     while(current && current->label) {
-        PropertyValue v;
-        if(properties.get_value_for_property(current->id, v) || !current->readonly) {
-            add_data(current, v);
+        auto result = properties.get_value_for_property(current->id);
+        if(!result.empty() || !current->readonly) {
+            add_data(current, result.unwrap());
         }
         else {
             DBG_OUT("get_property failed id = %d, label = %s",
@@ -474,14 +474,14 @@ void MetaDataWidget::on_int_changed(int value, fwk::PropertyIndex prop)
     emit_metadata_changed(prop, fwk::PropertyValue(value));
 }
 
-void MetaDataWidget::emit_metadata_changed(fwk::PropertyIndex prop, 
+void MetaDataWidget::emit_metadata_changed(fwk::PropertyIndex prop,
                                            const fwk::PropertyValue & value)
 {
     fwk::PropertyBag props, old_props;
     props.set_value_for_property(prop, value);
-    fwk::PropertyValue old_value;
-    if(m_current_data.get_value_for_property(prop, old_value)) {
-        old_props.set_value_for_property(prop, old_value);
+    auto result = m_current_data.get_value_for_property(prop);
+    if (!result.empty()) {
+        old_props.set_value_for_property(prop, result.unwrap());
     }
     signal_metadata_changed.emit(props, old_props);
 }
diff --git a/src/niepce/modules/map/mapmodule.cpp b/src/niepce/modules/map/mapmodule.cpp
index 9ed8271..bfddc54 100644
--- a/src/niepce/modules/map/mapmodule.cpp
+++ b/src/niepce/modules/map/mapmodule.cpp
@@ -1,7 +1,7 @@
 /*
  * niepce - modules/map/mapmodule.cpp
  *
- * Copyright (C) 2014 Hubert Figuiere
+ * Copyright (C) 2014-2017 Hubert Figuiere
  *
  * 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
@@ -84,15 +84,18 @@ MapModule::on_lib_notification(const eng::LibNotification &ln)
             lm->to_properties(propset, properties);
             double latitude, longitude;
             latitude = longitude = NAN;
-            fwk::PropertyValue val;
-            if(properties.get_value_for_property(eng::NpExifGpsLongProp, val)) {
+            auto result = properties.get_value_for_property(eng::NpExifGpsLongProp);
+            if (!result.empty()) {
+                fwk::PropertyValue val = result.unwrap();
                 // it is a string
                 if (is_string(val)) {
                     longitude = fwk::XmpMeta::gpsCoordFromXmp(
                         fwk::get_string(val));
                 }
             }
-            if(properties.get_value_for_property(eng::NpExifGpsLatProp, val)) {
+            result = properties.get_value_for_property(eng::NpExifGpsLatProp);
+            if (!result.empty()) {
+                fwk::PropertyValue val = result.unwrap();
                 // it is a string
                 if (is_string(val)) {
                     latitude = fwk::XmpMeta::gpsCoordFromXmp(
diff --git a/src/niepce/ui/selectioncontroller.cpp b/src/niepce/ui/selectioncontroller.cpp
index cf7d2ba..65ba552 100644
--- a/src/niepce/ui/selectioncontroller.cpp
+++ b/src/niepce/ui/selectioncontroller.cpp
@@ -1,7 +1,7 @@
 /*
  * niepce - niepce/ui/selectioncontroller.cpp
  *
- * Copyright (C) 2008-2014 Hubert Figuiere
+ * Copyright (C) 2008-2017 Hubert Figuiere
  *
  * 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
@@ -217,11 +217,14 @@ bool SelectionController::_set_metadata(const std::string & undo_label,
     auto undo = fwk::Application::app()->begin_undo(undo_label);
     for(auto iter : props) {
         fwk::PropertyValue value;
-        old.get_value_for_property(iter.first, value);
+        auto result = old.get_value_for_property(iter.first);
 
-        if(value.type() != typeid(fwk::EmptyValue)) {
-            DBG_ASSERT(value.type() == iter.second.type(),
-                       "Value type mismatch");
+        if (!result.empty()) {
+            value = result.unwrap();
+            if(value.type() != typeid(fwk::EmptyValue)) {
+                DBG_ASSERT(value.type() == iter.second.type(),
+                           "Value type mismatch");
+            }
         }
 
         undo->new_command<void>(


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