Fix unarchiving empty containers.
authorRichard Kreckel <kreckel@ginac.de>
Sun, 22 Sep 2019 17:18:19 +0000 (19:18 +0200)
committerRichard Kreckel <kreckel@ginac.de>
Sun, 22 Sep 2019 17:18:19 +0000 (19:18 +0200)
The bug was reported by Vladimir V. Kisil <kisilv@maths.leeds.ac.uk>, see
<https://www.ginac.de/pipermail/ginac-devel/2019-September/002399.html>.

ginac/archive.cpp
ginac/archive.h
ginac/container.h
ginac/expairseq.cpp
ginac/matrix.cpp
ginac/pseries.cpp

index eb50e86..5fa5d1f 100644 (file)
@@ -357,17 +357,17 @@ bool archive_node::has_same_ex_as(const archive_node &other) const
 }
 
 archive_node::archive_node_cit
-               archive_node::find_first(const std::string &name) const
-{      
+archive_node::find_first(const std::string &name) const
+{
        archive_atom name_atom = a.atomize(name);
        for (auto i=props.begin(); i!=props.end(); ++i)
                if (i->name == name_atom)
                        return i;
-       return props.end();;
+       return props.end();
 }
 
 archive_node::archive_node_cit
-               archive_node::find_last(const std::string &name) const
+archive_node::find_last(const std::string &name) const
 {
        archive_atom name_atom = a.atomize(name);
        for (auto i=props.end(); i!=props.begin();) {
@@ -378,6 +378,23 @@ archive_node::archive_node_cit
        return props.end();
 }
 
+archive_node::archive_node_cit_range
+archive_node::find_property_range(const std::string &name1, const std::string &name2) const
+{
+       archive_atom name1_atom = a.atomize(name1),
+                    name2_atom = a.atomize(name2);
+       archive_node_cit_range range = {props.end(), props.end()};
+       for (auto i=props.begin(); i!=props.end(); ++i) {
+               if (i->name == name1_atom && range.begin == props.end()) {
+                       range.begin = i;
+               }
+               if (i->name == name2_atom && range.begin != props.end()) {
+                       range.end = i + 1;
+               }
+       }
+       return range;
+}
+
 void archive_node::add_bool(const std::string &name, bool value)
 {
        props.push_back(property(a.atomize(name), PTYPE_BOOL, value));
@@ -455,8 +472,7 @@ bool archive_node::find_string(const std::string &name, std::string &ret, unsign
        return false;
 }
 
-void archive_node::find_ex_by_loc(archive_node_cit loc, ex &ret, lst &sym_lst)
-               const
+void archive_node::find_ex_by_loc(archive_node_cit loc, ex &ret, lst &sym_lst) const
 {
        ret = a.get_node(loc->value).unarchive(sym_lst);
 }
@@ -517,7 +533,7 @@ void archive_node::get_properties(propinfovector &v) const
                if (!found)
                        v.push_back(property_info(type, name));
                i++;
-       }       
+       }
 }
 
 static synthesize_func find_factory_fcn(const std::string& name)
index 53c4543..c3314f1 100644 (file)
@@ -82,6 +82,9 @@ public:
                unsigned value;     /**< Stored value. */
        };
        typedef std::vector<property>::const_iterator archive_node_cit;
+       struct archive_node_cit_range {
+               archive_node_cit begin, end;
+       };
 
        archive_node(archive &ar) : a(ar), has_expression(false) {}
        archive_node(archive &ar, const ex &expr);
@@ -113,17 +116,22 @@ public:
        bool find_string(const std::string &name, std::string &ret, unsigned index = 0) const;
 
        /** Find the location in the vector of properties of the first/last
-    *  property with a given name. */
+        *  property with a given name. */
        archive_node_cit find_first(const std::string &name) const;
        archive_node_cit find_last(const std::string &name) const;
 
