sivachandra created this revision.
sivachandra added reviewers: clayborg, granata.enrico.
sivachandra added a subscriber: lldb-commits.

Along with this, support for an optional Python synthetic child provider
method "has_child_at_index" has also been added. These have been added
with the following use case in mind:

Synthetic child providers currently have a method "has_children" and
"get_num_children". While the former is good enough to know if there are
children, it does not give any insight into how many children there are.
Though the latter serves this purpose, calculating the number for children
of a data structure could be an O(N) operation if the data structure has N
children. The new methods added in this change provide a middle ground.
One can call HasChildAtIndex to know if a child exists at an index K which
can be as large as the callers tolerance can be. If the caller wants to
know about children beyond K, it can make an other call with 2K. If the
synthetic child provider maintains state about it counting till K
previosly, then the next call is only an O(K) operation. Infact, all
calls made progressively with steps of K will be O(K) operations.

http://reviews.llvm.org/D13778

Files:
  include/lldb/API/SBValue.h
  include/lldb/Core/ValueObject.h
  include/lldb/Core/ValueObjectSyntheticFilter.h
  include/lldb/DataFormatters/TypeSynthetic.h
  include/lldb/Interpreter/ScriptInterpreter.h
  scripts/Python/python-wrapper.swig
  scripts/interface/SBValue.i
  source/API/SBValue.cpp
  source/API/SystemInitializerFull.cpp
  source/Core/ValueObject.cpp
  source/Core/ValueObjectSyntheticFilter.cpp
  source/DataFormatters/TypeSynthetic.cpp
  source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
  source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h

Index: source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
===================================================================
--- source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
+++ source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
@@ -71,6 +71,7 @@
     
     typedef size_t          (*SWIGPythonCalculateNumChildren)                   (void *implementor);
     typedef void*           (*SWIGPythonGetChildAtIndex)                        (void *implementor, uint32_t idx);
+    typedef int             (*SWIGPythonHasChildAtIndex)                        (void *implementor, uint32_t idx);
     typedef int             (*SWIGPythonGetIndexOfChildWithName)                (void *implementor, const char* child_name);
     typedef void*           (*SWIGPythonCastPyObjectToSBValue)                  (void* data);
     typedef lldb::ValueObjectSP  (*SWIGPythonGetValueObjectSPFromSBValue)       (void* data);
@@ -200,6 +201,8 @@
 
     lldb::ValueObjectSP GetChildAtIndex(const StructuredData::ObjectSP &implementor, uint32_t idx) override;
 
+    int HasChildAtIndex(const StructuredData::ObjectSP &implementor, uint32_t idx) override;
+
     int GetIndexOfChildWithName(const StructuredData::ObjectSP &implementor, const char *child_name) override;
 
     bool UpdateSynthProviderInstance(const StructuredData::ObjectSP &implementor) override;
@@ -363,6 +366,7 @@
                            SWIGPythonCreateCommandObject swig_create_cmd,
                            SWIGPythonCalculateNumChildren swig_calc_children,
                            SWIGPythonGetChildAtIndex swig_get_child_index,
+                           SWIGPythonHasChildAtIndex swig_has_child_at_index,
                            SWIGPythonGetIndexOfChildWithName swig_get_index_child,
                            SWIGPythonCastPyObjectToSBValue swig_cast_to_sbvalue ,
                            SWIGPythonGetValueObjectSPFromSBValue swig_get_valobj_sp_from_sbvalue,
Index: source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
===================================================================
--- source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
+++ source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
@@ -60,6 +60,7 @@
 static ScriptInterpreterPython::SWIGPythonCreateCommandObject g_swig_create_cmd = nullptr;
 static ScriptInterpreterPython::SWIGPythonCalculateNumChildren g_swig_calc_children = nullptr;
 static ScriptInterpreterPython::SWIGPythonGetChildAtIndex g_swig_get_child_index = nullptr;
+static ScriptInterpreterPython::SWIGPythonHasChildAtIndex g_swig_has_child_at_index = nullptr;
 static ScriptInterpreterPython::SWIGPythonGetIndexOfChildWithName g_swig_get_index_child = nullptr;
 static ScriptInterpreterPython::SWIGPythonCastPyObjectToSBValue g_swig_cast_to_sbvalue  = nullptr;
 static ScriptInterpreterPython::SWIGPythonGetValueObjectSPFromSBValue g_swig_get_valobj_sp_from_sbvalue = nullptr;
