https://gcc.gnu.org/g:26e3c0bcc4e385d90189fd89561d2746a4d8c860

commit r17-3925-g26e3c0bcc4e385d90189fd89561d2746a4d8c860
Author: Robert Dubner <[email protected]>
Date:   Fri Sep 4 09:16:14 2026 -0400

    cobol: Refactor STRING/UNSTRING routines for speed.
    
    The routines implementing the COBOL STRING and UNSTRING statements have
    been split into separate versions for handling single-byte-encoded
    character sets on the one hand, and multi-byte character sets on the
    other.  This results in significant execution speed improvements in the
    common single-byte case.
    
    libgcobol/ChangeLog:
    
            * libgcobol.cc (string_operand): New structure.
            (__gg__string): Dispatches to __gg__string_1 and __gg__string_24
            (__gg__string_1): Optimized for single-byte-coded strings.
            (find_string_24): New finder for multi-byte strings.
            (__gg__string_24): Optimized for multi-strings.
            (__gg__unstring): Dispatches to __gg__unstring_1 and
            __gg__unstring_24
            (struct unstring_finder_1): New finder for single-byte strings.
            (struct unstring_finder_24): New finder for multi-byte strings.
            (unstring_fixed): Specialized finder for unstring.
            (__gg__unstring_1): Optimized for single-byte-coded strings.
            (__gg__unstring_24): Optimized for multi-byte strings.

Diff:
---
 libgcobol/libgcobol.cc | 759 +++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 605 insertions(+), 154 deletions(-)

diff --git a/libgcobol/libgcobol.cc b/libgcobol/libgcobol.cc
index efb44a62cadb..be8c58a20bc9 100644
--- a/libgcobol/libgcobol.cc
+++ b/libgcobol/libgcobol.cc
@@ -7961,9 +7961,70 @@ normalize_for_inspect_format_4(const cblc_field_t  *var,
   return retval;
   }
 
+// The compiler ensures that every operand uses the target encoding, so an
+// ordinary operand can be used directly.
+static inline const char *
+string_operand(const cblc_referlet_t &refer,
+               charmap_t             *charmap,
+               size_t                 stride,
+               char                   figurative[4],
+               size_t                *size)
+  {
+  const cblc_field_t *field = refer.field;
+  if( !field )
+    {
+    *size = 0;
+    return figurative;
+    }
+
+  cbl_figconst_t figconst =
+                  static_cast<cbl_figconst_t>(field->attr & FIGCONST_MASK);
+  // We have a corner case to deal with:
+  if(    !figconst
+      && field->name[0] == 'N'
+      && strcmp(field->name, "NULLS") == 0 )
+    {
+    figconst = null_value_e;
+    }
+
+  if( figconst )
+    {
+    cbl_char_t figchar = '\0';
+    switch( figconst )
+      {
+      case low_value_e   :
+        figchar = charmap->low_value_character();
+        break;
+      case zero_value_e  :
+        figchar = charmap->mapped_character(ascii_0);
+        break;
+      case space_value_e :
+        figchar = charmap->mapped_character(ascii_space);
+        break;
+      case quote_value_e :
+        figchar = charmap->quote_character();
+        break;
+      case high_value_e  :
+        figchar = charmap->high_value_character();
+        break;
+      case null_value_e:
+        break;
+      default:
+        abort();
+        break;
+      }
+    charmap->putch(figchar, figurative, size_t(0));
+    *size = stride;
+    return figurative;
+    }
+
+  *size = refer.size;
+  return as_chars(field->data + refer.offset);
+  }
+
 extern "C"
 int
