[nemiver] Use a fuzzy matching scheme when searching an @



commit 01e1bf2857d14462dd89692ba50914c376b5ef2a
Author: Dodji Seketeli <dodji redhat com>
Date:   Sun Sep 5 18:11:07 2010 +0200

    Use a fuzzy matching scheme when searching an @
    
    	* src/common/nmv-range.h (Range::ValueSearchResult): New enum.
    	* src/uicommon/nmv-source-editor.cc
    	(SourceEditor::Priv::get_smallest_range_containing_address): New
    	function.
    	(address_2_line): Use it. When asked the line matching an address
    	@, if @ is not present in the buffer, find the range of addresses
    	that encloses @, and return the line matching the uppper bound of
    	that address range.

 src/common/nmv-range.h            |   27 +++++++++++
 src/uicommon/nmv-source-editor.cc |   89 ++++++++++++++++++++++++++++++++-----
 2 files changed, 104 insertions(+), 12 deletions(-)
---
diff --git a/src/common/nmv-range.h b/src/common/nmv-range.h
index 2993520..aef1512 100644
--- a/src/common/nmv-range.h
+++ b/src/common/nmv-range.h
@@ -36,6 +36,33 @@ class Range {
     size_t m_max;
 
 public:
+
+    /// An enum representing the result of the searching of a range
+    /// around a value. E.g, suppose we have an ordered set of integer
+    /// values vi {v1, v2, v3 ...} that we name V.
+    /// Suppose we also have a particular integer N. And we want to
+    /// make the query expressed as: "What is the smallest range
+    /// R{vi,vi+p} that encloses N?".
+    /// If we had a function that would execute that query and return
+    /// an answer, this enum would help us know more about the how N
+    /// relates to the returned range.
+    /// VALUE_SEARCH_RESULT_EXACT means
+    /// that the N equals vi and equals vi+p. It means the range is
+    /// actually a single value, which is N.
+    /// VALUE_SEARCH_RESULT_WITHIN means that N is greater than vi
+    /// and less than vi+p. I means N is within the range.
+    /// VALUE_SEARCH_RESULT_BEFORE means that N is less then vi, and
+    /// so less than vi+p too. It means N is before the range.
+    /// VALUE_SEARCH_RESULT_AFTER means N is greater than vi+p, and so
+    /// greater than vi too. It means N is after the range.
+    enum ValueSearchResult {
+        VALUE_SEARCH_RESULT_EXACT = 0,
+        VALUE_SEARCH_RESULT_WITHIN,
+        VALUE_SEARCH_RESULT_BEFORE,
+        VALUE_SEARCH_RESULT_AFTER,
+        VALUE_SEARCH_RESULT_NONE // <-- must always be last.
+    };
+
     Range (size_t a_min = 0, size_t a_max = 0) :
         m_min (a_min),
         m_max (a_max)
diff --git a/src/uicommon/nmv-source-editor.cc b/src/uicommon/nmv-source-editor.cc
index 06e0d45..fe8ca21 100644
--- a/src/uicommon/nmv-source-editor.cc
+++ b/src/uicommon/nmv-source-editor.cc
@@ -332,36 +332,101 @@ struct SourceEditor::Priv {
         return 0;
     }
 
-    bool
-    address_2_line (Glib::RefPtr<SourceBuffer> a_buf,
-		    const Address an_addr,
-		    int &a_line) const
+    typedef std::pair<Address, int> AddrLine;
+    typedef std::pair<AddrLine, AddrLine> AddrLineRange;
+
+    common::Range::ValueSearchResult
+    get_smallest_range_containing_address (Glib::RefPtr<SourceBuffer> a_buf,
+                                           const Address &an_addr,
+                                           AddrLineRange &a_range) const
+                                    
     {
-        if (!a_buf)
-            return false;
-
         Gtk::TextBuffer::iterator it = a_buf->begin ();
         size_t  i;
         std::string addr;
+        AddrLine lower_bound, upper_bound;
+
+        THROW_IF_FAIL (it.starts_line ());
+
         while (!it.is_end ()) {
             // We must always be at the beginning of a line here.
             THROW_IF_FAIL (it.starts_line ());
             addr.clear ();
             for (i = 0;
                  !isspace (it.get_char ()) && it.ends_line () != true
-                 && i < an_addr.string_size ();
+                     && i < an_addr.string_size ();
                  ++it, ++i) {
                 addr += it.get_char ();
             }
-            bool match = (addr == an_addr.to_string ());
-            if (match) {
-                a_line = it.get_line () + 1;
-                return true;
+
+            int match = (addr.compare (an_addr.to_string ()));
+
+            if (match < 0
+                && str_utils::string_is_hexa_number (addr)) {
+                lower_bound.first = addr;
+                lower_bound.second = it.get_line () + 1;
+            }
+
+            if (match > 0
+                && str_utils::string_is_hexa_number (addr)) {
+                if (lower_bound.first.empty ()) {
+                    // So we are seing an @ that is greater than
+                    // an_addr without having ever seen an @ that is
+                    // lower than an_addr.  That means all the @s of
+                    // the buffer are greater than an_addr.
+                    return common::Range::VALUE_SEARCH_RESULT_BEFORE;
+                } else {
+                    // So the previous @ we saw was lower than
+                    // a_address and this one is greater. it means we
+                    // the buffer does not contain a_address, but
+                    // rather contains at a range of @s that surrounds
+                    // a_address. Return that range.
+                    upper_bound.first = addr;
+                    upper_bound.second = it.get_line () + 1;
+                    a_range.first = lower_bound;
+                    a_range.second = upper_bound;
+                    return common::Range::VALUE_SEARCH_RESULT_WITHIN;
+                }
+            }
+
+            if (match == 0) {
+                a_range.first.first = an_addr;
+                a_range.first.second = it.get_line () + 1;
+                a_range.second = a_range.first;
+                return common::Range::VALUE_SEARCH_RESULT_EXACT;
             } else {
                 // Go to next line.
                 it.forward_line ();
             }
         }
+
+        if (!lower_bound.first.empty ()) {
+            if (upper_bound.first.empty ())
+                return common::Range::VALUE_SEARCH_RESULT_AFTER;
+            else
+                THROW ("unreachable");
+        }
+         
+        return common::Range::VALUE_SEARCH_RESULT_NONE;
+    }
+
+    bool
+    address_2_line (Glib::RefPtr<SourceBuffer> a_buf,
+		    const Address an_addr,
+		    int &a_line) const
+    {
+        if (!a_buf)
+            return false;
+
+        AddrLineRange range;
+        common::Range::ValueSearchResult s =
+            get_smallest_range_containing_address (a_buf, an_addr, range);
+
+        if (s == common::Range::VALUE_SEARCH_RESULT_EXACT
+            || s == common::Range::VALUE_SEARCH_RESULT_WITHIN) {
+            a_line = range.second.second;
+            return true;
+        }
         return false;
     }
 



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