@@ -2262,6 +2263,28 @@
 }
 
 int
+ScriptInterpreterPython::HasChildAtIndex(const StructuredData::ObjectSP &implementor_sp, uint32_t idx)
+{
+    if (!implementor_sp)
+        return -1;
+
+    StructuredData::Generic *generic = implementor_sp->GetAsGeneric();
+    if (!generic)
+        return -1;
+    void *implementor = generic->GetValue();
+    if (!implementor)
+        return -1;
+
+    if (!g_swig_has_child_at_index)
+        return -1;
+
+    {
+        Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
+        return g_swig_has_child_at_index (implementor, idx);
+    }
+}
+
+int
 ScriptInterpreterPython::GetIndexOfChildWithName(const StructuredData::ObjectSP &implementor_sp, const char *child_name)
 {
     if (!implementor_sp)
@@ -3124,6 +3147,7 @@
                                                 SWIGPythonCreateCommandObject swig_create_cmd,
                                                 SWIGPythonCalculateNumChildren swig_calc_children,
                                                 SWIGPythonGetChildAtIndex swig_get_child_index,
+                                                SWIGPythonHasChildAtIndex swig_has_child_at_index,
                                                 SWIGPythonGetIndexOfChildWithName swig_get_index_child,
                                                 SWIGPythonCastPyObjectToSBValue swig_cast_to_sbvalue ,
                                                 SWIGPythonGetValueObjectSPFromSBValue swig_get_valobj_sp_from_sbvalue,
@@ -3151,6 +3175,7 @@
     g_swig_create_cmd = swig_create_cmd;
     g_swig_calc_children = swig_calc_children;
     g_swig_get_child_index = swig_get_child_index;
+    g_swig_has_child_at_index = swig_has_child_at_index;
     g_swig_get_index_child = swig_get_index_child;
     g_swig_cast_to_sbvalue = swig_cast_to_sbvalue;
     g_swig_get_valobj_sp_from_sbvalue = swig_get_valobj_sp_from_sbvalue;
Index: source/DataFormatters/TypeSynthetic.cpp
===================================================================
--- source/DataFormatters/TypeSynthetic.cpp
+++ source/DataFormatters/TypeSynthetic.cpp
@@ -190,6 +190,15 @@
     return m_interpreter->GetChildAtIndex(m_wrapper_sp, idx);
 }
 