-__gg__string(const size_t integers[], const cblc_referlet_t *ref)
+__gg__string_1(const size_t integers[], const cblc_referlet_t *ref)
   {
   // The first integer is the count of identifier-2 values.  Call it N
   // The following N integers are the counts of each of the identifier-1
@@ -7988,7 +8049,6 @@ __gg__string(const size_t integers[], const 
cblc_referlet_t *ref)
   // controls all the parameters.
   cbl_encoding_t tgt_encoding = tgt->encoding;
   charmap_t *charmap = __gg__get_charmap(tgt_encoding);
-  int stride = charmap->stride();
 
   // Pick up the rest of the parameters
   size_t tgt_o = ref[index_cblc].offset;
@@ -7996,7 +8056,7 @@ __gg__string(const size_t integers[], const 
cblc_referlet_t *ref)
   index_cblc += 1;
 
   char  *dest         = as_chars(tgt->data + tgt_o);
-  size_t dest_length = tgt_s/stride;
+  size_t dest_length = tgt_s;
 
   // Skip over the index of POINTER:
   index_cblc += 1;
@@ -8006,22 +8066,22 @@ __gg__string(const size_t integers[], const 
cblc_referlet_t *ref)
   int overflow = 0;
   if( ref[INDEX_OF_POINTER].field )
     {
-    int p  = (size_t)__gg__int128_from_qualified_field(
-                                                    ref[INDEX_OF_POINTER]
-                                                      .field,
-                                                    ref[INDEX_OF_POINTER]
-                                                      .offset,
-                                                    ref[INDEX_OF_POINTER].size
-                                                    );
-    if( p<0 )
+    __int128 p = __gg__int128_from_qualified_field(
+                                              ref[INDEX_OF_POINTER].field,
+                                              ref[INDEX_OF_POINTER].offset,
+                                              ref[INDEX_OF_POINTER].size);
+    if( p < 1 || static_cast<unsigned __int128>(p) > dest_length )
       {
       overflow = 1;
       }
-    pointer = p - 1;
+    else
+      {
+      pointer = static_cast<size_t>(p - 1);
+      }
     }
 
   // Make sure that the destination pointer is within the destination
-  if( pointer < dest_length )
+  if( !overflow && pointer < dest_length )
     {
     // We are go for looping through identifier-2 values:
 
@@ -8030,6 +8090,7 @@ __gg__string(const size_t integers[], const 
cblc_referlet_t *ref)
     // Pick up the number of identifier-2 values
     size_t N = integers[index_int++];
 
+    std::string delimiter;
     for( size_t i=0; i<N; i++ )
       {
       // Pick up the number of M identifier-1 values for this list of
@@ -8037,70 +8098,281 @@ __gg__string(const size_t integers[], const 
cblc_referlet_t *ref)
       size_t M = integers[index_int++];
 
       // Pick up the identifier_2 DELIMITED BY value
-      std::u32string str_id2 = normalize_for_inspect_format_4(
-                                                        ref[index_cblc].field,
-                                                        ref[index_cblc].offset,
-                                                        ref[index_cblc].size,
-                                                        tgt_encoding);
+      char fig_id2[4];
+      size_t str_id2_size;
+      const char *str_id2 = string_operand(ref[index_cblc],
+                                            charmap,
+                                            1,
+                                            fig_id2,
+                                            &str_id2_size);
       index_cblc += 1;
 
+      // Preserve the delimiter in case it overlaps the target.
+      delimiter.assign(str_id2, str_id2_size);
+
       for(size_t j=0; j<M; j++)
         {
         // Pick up the next id-1 source string for the current id-2 delimiter
-        std::u32string str_id1 = normalize_for_inspect_format_4(
-                                                        ref[index_cblc].field,
-                                                        ref[index_cblc].offset,
-                                                        ref[index_cblc].size,
-                                                        tgt_encoding);
+        char fig_id1[4];
+        size_t str_id1_size;
+        const char *str_id1 = string_operand(ref[index_cblc],
+                                              charmap,
+                                              1,
+                                              fig_id1,
+                                              &str_id1_size);
         index_cblc += 1;
 
         size_t nfound;
-        if( str_id2.size() == 0 )
+        if( delimiter.empty() )
           {
           // No given delimiter means DELIMITED BY SIZE
-          nfound = str_id1.size();
+          nfound = str_id1_size;
+          }
+        else if( delimiter.size() == 1 )
+          {
+          // A one-character delimiter is overwhelmingly the common case.
+          const void *found = memchr(str_id1,
+                                     static_cast<unsigned char>(delimiter[0]),
+                                     str_id1_size);
+          nfound = found
+                 ? static_cast<size_t>(
+                              static_cast<const char *>(found) - str_id1)
+                 : str_id1_size;
           }
         else
           {
           // We have an id2, so we look for it inside id1
-          nfound = str_id1.find(str_id2);
-          if( nfound == std::u32string::npos )
-            {
-            nfound = str_id1.size();
-            }
+          const char *found = std::search(str_id1,
+                                          str_id1 + str_id1_size,
+                                          delimiter.begin(),
+                                          delimiter.end());
+          nfound = static_cast<size_t>(found - str_id1);
+          }
+
+        // We have found id2 inside id1 at location nfound.
+        size_t available = dest_length - pointer;
+        size_t count = std::min(nfound, available);
+        memmove(dest + pointer, str_id1, count);
+        pointer += count;
+        if( count != nfound )
+          {
+          overflow = 1;
           }
+        if( overflow )
+          {
+          break;
+          }
+        }
+      if( overflow )
+        {
+        break;
+        }
+      }
+
+    // Update the pointer, if there is one
+    if( ref[INDEX_OF_POINTER].field )
+      {
+      __gg__int128_to_qualified_field(ref[INDEX_OF_POINTER].field,
+                                      ref[INDEX_OF_POINTER].offset,
+                                      ref[INDEX_OF_POINTER].size,
+                                      (__int128)(pointer+1),
+                                      0,
+                                      truncation_e);
+      }
+    }
+  else
+    {
+    // The initial pointer is not inside the destination
+    overflow = 1;
+    }
+
+  return overflow;
+  }
+
+static size_t
+find_string_24(const char *str_id1,
+               size_t      str_id1_size,
+               const char *str_id2,
+               size_t      str_id2_size,
+               size_t      stride)
+  {
+  size_t id1_characters = str_id1_size / stride;
+  size_t id2_characters = str_id2_size / stride;
 
+  if( id2_characters == 0 || id2_characters > id1_characters )
+    {
+    return id1_characters;
+    }
 
+  size_t last = id1_characters - id2_characters;
+  if( stride == 2 )
+    {
+    uint16_t first = load_unaligned<uint16_t>(str_id2);
+    for(size_t i=0; i<=last; i++)
+      {
+      const char *candidate = str_id1 + i * stride;
+      if(    load_unaligned<uint16_t>(candidate) == first
+          && (   id2_characters == 1
+              || memcmp(candidate, str_id2, str_id2_size) == 0) )
+        {
+        return i;
+        }
+      }
+    }
+  else
+    {
+    uint32_t first = load_unaligned<uint32_t>(str_id2);
+    for(size_t i=0; i<=last; i++)
+      {
+      const char *candidate = str_id1 + i * stride;
+      if(    load_unaligned<uint32_t>(candidate) == first
+          && (   id2_characters == 1
+              || memcmp(candidate, str_id2, str_id2_size) == 0) )
+        {
+        return i;
+        }
+      }
+    }
+  return id1_characters;
+  }
+
+extern "C"
+int
+__gg__string_24(const size_t integers[], const cblc_referlet_t *ref)
+  {
+  // The first integer is the count of identifier-2 values.  Call it N
+  // The following N integers are the counts of each of the identifier-1
+  // values,
+  // one for each identifier-1.  Call them M.
+
+  // The first refer is the target
+  // The second refer is the pointer
+  // The third refer is identifier-2 for N1
+  // That's followed by M1 identifier-1 values
+  // That's followed by identifier2 for N2
+  // And so on
+
+  static const int INDEX_OF_POINTER = 1;
+
+  size_t index_cblc = 0 ;
+
+  // Pick up the target
+  const cblc_field_t *tgt = ref[index_cblc].field;
+
+  // Pick up the target encoding, which according to the ISO specification
+  // controls all the parameters.
+  cbl_encoding_t tgt_encoding = tgt->encoding;
+  charmap_t *charmap = __gg__get_charmap(tgt_encoding);
+  size_t stride = static_cast<size_t>(charmap->stride());
+
+  // Pick up the rest of the parameters
+  size_t tgt_o = ref[index_cblc].offset;
+  size_t tgt_s = ref[index_cblc].size;
+  index_cblc += 1;
+
+  char  *dest        = as_chars(tgt->data + tgt_o);
+  size_t dest_length = tgt_s / stride;
+
+  // Skip over the index of POINTER:
+  index_cblc += 1;
+
+  // Pick up the pointer, if any
+  size_t pointer = 0;
+  int overflow = 0;
+  if( ref[INDEX_OF_POINTER].field )
+    {
+    __int128 p = __gg__int128_from_qualified_field(
+                                              ref[INDEX_OF_POINTER].field,
+                                              ref[INDEX_OF_POINTER].offset,
+                                              ref[INDEX_OF_POINTER].size);
+    if( p < 1 || static_cast<unsigned __int128>(p) > dest_length )
+      {
+      overflow = 1;
+      }
+    else
+      {
+      pointer = static_cast<size_t>(p - 1);
+      }
+    }
+
+  // Make sure that the destination pointer is within the destination
+  if( !overflow && pointer < dest_length )
+    {
+    // We are go for looping through identifier-2 values:
+
+    size_t index_int = 0;
+
+    // Pick up the number of identifier-2 values
+    size_t N = integers[index_int++];
+
+    std::string delimiter;
+    for(size_t i=0; i<N; i++)
+      {
+      // Pick up the number of M identifier-1 values for this list of
+      // identifier-2 values:
+      size_t M = integers[index_int++];
+
+      // Pick up the identifier_2 DELIMITED BY value
+      char fig_id2[4];
+      size_t str_id2_size;
+      const char *str_id2 = string_operand(ref[index_cblc],
+                                            charmap,
+                                            stride,
+                                            fig_id2,
+                                            &str_id2_size);
+      index_cblc += 1;
+
+      // Preserve the delimiter in case it overlaps the target.
+      delimiter.assign(str_id2, str_id2_size);
+
+      for(size_t j=0; j<M; j++)
+        {
+        // Pick up the next id-1 source string for the current id-2 delimiter
+        char fig_id1[4];
+        size_t str_id1_size;
+        const char *str_id1 = string_operand(ref[index_cblc],
+                                              charmap,
+                                              stride,
+                                              fig_id1,
+                                              &str_id1_size);
+        index_cblc += 1;
+
+        size_t nfound;
+        if( delimiter.empty() )
           {
-          // We have found id2 inside id1 at location nfound.
+          // No given delimiter means DELIMITED BY SIZE
+          nfound = str_id1_size / stride;
+          }
+        else
+          {
+          // We have an id2, so we look for it inside id1
+          nfound = find_string_24(str_id1,
+                                  str_id1_size,
+                                  delimiter.data(),
+                                  delimiter.size(),
+                                  stride);
+          }
 
-          // Convert the UTF32 to the original encoding:
-          size_t bytes_converted;
-          char *converted = __gg__miconverter(HOST_32_ENCODING,
-                                              tgt_encoding,
-                                              str_id1.data(),
-                                              nfound*width_of_utf32,
-                                              &bytes_converted );
-          size_t k = 0;
-          while(k < nfound)
-            {
-            if( pointer >= dest_length )
-              {
-              overflow = 1;
-              break;
-              }
-            cbl_char_t ch = charmap->getch(converted, k*stride);
-            charmap->putch(ch, dest, pointer*stride);
-            k += 1;
-            pointer += 1;
-            }
-          free(converted);
+        // We have found id2 inside id1 at location nfound.
+        size_t available = dest_length - pointer;
+        size_t count = std::min(nfound, available);
+        memmove(dest + pointer * stride,
+                str_id1,
+                count * stride);
+        pointer += count;
+        if( count != nfound )
+          {
+          overflow = 1;
           }
         if( overflow )
           {
           break;
           }
         }
+      if( overflow )
+        {
+        break;
+        }
       }
 
     // Update the pointer, if there is one
@@ -8123,6 +8395,16 @@ __gg__string(const size_t integers[], const 
cblc_referlet_t *ref)
   return overflow;
   }
 
+extern "C"
+int
+__gg__string(const size_t integers[], const cblc_referlet_t *ref)
+  {
+  const charmap_t *charmap = __gg__get_charmap(ref[0].field->encoding);
+  return charmap->stride() == 1
+       ? __gg__string_1(integers, ref)
+       : __gg__string_24(integers, ref);
+  }
+
 static
 void
 display_both(cblc_field_t  *field,
@@ -10006,9 +10288,53 @@ __gg__assign_value_from_stack(cblc_field_t *dest, 
__int128 parameter)
     }
   }
 
