You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@buildstream.apache.org by gi...@apache.org on 2020/12/29 13:01:58 UTC

[buildstream] 08/27: _variables: Convert ValuePart to C struct

This is an automated email from the ASF dual-hosted git repository.

github-bot pushed a commit to branch tristan/partial-variables-manual-string-join
in repository https://gitbox.apache.org/repos/asf/buildstream.git

commit c67fe08ff1cc9ff5b8203d0bb3742c39b801acb1
Author: Tristan van Berkom <tr...@codethink.co.uk>
AuthorDate: Thu Jul 2 03:45:07 2020 +0900

    _variables: Convert ValuePart to C struct
---
 src/buildstream/_variables.pyx | 100 ++++++++++++++++++++++++++---------------
 1 file changed, 65 insertions(+), 35 deletions(-)

diff --git a/src/buildstream/_variables.pyx b/src/buildstream/_variables.pyx
index 245cbab..9512ab5 100644
--- a/src/buildstream/_variables.pyx
+++ b/src/buildstream/_variables.pyx
@@ -409,29 +409,6 @@ cdef class ResolutionStep:
                         detail="\n".join(reversed(error_lines)))
 
 
-# ValuePart()
-#
-# Represents a part of a value (a string and an indicator
-# of whether the string is a variable or not).
-#
-# This only exists for better performance than constructing
-# and unpacking tuples.
-#
-# Args:
-#    text (str): The text of this part
-#    is_variable (bint): True if the text is a variable, False if it's literal
-#
-cdef class ValuePart:
-    cdef str text
-    cdef bint is_variable
-    cdef ValuePart next_part
-
-    cdef init(self, str text, bint is_variable):
-        self.text = text
-        self.is_variable = is_variable
-        self.next_part = None
-
-
 cdef EMPTY_SET = set()
 
 # Value():
@@ -474,7 +451,7 @@ cdef class Value:
     cdef str resolve(self, dict values):
         cdef str dep_name
         cdef Value part_var
-        cdef ValuePart part
+        cdef ValuePart *part
         cdef object part_object
         cdef list parts = []
 
@@ -483,10 +460,10 @@ cdef class Value:
 
             while part:
                 if part.is_variable:
-                    part_var = <Value> values[part.text]
+                    part_var = <Value> values[<str>part.text]
                     parts.append(part_var._resolved)
                 else:
-                    parts.append(part.text)
+                    parts.append(<str>part.text)
 
                 part = part.next_part
 
@@ -564,7 +541,7 @@ cdef class ValueClass:
     # Public
     #
     cdef set variable_names  # A set of variable names
-    cdef ValuePart parts  # The linked list of ValuePart objects
+    cdef ValuePart *parts
 
     # init():
     #
@@ -574,10 +551,15 @@ cdef class ValueClass:
     #    string (str): The string which can contain variables
     #
     cdef init(self, str string):
+
         self.variable_names = set()
-        self.parts = None
+        self.parts = NULL
+
         self._parse_string(string)
 
+    def __dealloc__(self):
+        free_value_parts(self.parts)
+
     # _parse_string()
     #
     # Parse the string for this ValueClass, breaking it down into
@@ -604,19 +586,21 @@ cdef class ValueClass:
         # What do you expect ? These are regular expressions after all,
         # they are *supposed* to be weird.
         #
-        cdef list splits = VALUE_CLASS_PARSE_EXPANSION.split(string)
+        cdef splits = VALUE_CLASS_PARSE_EXPANSION.split(string)
         cdef object split_object
         cdef str split
         cdef Py_ssize_t split_idx = 0
-        cdef bint is_variable
-        cdef ValuePart part
-        cdef ValuePart last_part = None
+        cdef int is_variable
+
+        # Adding parts
+        #
+        cdef ValuePart *part
+        cdef ValuePart *last_part = NULL
 
         #
         # Collect the weird regex return value into something
         # more comprehensible.
         #
-
         for split_object in splits:
             split = <str> split_object
             if split:
@@ -633,8 +617,7 @@ cdef class ValueClass:
                     is_variable = True
                     self.variable_names.add(split)
 
-                part = ValuePart()
-                part.init(split, is_variable)
+                part = new_value_part(split, is_variable)
                 if last_part:
                     last_part.next_part = part
                 else:
@@ -664,3 +647,50 @@ cdef class ValueIterator:
     def __next__(self):
         name = next(self._iter)
         return name, self._variables[name]
+
+
+############################## BASEMENT ########################################
+
+
+from cpython.mem cimport PyMem_Malloc, PyMem_Free
+from cpython.object cimport PyObject
+from cpython.ref cimport Py_XINCREF, Py_XDECREF
+
+# ValuePart()
+#
+# Represents a part of a value (a string and an indicator
+# of whether the string is a variable or not).
+#
+# This only exists for better performance than constructing
+# and unpacking tuples.
+#
+# Args:
+#    text (str): The text of this part
+#    is_variable (bint): True if the text is a variable, False if it's literal
+#
+ctypedef struct ValuePart:
+    PyObject *text
+    int is_variable
+    ValuePart *next_part
+
+cdef ValuePart *new_value_part(str text, int is_variable):
+    cdef ValuePart *part = <ValuePart *>PyMem_Malloc(sizeof(ValuePart))
+    if not part:
+        raise MemoryError()
+
+    part.text = <PyObject *>text
+    part.is_variable = is_variable
+    part.next_part = NULL
+    Py_XINCREF(part.text)
+    return part
+
+cdef void free_value_part(ValuePart *part):
+    Py_XDECREF(part.text)
+    PyMem_Free(part)
+
+cdef void free_value_parts(ValuePart *part):
+    cdef ValuePart *to_free
+    while part:
+        to_free = part
+        part = part.next_part
+        free_value_part(to_free)