+int
+ScriptedSyntheticChildren::FrontEnd::HasChildAtIndex (size_t idx)
+{
+    if (!m_wrapper_sp || !m_interpreter)
+        return -1;
+
+    return m_interpreter->HasChildAtIndex(m_wrapper_sp, idx);
+}
+
 bool
 ScriptedSyntheticChildren::FrontEnd::IsValid ()
 {
Index: source/Core/ValueObjectSyntheticFilter.cpp
===================================================================
--- source/Core/ValueObjectSyntheticFilter.cpp
+++ source/Core/ValueObjectSyntheticFilter.cpp
@@ -36,7 +36,13 @@
     {
         return m_backend.GetChildAtIndex(idx, true);
     }
-    
+
+    int
+    HasChildAtIndex (size_t idx)
+    {
+        return m_backend.HasChildAtIndex(idx);
+    }
+
     size_t
     GetIndexOfChildWithName (const ConstString &name)
     {
@@ -233,6 +239,17 @@
         return valobj->GetSP();
 }
 
+int
+ValueObjectSynthetic::HasChildAtIndex (size_t idx)
+{
+  UpdateValueIfNeeded();
+
+  if (m_synth_filter_ap.get() == NULL)
+      return -1;
+
+  return m_synth_filter_ap->HasChildAtIndex (idx);
+}
+
 lldb::ValueObjectSP
 ValueObjectSynthetic::GetChildMemberWithName (const ConstString &name, bool can_create)
 {
Index: source/Core/ValueObject.cpp
===================================================================
--- source/Core/ValueObject.cpp
+++ source/Core/ValueObject.cpp
@@ -561,6 +561,35 @@
     return child_sp;
 }
 
+int
+ValueObject::HasChildAtIndex (size_t idx)
+{
+    ExecutionContext exe_ctx (GetExecutionContextRef());
+    std::string child_name_str;
+    bool child_is_base_class, child_is_deref_of_parent;
+    int32_t child_byte_offset;
+    uint32_t child_byte_size, child_bitfield_bit_size, child_bitfield_bit_offset;
+
+    auto compiler_type = GetCompilerType().GetChildCompilerTypeAtIndex (&exe_ctx,
+                                                                        idx,
+                                                                        false, // transparent_pointers
+                                                                        true,  // omit_empty_base_classes,
+                                                                        false, //ignore_array_bounds,
+                                                                        child_name_str,
+                                                                        child_byte_size,
+                                                                        child_byte_offset,
+                                                                        child_bitfield_bit_size,
+                                                                        child_bitfield_bit_offset,
+                                                                        child_is_base_class,
+                                                                        child_is_deref_of_parent,
+                                                                        this);
+
+    if (compiler_type)
+        return 1;
+    else
+        return 0;
+}
+
 ValueObjectSP
 ValueObject::GetChildAtIndexPath (const std::initializer_list<size_t>& idxs,
                                   size_t* index_of_error)
Index: source/API/SystemInitializerFull.cpp
===================================================================
--- source/API/SystemInitializerFull.cpp
+++ source/API/SystemInitializerFull.cpp
@@ -145,6 +145,9 @@
 LLDBSwigPython_GetChildAtIndex (void *implementor, uint32_t idx);
 
 extern "C" int
+LLDBSwigPython_HasChildAtIndex (void *implementor, uint32_t idx);
+
+extern "C" int
 LLDBSwigPython_GetIndexOfChildWithName (void *implementor, const char* child_name);
 
 extern "C" void *
@@ -336,6 +339,7 @@
         LLDBSwigPythonCreateCommandObject,
         LLDBSwigPython_CalculateNumChildren,
         LLDBSwigPython_GetChildAtIndex,
+        LLDBSwigPython_HasChildAtIndex,
         LLDBSwigPython_GetIndexOfChildWithName,
         LLDBSWIGPython_CastPyObjectToSBValue,
         LLDBSWIGPython_GetValueObjectSPFromSBValue,
Index: source/API/SBValue.cpp
===================================================================
--- source/API/SBValue.cpp
+++ source/API/SBValue.cpp
@@ -997,6 +997,18 @@
     return sb_value;
 }
 
