diff data/model/EditableDenseThreeDimensionalModel.cpp @ 1777:d484490cdf69

Split EditableDenseThreeDimensionalModel into explicitly compressed and uncompressed variants. Simplifies the uncompressed version, and we may want to consider whether we need the compressed one at all.
author Chris Cannam
date Tue, 10 Sep 2019 16:34:47 +0100
parents 6d09d68165a4
children c546429d4c2f
line wrap: on
line diff
--- a/data/model/EditableDenseThreeDimensionalModel.cpp	Mon Sep 09 10:25:16 2019 +0100
+++ b/data/model/EditableDenseThreeDimensionalModel.cpp	Tue Sep 10 16:34:47 2019 +0100
@@ -19,8 +19,7 @@
 
 #include <QTextStream>
 #include <QStringList>
-#include <QReadLocker>
-#include <QWriteLocker>
+#include <QMutexLocker>
 
 #include <iostream>
 
@@ -34,13 +33,11 @@
 EditableDenseThreeDimensionalModel::EditableDenseThreeDimensionalModel(sv_samplerate_t sampleRate,
                                                                        int resolution,
                                                                        int yBinCount,
-                                                                       CompressionType compression,
                                                                        bool notifyOnAdd) :
     m_startFrame(0),
     m_sampleRate(sampleRate),
     m_resolution(resolution),
     m_yBinCount(yBinCount),
-    m_compression(compression),
     m_minimum(0.0),
     m_maximum(0.0),
     m_haveExtents(false),
