From 19cc08b7e5e4fac0156ffea5d47f7ac3e05844fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Villemot?= <sebastien@dynare.org> Date: Wed, 6 Feb 2019 18:39:46 +0100 Subject: [PATCH] Dynare++: modernization and simplification of the IntSequence class Similarly to Vector, it now uses a std::shared_ptr for managing the underlying data. --- dynare++/kord/journal.hh | 1 + dynare++/tl/cc/int_sequence.cc | 136 +++++++++++---------------------- dynare++/tl/cc/int_sequence.hh | 53 ++++++------- dynare++/tl/cc/symmetry.hh | 8 +- 4 files changed, 71 insertions(+), 127 deletions(-) diff --git a/dynare++/kord/journal.hh b/dynare++/kord/journal.hh index a32ff385b..70f368424 100644 --- a/dynare++/kord/journal.hh +++ b/dynare++/kord/journal.hh @@ -9,6 +9,7 @@ #include <sys/time.h> #include <cstdio> +#include <cstring> #include <iostream> #include <fstream> diff --git a/dynare++/tl/cc/int_sequence.cc b/dynare++/tl/cc/int_sequence.cc index 21d2676b2..2dad701d9 100644 --- a/dynare++/tl/cc/int_sequence.cc +++ b/dynare++/tl/cc/int_sequence.cc @@ -4,15 +4,16 @@ #include "symmetry.hh" #include "tl_exception.hh" -#include <cstdio> -#include <climits> +#include <iostream> +#include <limits> +#include <numeric> /* This unfolds a given integer sequence with respect to the given symmetry. If for example the symmetry is $(2,3)$, and the sequence is $(a,b)$, then the result is $(a,a,b,b,b)$. */ IntSequence::IntSequence(const Symmetry &sy, const IntSequence &se) - : data(new int[sy.dimen()]), length(sy.dimen()), destroy(true) + : data{new int[sy.dimen()], [](int *arr) { delete[] arr; }}, length{sy.dimen()} { int k = 0; for (int i = 0; i < sy.num(); i++) @@ -30,7 +31,7 @@ IntSequence::IntSequence(const Symmetry &sy, const IntSequence &se) and one $u$. */ IntSequence::IntSequence(const Symmetry &sy, const std::vector<int> &se) - : data(new int[sy.num()]), length(sy.num()), destroy(true) + : data{new int[sy.num()], [](int *arr) { delete[] arr; }}, length{sy.num()} { TL_RAISE_IF(sy.dimen() <= se[se.size()-1], "Sequence is not reachable by symmetry in IntSequence()"); @@ -45,7 +46,7 @@ IntSequence::IntSequence(const Symmetry &sy, const std::vector<int> &se) sequence inserting the given number to the sequence. */ IntSequence::IntSequence(int i, const IntSequence &s) - : data(new int[s.size()+1]), length(s.size()+1), destroy(true) + : data{new int[s.size()+1], [](int *arr) { delete[] arr; }}, length{s.size()+1} { int j = 0; while (j < s.size() && s[j] < i) @@ -58,7 +59,7 @@ IntSequence::IntSequence(int i, const IntSequence &s) } IntSequence::IntSequence(int i, const IntSequence &s, int pos) - : data(new int[s.size()+1]), length(s.size()+1), destroy(true) + : data{new int[s.size()+1], [](int *arr) { delete[] arr; }}, length{s.size()+1} { TL_RAISE_IF(pos < 0 || pos > s.size(), "Wrong position for insertion IntSequence constructor"); @@ -72,42 +73,31 @@ IntSequence::IntSequence(int i, const IntSequence &s, int pos) const IntSequence & IntSequence::operator=(const IntSequence &s) { - TL_RAISE_IF(!destroy && length != s.length, - "Wrong length for in-place IntSequence::operator="); - if (destroy && length != s.length) - { - delete [] data; - data = new int[s.length]; - destroy = true; - length = s.length; - } - memcpy(data, s.data, sizeof(int)*length); + TL_RAISE_IF(length != s.length, "Wrong length for in-place IntSequence::operator="); + std::copy_n(s.data.get()+s.offset, length, data.get()+offset); + return *this; +} + +const IntSequence & +IntSequence::operator=(IntSequence &&s) +{ + TL_RAISE_IF(length != s.length, "Wrong length for in-place IntSequence::operator="); + std::copy_n(s.data.get()+s.offset, length, data.get()+offset); return *this; } bool IntSequence::operator==(const IntSequence &s) const { - if (size() != s.size()) - return false; - - int i = 0; - while (i < size() && operator[](i) == s[i]) - i++; - return i == size(); + return std::equal(data.get()+offset, data.get()+offset+length, + s.data.get()+s.offset, s.data.get()+s.offset+s.length); } -/* We need some linear irreflexive ordering, we implement it as - lexicographic ordering without identity. */ bool IntSequence::operator<(const IntSequence &s) const { - int len = std::min(size(), s.size()); - - int i = 0; - while (i < len && operator[](i) == s[i]) - i++; - return (i < s.size() && (i == size() || operator[](i) < s[i])); + return std::lexicographical_compare(data.get()+offset, data.get()+offset+length, + s.data.get()+s.offset, s.data.get()+s.offset+s.length); } bool @@ -134,28 +124,10 @@ IntSequence::less(const IntSequence &s) const return (i == size()); } -/* This is a bubble sort, all sequences are usually very short, so this - sin might be forgiven. */ - void IntSequence::sort() { - for (int i = 0; i < length; i++) - { - int swaps = 0; - for (int j = 0; j < length-1; j++) - { - if (data[j] > data[j+1]) - { - int s = data[j+1]; - data[j+1] = data[j]; - data[j] = s; - swaps++; - } - } - if (swaps == 0) - return; - } + std::sort(data.get()+offset, data.get()+offset+length); } /* Here we monotonize the sequence. If an item is less then its @@ -165,8 +137,8 @@ void IntSequence::monotone() { for (int i = 1; i < length; i++) - if (data[i-1] > data[i]) - data[i] = data[i-1]; + if (operator[](i-1) > operator[](i)) + operator[](i) = operator[](i-1); } /* This partially monotones the sequence. The partitioning is done by a @@ -181,8 +153,8 @@ IntSequence::pmonotone(const Symmetry &s) for (int i = 0; i < s.num(); i++) { for (int j = cum + 1; j < cum + s[i]; j++) - if (data[j-1] > data[j]) - data[j] = data[j-1]; + if (operator[](j-1) > operator[](j)) + operator[](j) = operator[](j-1); cum += s[i]; } } @@ -192,10 +164,7 @@ IntSequence::pmonotone(const Symmetry &s) int IntSequence::sum() const { - int res = 0; - for (int i = 0; i < length; i++) - res += operator[](i); - return res; + return std::accumulate(data.get()+offset, data.get()+offset+length, 0); } /* This returns product of subsequent items. Useful for Kronecker product @@ -204,10 +173,8 @@ IntSequence::sum() const int IntSequence::mult(int i1, int i2) const { - int res = 1; - for (int i = i1; i < i2; i++) - res *= operator[](i); - return res; + return std::accumulate(data.get()+offset+i1, data.get()+offset+i2, + 1, std::multiplies<int>()); } /* Return a number of the same items in the beginning of the sequence. */ @@ -228,9 +195,9 @@ int IntSequence::getNumDistinct() const { int res = 0; - if (size() > 0) + if (length > 0) res++; - for (int i = 1; i < size(); i++) + for (int i = 1; i < length; i++) if (operator[](i) != operator[](i-1)) res++; return res; @@ -242,11 +209,9 @@ IntSequence::getNumDistinct() const int IntSequence::getMax() const { - int res = INT_MIN; - for (int i = 0; i < size(); i++) - if (operator[](i) > res) - res = operator[](i); - return res; + if (length == 0) + return std::numeric_limits<int>::min(); + return *std::max_element(data.get()+offset, data.get()+offset+length); } void @@ -268,36 +233,23 @@ IntSequence::add(int f, const IntSequence &s) bool IntSequence::isPositive() const { - int i = 0; - while (i < size() && operator[](i) >= 0) - i++; - return (i == size()); + return std::all_of(data.get()+offset, data.get()+offset+length, + [](int x) { return x >= 0; }); } bool IntSequence::isConstant() const { - bool res = true; - int i = 1; - while (res && i < size()) - { - res = res && operator[](0) == operator[](i); - i++; - } - return res; + if (length < 2) + return true; + return std::all_of(data.get()+offset+1, data.get()+offset+length, + [this](int x) { return x == operator[](0); }); } bool IntSequence::isSorted() const { - bool res = true; - int i = 1; - while (res && i < size()) - { - res = res && operator[](i-1) <= operator[](i); - i++; - } - return res; + return std::is_sorted(data.get()+offset, data.get()+offset+length); } /* Debug print. */ @@ -305,8 +257,8 @@ IntSequence::isSorted() const void IntSequence::print() const { - printf("["); + std::cout << '['; for (int i = 0; i < size(); i++) - printf("%2d ", operator[](i)); - printf("]\n"); + std::cout << operator[](i) << ' '; + std::cout << ']' << std::endl; } diff --git a/dynare++/tl/cc/int_sequence.hh b/dynare++/tl/cc/int_sequence.hh index a99449caa..11467f135 100644 --- a/dynare++/tl/cc/int_sequence.hh +++ b/dynare++/tl/cc/int_sequence.hh @@ -19,26 +19,25 @@ items in the front (|getPrefixLength|), and also to add some integer number to all items. - Also, we need to construct a subsequence of a sequence, so - some instances do destroy the underlying data, and some not. */ + Also, we need to construct a subsequence of a sequence. */ #ifndef INT_SEQUENCE_H #define INT_SEQUENCE_H -#include <cstring> #include <vector> +#include <memory> +#include <algorithm> - -/* The implementation of |IntSequence| is straightforward. It has a - pointer |data|, a |length| of the data, and a flag |destroy|, whether - the instance must destroy the underlying data. */ +/* The implementation of |IntSequence| is straightforward. It has a pointer + |data|, an |offset| integer indicating the beginning of the data relatively + to the pointer and a |length| of the sequence. */ class Symmetry; class IntSequence { - int *data; + std::shared_ptr<int> data; int length; - bool destroy; + int offset{0}; public: /* We have a constructor allocating a given length of data, constructor allocating and then initializing all members to a given number, a copy @@ -49,46 +48,38 @@ public: respect to a given symmetry and constructor which inserts a given number to the ordered sequence or given number to a given position. */ - IntSequence(int l) - : data(new int[l]), length(l), destroy(true) + explicit IntSequence(int l) + : data{new int[l], [](int *arr) { delete[] arr; }}, length{l} { } IntSequence(int l, int n) - : data(new int[l]), length(l), destroy(true) + : data{new int[l], [](int *arr) { delete[] arr; }}, length{l} { - for (int i = 0; i < length; i++) - data[i] = n; + std::fill_n(data.get(), length, n); } IntSequence(const IntSequence &s) - : data(new int[s.length]), length(s.length), destroy(true) + : data{new int[s.length], [](int *arr) { delete[] arr; }}, length{s.length} { - memcpy(data, s.data, length*sizeof(int)); + std::copy_n(s.data.get()+s.offset, length, data.get()); } + IntSequence(IntSequence &&s) = default; IntSequence(IntSequence &s, int i1, int i2) - : data(s.data+i1), length(i2-i1), destroy(false) + : data{s.data}, length{i2-i1}, offset{s.offset+i1} { } IntSequence(const IntSequence &s, int i1, int i2) - : data(new int[i2-i1]), length(i2-i1), destroy(true) + : data{new int[i2-i1], [](int *arr) { delete[] arr; }}, length{i2-i1} { - memcpy(data, s.data+i1, sizeof(int)*length); + std::copy_n(s.data.get()+s.offset+i1, length, data.get()); } IntSequence(const Symmetry &sy, const std::vector<int> &se); IntSequence(const Symmetry &sy, const IntSequence &se); IntSequence(int i, const IntSequence &s); IntSequence(int i, const IntSequence &s, int pos); - IntSequence(int l, const int *d) - : data(new int[l]), length(l), destroy(true) - { - memcpy(data, d, sizeof(int)*length); - } const IntSequence &operator=(const IntSequence &s); - virtual ~IntSequence() - { - if (destroy) - delete [] data; - } + const IntSequence &operator=(IntSequence &&s); + virtual ~IntSequence() = default; bool operator==(const IntSequence &s) const; bool operator!=(const IntSequence &s) const @@ -98,12 +89,12 @@ public: int & operator[](int i) { - return data[i]; + return data.get()[offset+i]; } int operator[](int i) const { - return data[i]; + return data.get()[offset+i]; } int size() const diff --git a/dynare++/tl/cc/symmetry.hh b/dynare++/tl/cc/symmetry.hh index 542f15da3..eff2d84d0 100644 --- a/dynare++/tl/cc/symmetry.hh +++ b/dynare++/tl/cc/symmetry.hh @@ -75,7 +75,8 @@ public: Symmetry(int i1, int i2) : IntSequence(2) { - operator[](0) = i1; operator[](1) = i2; + operator[](0) = i1; + operator[](1) = i2; } Symmetry(int i1, int i2, int i3) : IntSequence(3) @@ -92,9 +93,8 @@ public: operator[](2) = i3; operator[](3) = i4; } - Symmetry(const Symmetry &s) - - = default; + Symmetry(const Symmetry &s) = default; + Symmetry(Symmetry &&s) = default; Symmetry(const Symmetry &s, const OrdSequence &cl) : IntSequence(s, cl.getData()) { -- GitLab