+int32_t
+SBValue::HasChildAtIndex (uint32_t idx)
+{
+    ValueLocker locker;
+    lldb::ValueObjectSP value_sp(GetSP(locker));
+
+    if (!value_sp)
+        return -1;
+
+    return value_sp->HasChildAtIndex (idx);
+}
+
 uint32_t
 SBValue::GetIndexOfChildWithName (const char *name)
 {
Index: scripts/interface/SBValue.i
===================================================================
--- scripts/interface/SBValue.i
+++ scripts/interface/SBValue.i
@@ -238,6 +238,17 @@
     GetChildAtIndex (uint32_t idx, 
                      lldb::DynamicValueType use_dynamic,
                      bool can_create_synthetic);
+
+    %feature("docstring", "
+    //------------------------------------------------------------------
+    /// The return value is a tri-state value. If it is positive, then it means that there
+    /// is indeed a child at index idx. If it is 0, then it means that there is no child
+    /// at that index. If it is negative, then it means that it (whether a child exists or not
+    /// at that said index) could not be evaluated properly.
+    //------------------------------------------------------------------
+    ") HasChildAtIndex;
+    int32_t
+    HasChildAtIndex (uint32_t idx);
     
     lldb::SBValue
     CreateChildAtOffset (const char *name, uint32_t offset, lldb::SBType type);
Index: scripts/Python/python-wrapper.swig
===================================================================
--- scripts/Python/python-wrapper.swig
+++ scripts/Python/python-wrapper.swig
@@ -716,6 +716,32 @@
 }
 
 SWIGEXPORT int
+LLDBSwigPython_HasChildAtIndex
+(
+    PyObject *implementor,
+    uint32_t idx
+)
+{
+    PyErr_Cleaner py_err_cleaner(true);
+
+    PyCallable pfunc = PyCallable::FindWithMemberFunction(implementor, "has_child_at_index");
+
+    if (!pfunc)
+        return -1;
+
+    PyObject *py_return = NULL;
+    py_return = pfunc(idx);
+
+    if (py_return == NULL)
+        return -1;
+
+    int truth_value = PyObject_IsTrue(py_return);
+    Py_DECREF(py_return);
+
+    return truth_value;
+}
+
+SWIGEXPORT int
 LLDBSwigPython_GetIndexOfChildWithName
 (
     PyObject *implementor,
Index: include/lldb/Interpreter/ScriptInterpreter.h
===================================================================
--- include/lldb/Interpreter/ScriptInterpreter.h
+++ include/lldb/Interpreter/ScriptInterpreter.h
@@ -361,6 +361,12 @@
     }
 
     virtual int
+    HasChildAtIndex(const StructuredData::ObjectSP &implementor, uint32_t idx)
+    {
+        return -1;
+    }
+
+    virtual int
     GetIndexOfChildWithName(const StructuredData::ObjectSP &implementor, const char *child_name)
     {
         return UINT32_MAX;
Index: include/lldb/DataFormatters/TypeSynthetic.h
===================================================================
--- include/lldb/DataFormatters/TypeSynthetic.h
+++ include/lldb/DataFormatters/TypeSynthetic.h
@@ -62,6 +62,12 @@
         
         virtual lldb::ValueObjectSP
         GetChildAtIndex (size_t idx) = 0;
+
+        virtual int
+        HasChildAtIndex (size_t idx)
+        {
+            return -1;
+        }
         
         virtual size_t
         GetIndexOfChildWithName (const ConstString &name) = 0;
@@ -129,6 +135,9 @@
         lldb::ValueObjectSP
         GetChildAtIndex(size_t idx) override { return nullptr; }
         
+        int
+        HasChildAtIndex(size_t idx) override { return 0; }
+
         size_t
         GetIndexOfChildWithName(const ConstString &name) override { return UINT32_MAX; }
         
@@ -454,6 +463,15 @@
                     return lldb::ValueObjectSP();
                 return m_backend.GetSyntheticExpressionPathChild(filter->GetExpressionPathAtIndex(idx), true);
             }
+
+            int
+            HasChildAtIndex(size_t idx) override
+            {
+                if (idx < filter->GetCount())
+                    return 1;
+                else
+                    return 0;
+            }
             
             bool
             Update() override { return false; }
@@ -595,6 +613,9 @@
             
             lldb::ValueObjectSP
             GetChildAtIndex(size_t idx) override;
+
+            int
+            HasChildAtIndex(size_t idx) override;
             
             bool
             Update() override;
Index: include/lldb/Core/ValueObjectSyntheticFilter.h
===================================================================
--- include/lldb/Core/ValueObjectSyntheticFilter.h
+++ include/lldb/Core/ValueObjectSyntheticFilter.h
@@ -56,6 +56,9 @@
     
     virtual lldb::ValueObjectSP
     GetChildAtIndex (size_t idx, bool can_create);
+
+    virtual int
+    HasChildAtIndex (size_t idx);
     
     virtual lldb::ValueObjectSP
     GetChildMemberWithName (const ConstString &name, bool can_create);
Index: include/lldb/Core/ValueObject.h
===================================================================
--- include/lldb/Core/ValueObject.h
+++ include/lldb/Core/ValueObject.h
@@ -554,6 +554,13 @@
     virtual lldb::ValueObjectSP
     GetChildAtIndex (size_t idx, bool can_create);
 
+    // The return value is a tri-state value. If it is positive, then it means that there
+    // is indeed a child at index idx. If it is 0, then it means that there is no child
+    // at that index. If it is negative, then it means that it (whether a child exists or not
+    // at that said index) could not be evaluated properly.
+    virtual int
+    HasChildAtIndex (size_t idx);
+
     // this will always create the children if necessary
     lldb::ValueObjectSP
     GetChildAtIndexPath (const std::initializer_list<size_t> &idxs,
Index: include/lldb/API/SBValue.h
===================================================================
--- include/lldb/API/SBValue.h
+++ include/lldb/API/SBValue.h
@@ -235,6 +235,13 @@
                      lldb::DynamicValueType use_dynamic,
                      bool can_create_synthetic);
 
+    /// The return value is a tri-state value. If it is positive, then it means that there
+    /// is indeed a child at index idx. If it is 0, then it means that there is no child
+    /// at that index. If it is negative, then it means that it (whether a child exists or not
+    /// at that said index) could not be evaluated properly.
+    int32_t
+    HasChildAtIndex (uint32_t idx);
+
     // Matches children of this object only and will match base classes and
     // member names if this is a clang typed object.
     uint32_t
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to