+       /** Find a range of locations in the vector of properties. The result
+        *  begins at the first property with name1 and ends one past the last
+        *  property with name2. */
+       archive_node_cit_range find_property_range(const std::string &name1, const std::string &name2) const;
+
        /** Retrieve property of type "ex" from node.
         *  @return "true" if property was found, "false" otherwise */
        bool find_ex(const std::string &name, ex &ret, lst &sym_lst, unsigned index = 0) const;
 
        /** Retrieve property of type "ex" from the node if it is known
-    *  that this node in fact contains such a property at the given
-    *  location. This is much more efficient than the preceding function. */
+        *  that this node in fact contains such a property at the given
+        *  location. This is much more efficient than the preceding function. */
        void find_ex_by_loc(archive_node_cit loc, ex &ret, lst &sym_lst) const;
 
        /** Retrieve property of type "ex" from node, returning the node of
@@ -271,14 +279,14 @@ public:
        /** Retrieve expression from archive by index.
         *  @param sym_lst list of pre-defined symbols
         *  @param index index of expression
-     *  @see count_expressions */
+        *  @see count_expressions */
        ex unarchive_ex(const lst &sym_lst, unsigned index = 0) const;
 
        /** Retrieve expression and its name from archive by index.
         *  @param sym_lst list of pre-defined symbols
         *  @param name receives the name of the expression
         *  @param index index of expression
-     *  @see count_expressions */
+        *  @see count_expressions */
        ex unarchive_ex(const lst &sym_lst, std::string &name, unsigned index = 0) const;
 
        /** Return number of archived expressions. */
index 960f072..4360bcc 100644 (file)
@@ -212,14 +212,12 @@ public:
                inherited::read_archive(n, sym_lst);
                setflag(get_default_flags());
 
-               archive_node::archive_node_cit first = n.find_first("seq");
-               archive_node::archive_node_cit last = n.find_last("seq");
-               ++last;
-               this->reserve(this->seq, last - first);
-               for (archive_node::archive_node_cit i=first; i<last; ++i) {
+               auto range =  n.find_property_range("seq", "seq");
+               this->reserve(this->seq, range.end - range.begin);
+               for (archive_node::archive_node_cit i=range.begin; i<range.end; ++i) {
                        ex e;
                        n.find_ex_by_loc(i, e, sym_lst);
-                       this->seq.push_back(e);
+                       this->seq.emplace_back(e);
                }
        }
 
index a136153..59bd831 100644 (file)
@@ -112,17 +112,15 @@ expairseq::expairseq(epvector && vp, const ex &oc, bool do_index_renaming)
 void expairseq::read_archive(const archive_node &n, lst &sym_lst) 
 {
        inherited::read_archive(n, sym_lst);
-       auto first = n.find_first("rest");
-       auto last = n.find_last("coeff");
-       ++last;
-       seq.reserve((last-first)/2);
+       auto range = n.find_property_range("rest", "coeff");
+       seq.reserve((range.end-range.begin)/2);
 
-       for (auto loc = first; loc < last;) {
+       for (auto loc = range.begin; loc < range.end;) {
                ex rest;
                ex coeff;
                n.find_ex_by_loc(loc++, rest, sym_lst);
                n.find_ex_by_loc(loc++, coeff, sym_lst);
-               seq.push_back(expair(rest, coeff));
+               seq.emplace_back(expair(rest, coeff));
        }
 
        n.find_ex("overall_coeff", overall_coeff, sym_lst);
index fb67506..a1be78c 100644 (file)
@@ -140,13 +140,11 @@ void matrix::read_archive(const archive_node &n, lst &sym_lst)
        m.reserve(row * col);
        // XXX: default ctor inserts a zero element, we need to erase it here.
        m.pop_back();
-       auto first = n.find_first("m");
-       auto last = n.find_last("m");
-       ++last;
-       for (auto i=first; i != last; ++i) {
+       auto range = n.find_property_range("m", "m");
+       for (auto i=range.begin; i != range.end; ++i) {
                ex e;
                n.find_ex_by_loc(i, e, sym_lst);
-               m.push_back(e);
+               m.emplace_back(e);
        }
 }
 GINAC_BIND_UNARCHIVER(matrix);
index 4dba512..b064a20 100644 (file)
@@ -119,17 +119,15 @@ pseries::pseries(const ex &rel_, epvector &&ops_)
 void pseries::read_archive(const archive_node &n, lst &sym_lst) 
 {
        inherited::read_archive(n, sym_lst);
-       auto first = n.find_first("coeff");
-       auto last = n.find_last("power");
-       ++last;
-       seq.reserve((last-first)/2);
+       auto range = n.find_property_range("coeff", "power");
+       seq.reserve((range.end-range.begin)/2);
 
-       for (auto loc = first; loc < last;) {
+       for (auto loc = range.begin; loc < range.end;) {
                ex rest;
                ex coeff;
                n.find_ex_by_loc(loc++, rest, sym_lst);
                n.find_ex_by_loc(loc++, coeff, sym_lst);
-               seq.push_back(expair(rest, coeff));
+               seq.emplace_back(expair(rest, coeff));
        }
 
        n.find_ex("var", var, sym_lst);