AZ_NODISCARD int32_t az_span_find()

in sdk/src/azure/core/az_span.c [405:478]


AZ_NODISCARD int32_t az_span_find(az_span source, az_span target)
{
  /* This function implements the Naive string-search algorithm.
   * The rationale to use this algorithm instead of other potentially more
   * performing ones (Rabin-Karp, e.g.) is due to no additional space needed.
   * The logic:
   * 1. The function will look into each position of `source` if it contains the same value as the
   * first position of `target`.
   * 2. If it does, it could be that the next bytes in `source` are a perfect match of the remaining
   * bytes of `target`.
   * 3. Being so, it loops through the remaining bytes of `target` and see if they match exactly the
   * next bytes of `source`.
   * 4. If the loop gets to the end (all bytes of `target` are evaluated), it means `target` indeed
   * occurs in that position of `source`.
   * 5. If the loop gets interrupted before cruising through the entire `target`, the function must
   * go back to step 1. from  the next position in `source`.
   *   The loop in 5. gets interrupted if
   *     - a byte in `target` is different than `source`, in the expected corresponding position;
   *     - the loop has reached the end of `source` (and there are still remaining bytes of `target`
   *         to be checked).
   */

  int32_t source_size = az_span_size(source);
  int32_t target_size = az_span_size(target);
  const int32_t target_not_found = -1;

  if (target_size == 0)
  {
    return 0;
  }

  if (source_size < target_size)
  {
    return target_not_found;
  }

  uint8_t* source_ptr = az_span_ptr(source);
  uint8_t* target_ptr = az_span_ptr(target);

  // This loop traverses `source` position by position (step 1.)
  for (int32_t i = 0; i < (source_size - target_size + 1); i++)
  {
    // This is the check done in step 1. above.
    if (source_ptr[i] == target_ptr[0])
    {
      // The condition in step 2. has been satisfied.
      int32_t j = 1;
      // This is the loop defined in step 3.
      // The loop must be broken if it reaches the ends of `target` (step 3.) OR `source`
      // (step 5.).
      for (; j < target_size && (i + j) < source_size; j++)
      {
        // Condition defined in step 5.
        if (source_ptr[i + j] != target_ptr[j])
        {
          break;
        }
      }

      if (j == target_size)
      {
        // All bytes in `target` have been checked and matched the corresponding bytes in `source`
        // (from the start point `i`), so this is indeed an instance of `target` in that position
        // of `source` (step 4.).

        return i;
      }
    }
  }

  // If the function hasn't returned before, all positions
  // of `source` have been evaluated but `target` could not be found.
  return target_not_found;
}