@@ -145,218 +142,82 @@
 EditableDenseThreeDimensionalModel::Column
 EditableDenseThreeDimensionalModel::getColumn(int index) const
 {
-    QReadLocker locker(&m_lock);
-    if (in_range_for(m_data, index)) return expandAndRetrieve(index);
-    else return Column();
-}
-
-float
-EditableDenseThreeDimensionalModel::getValueAt(int index, int n) const
-{
-    Column c = getColumn(index);
-    if (in_range_for(c, n)) return c.at(n);
-    return m_minimum;
-}
-
-//static int given = 0, stored = 0;
-
-void
-EditableDenseThreeDimensionalModel::truncateAndStore(int index,
-                                                     const Column &values)
-{
-    assert(in_range_for(m_data, index));
-
-    //cout << "truncateAndStore(" << index << ", " << values.size() << ")" << endl;
-
-    // The default case is to store the entire column at m_data[index]
-    // and place 0 at m_trunc[index] to indicate that it has not been
-    // truncated.  We only do clever stuff if one of the clever-stuff
-    // tests works out.
-
-    m_trunc[index] = 0;
-    if (index == 0 ||
-        m_compression == NoCompression ||
-        int(values.size()) != m_yBinCount) {
-//        given += values.size();
-//        stored += values.size();
-        m_data[index] = values;
-        return;
+    QMutexLocker locker(&m_mutex);
+    if (!in_range_for(m_data, index)) {
+        return {};
     }
-
-    // Maximum distance between a column and the one we refer to as
-    // the source of its truncated values.  Limited by having to fit
-    // in a signed char, but in any case small values are usually
-    // better
-    static int maxdist = 6;
-
-    bool known = false; // do we know whether to truncate at top or bottom?
-    bool top = false;   // if we do know, will we truncate at top?
-
-    // If the previous column is not truncated, then it is the only
-    // candidate for comparison.  If it is truncated, then the column
-    // that it refers to is the only candidate.  Either way, we only
-    // have one possible column to compare against here, and we are
-    // being careful to ensure it is not a truncated one (to avoid
-    // doing more work recursively when uncompressing).
-    int tdist = 1;
-    int ptrunc = m_trunc[index-1];
-    if (ptrunc < 0) {
-        top = false;
-        known = true;
-        tdist = -ptrunc + 1;
-    } else if (ptrunc > 0) {
-        top = true;
-        known = true;
-        tdist = ptrunc + 1;
-    }
-
-    Column p = expandAndRetrieve(index - tdist);
-    int h = m_yBinCount;
-
-    if (int(p.size()) == h && tdist <= maxdist) {
-
-        int bcount = 0, tcount = 0;
-        if (!known || !top) {
-            // count how many identical values there are at the bottom
-            for (int i = 0; i < h; ++i) {
-                if (values.at(i) == p.at(i)) ++bcount;
-                else break;
-            }
-        }
-        if (!known || top) {
-            // count how many identical values there are at the top
-            for (int i = h; i > 0; --i) {
-                if (values.at(i-1) == p.at(i-1)) ++tcount;
-                else break;
-            }
-        }
-        if (!known) top = (tcount > bcount);
-
-        int limit = h / 4; // don't bother unless we have at least this many
-        if ((top ? tcount : bcount) > limit) {
-        
-            if (!top) {
-                // create a new column with h - bcount values from bcount up
-                Column tcol(h - bcount);
-//                given += values.size();
-//                stored += h - bcount;
-                for (int i = bcount; i < h; ++i) {
-                    tcol[i - bcount] = values.at(i);
-                }
-                m_data[index] = tcol;
-                m_trunc[index] = (signed char)(-tdist);
-                return;
-            } else {
-                // create a new column with h - tcount values from 0 up
-                Column tcol(h - tcount);
-//                given += values.size();
-//                stored += h - tcount;
-                for (int i = 0; i < h - tcount; ++i) {
-                    tcol[i] = values.at(i);
-                }
-                m_data[index] = tcol;
-                m_trunc[index] = (signed char)(tdist);
-                return;
-            }
-        }
-    }                
-
-//    given += values.size();
-//    stored += values.size();
-//    cout << "given: " << given << ", stored: " << stored << " (" 
-//              << ((float(stored) / float(given)) * 100.f) << "%)" << endl;
-
-    // default case if nothing wacky worked out
-    m_data[index] = values;
-    return;
-}
-
-EditableDenseThreeDimensionalModel::Column
-EditableDenseThreeDimensionalModel::rightHeight(const Column &c) const
-{
-    if (int(c.size()) == m_yBinCount) return c;
-    else {
+    Column c = m_data.at(index);
+    if (int(c.size()) == m_yBinCount) {
+        return c;
+    } else {
         Column cc(c);
         cc.resize(m_yBinCount, 0.0);
         return cc;
     }
 }
 
-EditableDenseThreeDimensionalModel::Column
-EditableDenseThreeDimensionalModel::expandAndRetrieve(int index) const
+float
+EditableDenseThreeDimensionalModel::getValueAt(int index, int n) const
 {
-    // See comment above m_trunc declaration in header
-
-    assert(index >= 0 && index < int(m_data.size()));
-    Column c = m_data.at(index);
-    if (index == 0) {
-        return rightHeight(c);
+    QMutexLocker locker(&m_mutex);
+    if (!in_range_for(m_data, index)) {
+        return m_minimum;
     }
-    int trunc = (int)m_trunc[index];
-    if (trunc == 0) {
-        return rightHeight(c);
+    const Column &c = m_data.at(index);
+    if (!in_range_for(c, n)) {
+        return m_minimum;
     }
-    bool top = true;
-    int tdist = trunc;
-    if (trunc < 0) { top = false; tdist = -trunc; }
-    Column p = expandAndRetrieve(index - tdist);
-    int psize = int(p.size()), csize = int(c.size());
-    if (psize != m_yBinCount) {
-        cerr << "WARNING: EditableDenseThreeDimensionalModel::expandAndRetrieve: Trying to expand from incorrectly sized column" << endl;
-    }
-    if (top) {
-        for (int i = csize; i < psize; ++i) {
-            c.push_back(p.at(i));
-        }
-    } else {
-        Column cc(psize);
-        for (int i = 0; i < psize - csize; ++i) {
-            cc[i] = p.at(i);
-        }
-        for (int i = 0; i < csize; ++i) {
-            cc[i + (psize - csize)] = c.at(i);
-        }
-        return cc;
-    }
-    return c;
+    return c.at(n);
 }
 
 void
 EditableDenseThreeDimensionalModel::setColumn(int index,
                                               const Column &values)
 {
-    QWriteLocker locker(&m_lock);
-
-    while (index >= int(m_data.size())) {
-        m_data.push_back(Column());
-        m_trunc.push_back(0);
-    }
-
     bool allChange = false;
-
-    for (int i = 0; in_range_for(values, i); ++i) {
-        float value = values[i];
-        if (ISNAN(value) || ISINF(value)) {
-            continue;
-        }
-        if (!m_haveExtents || value < m_minimum) {
-            m_minimum = value;
-            allChange = true;
-        }
-        if (!m_haveExtents || value > m_maximum) {
-            m_maximum = value;
-            allChange = true;
-        }
-        m_haveExtents = true;
-    }
-
-    truncateAndStore(index, values);
-
-//    assert(values == expandAndRetrieve(index));
-
     sv_frame_t windowStart = index;
     windowStart *= m_resolution;
 
+    {
+        QMutexLocker locker(&m_mutex);
+
+        while (index >= int(m_data.size())) {
+            m_data.push_back(Column());
+        }
+
+        for (int i = 0; in_range_for(values, i); ++i) {
+            float value = values[i];
+            if (ISNAN(value) || ISINF(value)) {
+                continue;
+            }
+            if (!m_haveExtents || value < m_minimum) {
+                m_minimum = value;
+                allChange = true;
+            }
+            if (!m_haveExtents || value > m_maximum) {
+                m_maximum = value;
+                allChange = true;
+            }
+            m_haveExtents = true;
+        }
+
+        m_data[index] = values;
+
+        if (allChange) {
+            m_sinceLastNotifyMin = -1;
+            m_sinceLastNotifyMax = -1;
+        } else {
+            if (m_sinceLastNotifyMin == -1 ||
+                windowStart < m_sinceLastNotifyMin) {
+                m_sinceLastNotifyMin = windowStart;
+            }
+            if (m_sinceLastNotifyMax == -1 ||
+                windowStart > m_sinceLastNotifyMax) {
+                m_sinceLastNotifyMax = windowStart;
+            }
+        }
+    }
+
     if (m_notifyOnAdd) {
         if (allChange) {
             emit modelChanged(getId());
@@ -366,18 +227,7 @@
         }
     } else {
         if (allChange) {
-            m_sinceLastNotifyMin = -1;
-            m_sinceLastNotifyMax = -1;
             emit modelChanged(getId());
-        } else {
-            if (m_sinceLastNotifyMin == -1 ||
-                windowStart < m_sinceLastNotifyMin) {
-                m_sinceLastNotifyMin = windowStart;
-            }
-            if (m_sinceLastNotifyMax == -1 ||
-                windowStart > m_sinceLastNotifyMax) {
-                m_sinceLastNotifyMax = windowStart;
-            }
         }
     }
 }
@@ -438,7 +288,7 @@
 bool
 EditableDenseThreeDimensionalModel::shouldUseLogValueScale() const
 {
-    QReadLocker locker(&m_lock);
+    QMutexLocker locker(&m_mutex);
 
     vector<double> sample;
     vector<int> n;
@@ -507,7 +357,7 @@
                                                           sv_frame_t startFrame,
                                                           sv_frame_t duration) const
 {
-    QReadLocker locker(&m_lock);
+    QMutexLocker locker(&m_mutex);
     QString s;
     for (int i = 0; in_range_for(m_data, i); ++i) {
         sv_frame_t fr = m_startFrame + i * m_resolution;
@@ -527,7 +377,7 @@
                                           QString indent,
                                           QString extraAttributes) const
 {
-    QReadLocker locker(&m_lock);
+    QMutexLocker locker(&m_mutex);
 
     // For historical reasons we read and write "resolution" as "windowSize".
 
@@ -552,7 +402,7 @@
     out << QString("<dataset id=\"%1\" dimensions=\"3\" separator=\" \">\n")
         .arg(getExportId());
 
-    for (int i = 0; i < (int)m_binNames.size(); ++i) {
+    for (int i = 0; in_range_for(m_binNames, i); ++i) {
         if (m_binNames[i] != "") {
             out << indent + "  ";
             out << QString("<bin number=\"%1\" name=\"%2\"/>\n")
@@ -560,12 +410,13 @@
         }
     }
 
-    for (int i = 0; i < (int)m_data.size(); ++i) {
+    for (int i = 0; in_range_for(m_data, i); ++i) {
+        Column c = getColumn(i);
         out << indent + "  ";
         out << QString("<row n=\"%1\">").arg(i);
-        for (int j = 0; j < (int)m_data.at(i).size(); ++j) {
+        for (int j = 0; in_range_for(c, j); ++j) {
             if (j > 0) out << " ";
-            out << m_data.at(i).at(j);
+            out << c.at(j);
         }
         out << QString("</row>\n");
         out.flush();