-extern "C"
-int
-__gg__unstring( const cblc_referlet_t *id2,
+struct unstring_finder_1
+  {
+  static size_t
+  find(const char *str_id1,
+       size_t      str_id1_size,
+       const char *str_id2,
+       size_t      str_id2_size,
+       size_t)
+    {
+    if( str_id2_size == 1 )
+      {
+      const void *found = memchr(str_id1,
+                                 static_cast<unsigned char>(str_id2[0]),
+                                 str_id1_size);
+      return found
+           ? static_cast<size_t>(static_cast<const char *>(found) - str_id1)
+           : str_id1_size;
+      }
+
+    const char *found = std::search(str_id1,
+                                    str_id1 + str_id1_size,
+                                    str_id2,
+                                    str_id2 + str_id2_size);
+    return static_cast<size_t>(found - str_id1);
+    }
+  };
+
+struct unstring_finder_24
+  {
+  static size_t
+  find(const char *str_id1,
+       size_t      str_id1_size,
+       const char *str_id2,
+       size_t      str_id2_size,
+       size_t      stride)
+    {
+    return find_string_24(str_id1,
+                          str_id1_size,
+                          str_id2,
+                          str_id2_size,
+                          stride);
+    }
+  };
+
+template <typename finder_t>
+static int
+unstring_fixed( const cblc_referlet_t *id2,
                 const cblc_referlet_t *id4,
                 const cblc_referlet_t *id5,
                 const cblc_referlet_t *id6,
@@ -10023,7 +10349,8 @@ __gg__unstring( const cblc_referlet_t *id2,
                 size_t        id7_s,
                 cblc_field_t *id8,        // Count of identifier-4 updates
                 size_t        id8_o,
-                size_t        id8_s)
+                size_t        id8_s,
+                size_t        stride_id1)
   {
   // The names of the parameters are based on the ISO 1989:2014 specification.
 
@@ -10043,11 +10370,10 @@ __gg__unstring( const cblc_referlet_t *id2,
   size_t left=0;
   size_t right=0;
 
-  std::u32string str_id1;
-  std::vector<std::u32string> delimiters;
+  std::string str_id1;
+  std::vector<std::string> delimiters;
 
-  const charmap_t *charmap_id1 = __gg__get_charmap(id1->encoding);
-  int stride_id1 = charmap_id1->stride();
+  charmap_t *charmap_id1 = __gg__get_charmap(id1->encoding);
 
   if( id8  )
     {
@@ -10058,15 +10384,17 @@ __gg__unstring( const cblc_referlet_t *id2,
 
   if( id7 )
     {
-    int p = (int)__gg__int128_from_qualified_field(id7,
-                                                   id7_o,
-                                                   id7_s);
-    if( p < 1 )
+    __int128 p = __gg__int128_from_qualified_field(id7,
+                                                    id7_o,
+                                                    id7_s);
+    if(    p < 1
+        || static_cast<unsigned __int128>(p)
+                                      > std::numeric_limits<size_t>::max() )
       {
       overflow = 1;
       goto done;
       }
-    pointer = p;
+    pointer = static_cast<size_t>(p);
     }
 
   // As per the spec, if the string is zero-length; we are done.
@@ -10084,18 +10412,13 @@ __gg__unstring( const cblc_referlet_t *id2,
     }
   // pointer is one-based throughout; don't forget that
 
-  /* I thought long and hard about converting things to UTF32 for UNSTRING. It
-     was not obviously necessary.  But, darn it all, sooner or later somebody
-     is going to demand UTF-8 capability and I can't think of any obvious way
-     of being able to handle multibyte codepoints as single characters without
-     doing something like converting to UTF32.  */
+  /* The earlier implementation converted everything to UTF32.  The
+     fixed-width entry points handle their encodings directly. */
 
-  str_id1 = normalize_for_inspect_format_4( id1,
-                                            id1_o,
-                                            id1_s,
-                                            id1->encoding);
+  // Preserve identifier-1 because a receiving item can overlap it.
+  str_id1.assign(as_chars(id1->data + id1_o), id1_s);
   left = pointer-1;
-  right = str_id1.size();
+  right = str_id1.size() / stride_id1;
   if( ndelimiteds == 0 )
     {
     // There are no DELIMITED BY identifier-2 values, so we just peel off
@@ -10113,7 +10436,10 @@ __gg__unstring( const cblc_referlet_t *id2,
         {
         // The receiver is NumericDisplay with a separate sign, so, as per
         // the spec, we reduce the size by one character.
-        id_4_size = id4[receiver].size - 1;
+        if( id_4_size )
+          {
+          id_4_size -= 1;
+          }
         }
 
       // Make sure id_4_size doesn't take us past the end of the universe
@@ -10122,22 +10448,13 @@ __gg__unstring( const cblc_referlet_t *id2,
         id_4_size = right - left;
         }
 
-      // Convert the specified str_id1 characters back to id1->encoding.
-      size_t bytes_converted;
-      const char *converted = __gg__iconverter(HOST_32_ENCODING,
-                                               id1->encoding,
-                                               &str_id1[left],
-                                               (right-left)*width_of_utf32,
-                                               &bytes_converted );
-      char *duped = static_cast<char *>(
-        __gg__memdup(converted, bytes_converted));
-      // Put the converted string into place:
-      __gg__field_from_string(id4[receiver].field,
-                        id4[receiver].offset,
-                        id4[receiver].size,
-                        duped,
-                        bytes_converted);
-      free(duped);
+      // Put the specified string into place:
+      __gg__move_literala(id4[receiver].field,
+                          id4[receiver].offset,
+                          id4[receiver].size,
+                          truncation_e,
+                          str_id1.data() + left * stride_id1,
+                          id_4_size * stride_id1);
       // Update the state variables:
       left += id_4_size;
       pointer += id_4_size;
@@ -10148,31 +10465,49 @@ __gg__unstring( const cblc_referlet_t *id2,
 
   // Arriving here means there is some number of ndelimiteds
 
-  // Convert them to the same encoding as str_id1:
+  // Preserve the delimiters because receiving items can overlap them.
+  delimiters.reserve(ndelimiteds);
   for( size_t i=0; i<ndelimiteds; i++ )
     {
-    std::u32string delimiter
-        = normalize_for_inspect_format_4(id2[i].field,
-                                         id2[i].offset,
-                                         id2[i].size,
-                                         id1->encoding);
-    delimiters.push_back(delimiter);
+    char figurative[4];
+    size_t delimiter_size;
+    const char *delimiter = string_operand(id2[i],
+                                            charmap_id1,
+                                            stride_id1,
+                                            figurative,
+                                            &delimiter_size);
+    delimiters.emplace_back(delimiter, delimiter_size);
     }
 
   nreceiver = 0;
   while( left < right )
     {
+    // If we've used up all receivers, we bail at this point
+    if( nreceiver >= nreceivers )
+      {
+      break;
+      }
+
     // Starting at 'left', see if we can find any of the delimiters.  For each
     // 'left' position, we look through all of the delimiters,
 
-    int    best_delimiter = -1;
+    size_t best_delimiter = ndelimiteds;
     size_t best_leftmost = right; // This is the location of the start of ALL
     size_t best_location = right; // This is the location of the last of ALL
     for( size_t i=0; i<ndelimiteds; i++ )
       {
-      std::u32string str_id2 = delimiters[i];
-      size_t nfound = str_id1.find(str_id2, left);
-      if( nfound != std::u32string::npos )
+      const std::string &str_id2 = delimiters[i];
+      if( str_id2.empty() )
+        {
+        continue;
+        }
+      size_t nfound = left + finder_t::find(
+                                     str_id1.data() + left * stride_id1,
+                                     (right - left) * stride_id1,
+                                     str_id2.data(),
+                                     str_id2.size(),
+                                     stride_id1);
+      if( nfound != right )
         {
         // We found a delimiter
         if( nfound > best_leftmost )
@@ -10190,24 +10525,22 @@ __gg__unstring( const cblc_referlet_t *id2,
           {
           // This delimiter is flagged as ALL, so we need to see if we have
           // a flock of them:
-          size_t next = nfound + str_id2.size() ;
-          while( str_id1.find(str_id2, next ) == next )
+          size_t delimiter_characters = str_id2.size() / stride_id1;
+          size_t next = nfound + delimiter_characters;
+          while(    delimiter_characters <= right - next
+                 && memcmp(str_id1.data() + next * stride_id1,
+                           str_id2.data(),
+                           str_id2.size()) == 0 )
             {
             // We found another consecutive one at next:
             best_location = next;
-            next += str_id2.size();
+            next += delimiter_characters;
             }
           }
         }
       }
 
-    // If we've used up all receivers, we bail at this point
-    if( nreceiver >= nreceivers )
-      {
-      break;
-      }
-
-    if( best_delimiter == -1 )
+    if( best_delimiter == ndelimiteds )
       {
       // We were unable to find a delimiter, so we eat up the remainder
       // of the sender:
@@ -10219,55 +10552,38 @@ __gg__unstring( const cblc_referlet_t *id2,
 
     size_t examined = best_leftmost - left;
 
-    // Convert the data from left to leftmost_delimiter back to encoding of
-    // id1:
-    size_t bytes_converted;
-    const char *converted = __gg__iconverter(
-                           HOST_32_ENCODING,
-                           id1->encoding,
-                           &str_id1[left],
-                           (best_leftmost-left)*width_of_utf32,
-                           &bytes_converted );
-    char *duped = static_cast<char *>(
-      __gg__memdup(converted, bytes_converted));
-    // Put the converted string into place:
-    __gg__field_from_string(id4[nreceiver].field,
-                      id4[nreceiver].offset,
-                      id4[nreceiver].size,
-                      duped,
-                      bytes_converted);
-    free(duped);
+    // Put the specified string into place:
+    __gg__move_literala(id4[nreceiver].field,
+                        id4[nreceiver].offset,
+                        id4[nreceiver].size,
+                        truncation_e,
+                        str_id1.data() + left * stride_id1,
+                        examined * stride_id1);
     // Update the left edge
-    left = best_location + (best_delimiter > -1
-                            ? delimiters[best_delimiter].size()
+    left = best_location + (best_delimiter != ndelimiteds
+                            ? delimiters[best_delimiter].size() / stride_id1
                             : 0) ;
     if( id5[nreceiver].field )
       {
       // The caller wants to know what the delimiter was:
-      if( best_delimiter > -1 )
-        {
-        converted = __gg__iconverter(
-                             HOST_32_ENCODING,
-                             id1->encoding,
-                             delimiters[best_delimiter].data(),
-                             delimiters[best_delimiter].size()*width_of_utf32,
-                             &bytes_converted );
-        duped = static_cast<char *>(__gg__memdup(converted, bytes_converted));
-        __gg__field_from_string(id5[nreceiver].field,
-                          id5[nreceiver].offset,
-                          id5[nreceiver].size,
-                          duped,
-                          bytes_converted);
-        free(duped);
+      if( best_delimiter != ndelimiteds )
+        {
+        __gg__move_literala(id5[nreceiver].field,
+                            id5[nreceiver].offset,
+                            id5[nreceiver].size,
+                            truncation_e,
+                            delimiters[best_delimiter].data(),
+                            delimiters[best_delimiter].size());
         }
       else
         {
         // We didn't find a delimiter
-        __gg__field_from_string(id5[nreceiver].field,
-                          id5[nreceiver].offset,
-                          id5[nreceiver].size,
-                          "",
-                          0);
+        __gg__move_literala(id5[nreceiver].field,
+                            id5[nreceiver].offset,
+                            id5[nreceiver].size,
+                            truncation_e,
+                            "",
+                            0);
         }
       }
 
@@ -10284,7 +10600,7 @@ __gg__unstring( const cblc_referlet_t *id2,
     // Update the state variables:
     tally += 1;
     nreceiver += 1;
-    if( best_delimiter > -1  )
+    if( best_delimiter != ndelimiteds )
       {
       pointer = left+1 ;
       }
@@ -10320,6 +10636,141 @@ done:
   return overflow;
   }
 
+extern "C"
+int
+__gg__unstring_1( const cblc_referlet_t *id2,
+                  const cblc_referlet_t *id4,
+                  const cblc_referlet_t *id5,
+                  const cblc_referlet_t *id6,
+                  const cblc_field_t *id1,
+                  size_t              id1_o,
+                  size_t              id1_s,
+                  size_t              ndelimiteds,
+                  const char         *all_flags,
+                  size_t              nreceivers,
+                  cblc_field_t       *id7,
+                  size_t              id7_o,
+                  size_t              id7_s,
+                  cblc_field_t       *id8,
+                  size_t              id8_o,
+                  size_t              id8_s)
+  {
+  return unstring_fixed<unstring_finder_1>(id2,
+                                           id4,
+                                           id5,
+                                           id6,
+                                           id1,
+                                           id1_o,
+                                           id1_s,
+                                           ndelimiteds,
+                                           all_flags,
+                                           nreceivers,
+                                           id7,
+                                           id7_o,
+                                           id7_s,
+                                           id8,
+                                           id8_o,
+                                           id8_s,
+                                           1);
+  }
+
+extern "C"
+int
+__gg__unstring_24( const cblc_referlet_t *id2,
+                   const cblc_referlet_t *id4,
+                   const cblc_referlet_t *id5,
+                   const cblc_referlet_t *id6,
+                   const cblc_field_t *id1,
+                   size_t              id1_o,
+                   size_t              id1_s,
+                   size_t              ndelimiteds,
+                   const char         *all_flags,
+                   size_t              nreceivers,
+                   cblc_field_t       *id7,
+                   size_t              id7_o,
+                   size_t              id7_s,
+                   cblc_field_t       *id8,
+                   size_t              id8_o,
+                   size_t              id8_s)
+  {
+  size_t stride = static_cast<size_t>(
+                         __gg__get_charmap(id1->encoding)->stride());
+  return unstring_fixed<unstring_finder_24>(id2,
+                                            id4,
+                                            id5,
+                                            id6,
+                                            id1,
+                                            id1_o,
+                                            id1_s,
+                                            ndelimiteds,
+                                            all_flags,
+                                            nreceivers,
+                                            id7,
+                                            id7_o,
+                                            id7_s,
+                                            id8,
+                                            id8_o,
+                                            id8_s,
+                                            stride);
+  }
+
+extern "C"
+int
+__gg__unstring( const cblc_referlet_t *id2,
+                const cblc_referlet_t *id4,
+                const cblc_referlet_t *id5,
+                const cblc_referlet_t *id6,
+                const cblc_field_t *id1,
+                size_t              id1_o,
+                size_t              id1_s,
+                size_t              ndelimiteds,
+                const char         *all_flags,
+                size_t              nreceivers,
+                cblc_field_t       *id7,
+                size_t              id7_o,
+                size_t              id7_s,
+                cblc_field_t       *id8,
+                size_t              id8_o,
+                size_t              id8_s)
+  {
+  const charmap_t *charmap = __gg__get_charmap(id1->encoding);
+  if( charmap->stride() == 1 )
+    {
+    return __gg__unstring_1(id2,
+                            id4,
+                            id5,
+                            id6,
+                            id1,
+                            id1_o,
+                            id1_s,
+                            ndelimiteds,
+                            all_flags,
+                            nreceivers,
+                            id7,
+                            id7_o,
+                            id7_s,
+                            id8,
+                            id8_o,
+                            id8_s);
+    }
+  return __gg__unstring_24(id2,
+                           id4,
+                           id5,
+                           id6,
+                           id1,
+                           id1_o,
+                           id1_s,
+                           ndelimiteds,
+                           all_flags,
+                           nreceivers,
+                           id7,
+                           id7_o,
+                           id7_s,
+                           id8,
+                           id8_o,
+                           id8_s);
+  }
+
 static std::set<void *> to_be_canceled;
 
 extern "C"

Reply via email to