[pan2] Changed a deque<FilterInfo> into a deque<FilterInfo *>



commit 0b399ecfd28bf6018cf3e24a9c1e4a24ddb0f662
Author: Olaf Seibert <rhialto falu nl>
Date:   Sun Mar 6 22:46:33 2016 +0100

    Changed a deque<FilterInfo> into a deque<FilterInfo *>
    
    and adjust everything that the compiler now dislikes.
    To fix the memory management (the pointed-to objects should be copied
    too), use the copy-and-swap-idiom.

 pan/data-impl/article-filter.cc |   12 +++---
 pan/gui/header-pane.cc          |   81 ++++++++++++++++++++-------------------
 pan/usenet-utils/filter-info.cc |   65 +++++++++++++++++++++++++++----
 pan/usenet-utils/filter-info.h  |   19 ++++++++-
 pan/usenet-utils/scorefile.cc   |   26 ++++++------
 5 files changed, 133 insertions(+), 70 deletions(-)
---
diff --git a/pan/data-impl/article-filter.cc b/pan/data-impl/article-filter.cc
index effdf69..b0380aa 100644
--- a/pan/data-impl/article-filter.cc
+++ b/pan/data-impl/article-filter.cc
@@ -62,10 +62,10 @@ ArticleFilter :: test_article (const Data        & data,
   {
     case FilterInfo::AGGREGATE_AND:
       pass = true;
-      foreach_const (FilterInfo::aggregates_t, criteria._aggregates, it) {
+      foreach_const (FilterInfo::aggregatesp_t, criteria._aggregates, it) {
         // assume test passes if test needs body but article not cached
-        if (!it->_needs_body || cache.contains(article.message_id) )
-          if (!test_article (data, *it, group, article)) {
+        if (!(*it)->_needs_body || cache.contains(article.message_id) )
+          if (!test_article (data, **it, group, article)) {
             pass = false;
             break;
           }
@@ -77,10 +77,10 @@ ArticleFilter :: test_article (const Data        & data,
         pass = true;
       else {
         pass = false;
-        foreach_const (FilterInfo::aggregates_t, criteria._aggregates, it) {
+        foreach_const (FilterInfo::aggregatesp_t, criteria._aggregates, it) {
           // assume test fails if test needs body but article not cached
-          if (!it->_needs_body || cache.contains(article.message_id) )
-            if (test_article (data, *it, group, article)) {
+          if (!(*it)->_needs_body || cache.contains(article.message_id) )
+            if (test_article (data, **it, group, article)) {
               pass = true;
               break;
             }
diff --git a/pan/gui/header-pane.cc b/pan/gui/header-pane.cc
index 81192fe..3b4c3fa 100644
--- a/pan/gui/header-pane.cc
+++ b/pan/gui/header-pane.cc
@@ -1390,62 +1390,62 @@ HeaderPane :: rebuild_filter (const std::string& text, int mode)
   f.set_type_aggregate_and ();
 
   // entry field filter...
-  FilterInfo entry_filter;
   if (!text.empty())
   {
+    FilterInfo *entry_filter = new FilterInfo;
     if (mode == SUBJECT)
-      entry_filter.set_type_text ("Subject", d);
+      entry_filter->set_type_text ("Subject", d);
     else if (mode == AUTHOR)
-      entry_filter.set_type_text ("From", d);
+      entry_filter->set_type_text ("From", d);
     else if (mode == MESSAGE_ID)
-      entry_filter.set_type_text ("Message-ID", d);
+      entry_filter->set_type_text ("Message-ID", d);
     else if (mode == SUBJECT_OR_AUTHOR) {
-      FilterInfo f1, f2;
-      entry_filter.set_type_aggregate_or ();
-      f1.set_type_text ("Subject", d);
-      f2.set_type_text ("From", d);
-      entry_filter._aggregates.push_back (f1);
-      entry_filter._aggregates.push_back (f2);
+      FilterInfo *f1 = new FilterInfo, *f2 = new FilterInfo;
+      entry_filter->set_type_aggregate_or ();
+      f1->set_type_text ("Subject", d);
+      f2->set_type_text ("From", d);
+      entry_filter->_aggregates.push_back (f1);
+      entry_filter->_aggregates.push_back (f2);
     } else if (mode == SUBJECT_OR_AUTHOR_REGEX) {
-      FilterInfo f1, f2;
-      entry_filter.set_type_aggregate_or ();
+      FilterInfo *f1 = new FilterInfo, *f2 = new FilterInfo;
+      entry_filter->set_type_aggregate_or ();
       d.type = TextMatch::REGEX;
-      f1.set_type_text ("Subject", d);
-      f2.set_type_text ("From", d);
-      entry_filter._aggregates.push_back (f1);
-      entry_filter._aggregates.push_back (f2);
+      f1->set_type_text ("Subject", d);
+      f2->set_type_text ("From", d);
+      entry_filter->_aggregates.push_back (f1);
+      entry_filter->_aggregates.push_back (f2);
     }
     f._aggregates.push_back (entry_filter);
   }
 
   if (_action_manager.is_action_active("match-only-read-articles")) {
 //std::cerr << LINE_ID << " AND is read" << std::endl;
-    FilterInfo tmp;
-    tmp.set_type_is_read ();
+    FilterInfo *tmp = new FilterInfo;
+    tmp->set_type_is_read ();
     f._aggregates.push_back (tmp);
   }
   if (_action_manager.is_action_active("match-only-unread-articles")) {
 //std::cerr << LINE_ID << " AND is unread" << std::endl;
-    FilterInfo tmp;
-    tmp.set_type_is_unread ();
+    FilterInfo *tmp = new FilterInfo;
+    tmp->set_type_is_unread ();
     f._aggregates.push_back (tmp);
   }
   if (_action_manager.is_action_active("match-only-cached-articles")) {
 //std::cerr << LINE_ID << " AND is cached" << std::endl;
-    FilterInfo tmp;
-    tmp.set_type_cached ();
+    FilterInfo *tmp = new FilterInfo;
+    tmp->set_type_cached ();
     f._aggregates.push_back (tmp);
   }
   if (_action_manager.is_action_active("match-only-binary-articles")) {
 //std::cerr << LINE_ID << " AND has an attachment" << std::endl;
-    FilterInfo tmp;
-    tmp.set_type_binary ();
+    FilterInfo *tmp = new FilterInfo;
+    tmp->set_type_binary ();
     f._aggregates.push_back (tmp);
   }
   if (_action_manager.is_action_active("match-only-my-articles")) {
 //std::cerr << LINE_ID << " AND was posted by me" << std::endl;
-    FilterInfo tmp;
-    tmp.set_type_posted_by_me ();
+    FilterInfo *tmp = new FilterInfo;
+    tmp->set_type_posted_by_me ();
     f._aggregates.push_back (tmp);
   }
 
@@ -1474,7 +1474,7 @@ HeaderPane :: rebuild_filter (const std::string& text, int mode)
 
 //for (size_t i=0; i<ranges.size(); ++i) std::cerr << LINE_ID << " range [" << ranges[i].first << "..." << 
ranges[i].second << "]" << std::endl;
 
-  std::deque<FilterInfo> filters;
+  std::deque<FilterInfo *> filters;
   for (size_t i=0; i<ranges.size(); ++i) {
     const range_t& range (ranges[i]);
     const bool low_bound (range.first == INT_MIN);
@@ -1482,22 +1482,23 @@ HeaderPane :: rebuild_filter (const std::string& text, int mode)
     if (low_bound && hi_bound) {
       // everything matches -- do nothing
     } else if (hi_bound) {
-      FilterInfo tmp;
-      tmp.set_type_score_ge (range.first);
+      FilterInfo *tmp = new FilterInfo;
+      tmp->set_type_score_ge (range.first);
 //std::cerr << LINE_ID << " AND has a score >= " << range.first << std::endl;
       filters.push_back (tmp);
     } else if (low_bound) {
-      FilterInfo tmp;
-      tmp.set_type_score_le (range.second);
+      FilterInfo *tmp = new FilterInfo;
+      tmp->set_type_score_le (range.second);
 //std::cerr << LINE_ID << " AND has a score <= " << range.second << std::endl;
       filters.push_back (tmp);
     } else  { // not bound on either side; need an aggregate
-      FilterInfo s, tmp;
-      s.set_type_aggregate_and ();
-      tmp.set_type_score_ge (range.first);
-      s._aggregates.push_back (tmp);
-      tmp.set_type_score_le (range.second);
-      s._aggregates.push_back (tmp);
+      FilterInfo *tmp = new FilterInfo;
+      FilterInfo *s = new FilterInfo;
+      s->set_type_aggregate_and ();
+      tmp->set_type_score_ge (range.first);
+      s->_aggregates.push_back (tmp);
+      tmp->set_type_score_le (range.second);
+      s->_aggregates.push_back (tmp);
 //std::cerr << LINE_ID << " AND has a in [" << range.first << "..." << range.second << ']' << std::endl;
       filters.push_back (s);
     }
@@ -1505,9 +1506,9 @@ HeaderPane :: rebuild_filter (const std::string& text, int mode)
   if (filters.size()==1) // can fit in an `and' parent
     f._aggregates.push_back (filters[0]);
   else if (!filters.empty()) { // needs an `or' parent
-    FilterInfo s;
-    s.set_type_aggregate_or ();
-    s._aggregates.swap (filters);
+    FilterInfo *s = new FilterInfo;
+    s->set_type_aggregate_or ();
+    s->_aggregates.swap (filters);
     f._aggregates.push_back (s);
   }
 //std::cerr << LINE_ID << " number of filters: " << f._aggregates.size() << std::endl;
diff --git a/pan/usenet-utils/filter-info.cc b/pan/usenet-utils/filter-info.cc
index 21e525c..7fd7906 100644
--- a/pan/usenet-utils/filter-info.cc
+++ b/pan/usenet-utils/filter-info.cc
@@ -31,6 +31,52 @@ using namespace pan;
 ****
 ***/
 
+/*
+ * Copy-and-swap idiom according to
+ * http://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom
+ */
+
+FilterInfo :: FilterInfo (const FilterInfo &that)
+  : _type(that._type)
+  , _ge(that._ge)
+  , _header(that._header)
+  , _text(that._text)
+  , _negate(that._negate)
+  , _needs_body(that._needs_body)
+{
+  foreach_const (aggregatesp_t, that._aggregates, it) {
+    _aggregates.push_back (new FilterInfo(**it));
+  }
+}
+
+void
+swap (FilterInfo &first, FilterInfo &second)
+{
+  using std::swap;
+
+  swap (first._type,       second._type);
+  swap (first._ge,         second._ge);
+  swap (first._header,     second._header);
+  swap (first._text,       second._text);
+  swap (first._aggregates, second._aggregates);
+  swap (first._negate,     second._negate);
+  swap (first._needs_body, second._needs_body);
+}
+
+FilterInfo &FilterInfo::operator = (FilterInfo other)
+{
+  swap (*this, other);
+
+  return *this;
+}
+
+FilterInfo :: ~FilterInfo ()
+{
+  foreach (aggregatesp_t, _aggregates, it) {
+    delete *it;
+  }
+}
+
 void
 FilterInfo :: clear ()
 {
@@ -38,6 +84,9 @@ FilterInfo :: clear ()
   _ge = 0;
   _header.clear ();
   _text.clear ();
+  foreach (aggregatesp_t, _aggregates, it) {
+    delete *it;
+  }
   _aggregates.clear ();
   _negate = false;
   _needs_body = false;
@@ -289,29 +338,29 @@ FilterInfo :: describe () const
   {
     ret = _("Any of these tests fail:");
     ret += "\n";
-    foreach_const (aggregates_t, _aggregates, it)
-      ret += "   " + it->describe() + "\n";
+    foreach_const (aggregatesp_t, _aggregates, it)
+      ret += "   " + (*it)->describe() + "\n";
   }
   else if (_type==AGGREGATE_AND)
   {
     ret = _("All of these tests pass:");
     ret += "\n";
-    foreach_const (aggregates_t, _aggregates, it)
-      ret += "   " + it->describe() + "\n";
+    foreach_const (aggregatesp_t, _aggregates, it)
+      ret += "   " + (*it)->describe() + "\n";
   }
   else if (_type==AGGREGATE_OR && _negate)
   {
     ret = _("None of these tests pass:");
     ret += "\n";
-    foreach_const (aggregates_t, _aggregates, it)
-      ret += "   " + it->describe() + "\n";
+    foreach_const (aggregatesp_t, _aggregates, it)
+      ret += "   " + (*it)->describe() + "\n";
   }
   else if (_type==AGGREGATE_OR)
   {
     ret = _("Any of these tests pass:");
     ret += "\n";
-    foreach_const (aggregates_t, _aggregates, it)
-      ret += "   " + it->describe() + "\n";
+    foreach_const (aggregatesp_t, _aggregates, it)
+      ret += "   " + (*it)->describe() + "\n";
   }
 
   return ret;
diff --git a/pan/usenet-utils/filter-info.h b/pan/usenet-utils/filter-info.h
index 32e3967..871a8aa 100644
--- a/pan/usenet-utils/filter-info.h
+++ b/pan/usenet-utils/filter-info.h
@@ -25,6 +25,16 @@
 #include <pan/general/string-view.h>
 #include <pan/general/text-match.h>
 
+/**
+ * Pre-declaring swap(...) is a bit involved, given the use
+ * of the namespace pan and it needs to be outside.
+ */
+namespace pan {
+  class FilterInfo;
+};
+
+void swap(pan::FilterInfo &first, pan::FilterInfo &second);
+
 namespace pan
 {
   /**
@@ -56,7 +66,10 @@ namespace pan
     public:
       bool empty() const { return _type == TYPE_ERR; }
       FilterInfo () { clear(); }
-      virtual ~FilterInfo () { }
+      FilterInfo (const FilterInfo &that);
+      friend void ::swap(FilterInfo &first, FilterInfo &second);
+      FilterInfo &operator = (FilterInfo other);
+      virtual ~FilterInfo ();
 
     public:
 
@@ -74,11 +87,11 @@ namespace pan
       TextMatch _text;
 
       /** Convenience typedef. */
-      typedef std::deque<FilterInfo> aggregates_t;
+      typedef std::deque<FilterInfo *> aggregatesp_t;
 
       /** When `_type' is AGGREGATE_OR or AGGREGATE_AND,
           these are the filters being or'ed or and'ed together. */
-      aggregates_t _aggregates;
+      aggregatesp_t _aggregates;
 
       /** When this is true, the results of the test should be negated. */
       bool _negate;
diff --git a/pan/usenet-utils/scorefile.cc b/pan/usenet-utils/scorefile.cc
index ac9d68c..0e0b979 100644
--- a/pan/usenet-utils/scorefile.cc
+++ b/pan/usenet-utils/scorefile.cc
@@ -103,7 +103,7 @@ struct pan::Scorefile::ParseContext
       test = &item->test;
     if (test)
       foreach_const (std::vector<int>, test_offsets, it)
-        test = &test->_aggregates[*it];
+        test = test->_aggregates[*it];
     return test;
   }
 
@@ -258,11 +258,11 @@ Scorefile :: parse_file (ParseContext& context, const StringView& filename)
 
       line.eat_chars (1); // skip past the '{'
       const bool only_one_test_must_pass (line.len>=2 && !memcmp(line.str,"::",2));
-      FilterInfo test;
+      FilterInfo *test = new FilterInfo;
       if (only_one_test_must_pass)
-        test.set_type_aggregate_or ();
+        test->set_type_aggregate_or ();
       else
-        test.set_type_aggregate_and ();
+        test->set_type_aggregate_and ();
 
       FilterInfo * parent (context.get_current_test ());
       context.test_offsets.push_back (parent->_aggregates.size());
@@ -331,9 +331,9 @@ Scorefile :: parse_file (ParseContext& context, const StringView& filename)
       StringView val (line.substr (delimiter+1, 0));
       val.trim ();
 
-      FilterInfo::aggregates_t& aggregates (context.get_current_test()->_aggregates);
-      aggregates.resize (aggregates.size() + 1);
-      FilterInfo& test (aggregates.back());
+      FilterInfo::aggregatesp_t& aggregates (context.get_current_test()->_aggregates);
+      aggregates.push_back (new FilterInfo);
+      FilterInfo& test (*aggregates.back());
  
       if (!key.strncasecmp ("Lines", 5))
       {
@@ -390,14 +390,14 @@ Scorefile :: parse_file (ParseContext& context, const StringView& filename)
 
 namespace
 {
-  void normalize_test (FilterInfo& test)
+  void normalize_test (FilterInfo *test)
   {
-    if ((test._type!=test.AGGREGATE_AND) && (test._type!=test.AGGREGATE_OR))
+    if ((test->_type!=test->AGGREGATE_AND) && (test->_type!=test->AGGREGATE_OR))
       return;
 
-    if (test._aggregates.size() == 1)
-      test = test._aggregates[0];
-    else foreach (FilterInfo::aggregates_t, test._aggregates, it)
+    if (test->_aggregates.size() == 1) {
+      *test = *test->_aggregates[0];
+    } else foreach (FilterInfo::aggregatesp_t, test->_aggregates, it)
       normalize_test (*it);
   }
 }
@@ -418,7 +418,7 @@ Scorefile :: parse_file (const StringView& filename)
 
   foreach (sections_t, _sections, sit)
     foreach (items_t, sit->items, it)
-      normalize_test (it->test);
+      normalize_test (&it->test);
 
   size_t item_count (0);
   foreach (sections_t, _sections, sit)


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