Repository: godotengine/godot
File: core/templates/span.h (C/C++)

Code before:
public:
	_FORCE_INLINE_ constexpr Span() = default;
	_FORCE_INLINE_ constexpr Span(const T *p_ptr, uint64_t p_len) :
			_ptr(p_ptr), _len(p_len) {}

	_FORCE_INLINE_ constexpr uint64_t size() const { return _len; }
	_FORCE_INLINE_ constexpr bool is_empty() const { return _len == 0; }

	_FORCE_INLINE_ constexpr const T *ptr() const { return _ptr; }

	// NOTE: Span subscripts sanity check the bounds to avoid undefined behavior.
	//       This is slower than direct buffer access and can prevent autovectorization.
	//       If the bounds are known, use ptr() subscript instead.
	_FORCE_INLINE_ constexpr const T &operator[](uint64_t p_idx) const {
		CRASH_COND(p_idx >= _len);
		return _ptr[p_idx];
	}

	_FORCE_INLINE_ constexpr const T *begin() const { return _ptr; }
	_FORCE_INLINE_ constexpr const T *end() const { return _ptr + _len; }

	// Algorithms.
	constexpr int64_t find(const T &p_val, int64_t p_from = 0) const;
	constexpr int64_t find_seq(const Span<T> &p_span, int64_t p_from = 0) const;
	constexpr int64_t rfind(const T &p_val, int64_t p_from = 0) const;
	constexpr int64_t rfind_seq(const Span<T> &p_span, int64_t p_from = 0) const;
	constexpr uint64_t count(const T &p_val) const;
};

template <typename T>
constexpr int64_t Span<T>::find(const T &p_val, int64_t p_from) const {
	if (p_from < 0 || size() == 0) {
		return -1;
	}

	for (uint64_t i = p_from; i < size(); i++) {
		if (ptr()[i] == p_val) {
			return i;
		}
	}

	return -1;
}

template <typename T>
constexpr int64_t Span<T>::find_seq(const Span<T> &p_span, int64_t p_from) const {
	for (int64_t i = p_from; i < size() - p_span.size(); i++) {
		bool found = true;
		for (int64_t j = 0; j < p_span.size(); j++){
			if(ptr()[i + j] != p_span.ptr()[j]){
				found = false;

Review comment (suggestion):
Careful, 0 is not a good default value here. See how I handled it in https://github.com/godotengine/godot/pull/104286:

```suggestion
	constexpr int64_t rfind_seq(const Span<T> &p_span, int64_t p_from) const;
	_FORCE_INLINE_ constexpr int64_t rfind_seq(const Span<T> &p_span) const { return rfind_seq(p_span, size() - 1);
```

Code after:

public:
	static constexpr bool is_string = std::disjunction_v<
			std::is_same<T, char>,
			std::is_same<T, char16_t>,
			std::is_same<T, char32_t>,
			std::is_same<T, wchar_t>>;

	_FORCE_INLINE_ constexpr Span() = default;

	_FORCE_INLINE_ Span(const T *p_ptr, uint64_t p_len) :
			_ptr(p_ptr), _len(p_len) {
#ifdef DEBUG_ENABLED
		// TODO In c++20, make this check run only in non-consteval, and make this constructor constexpr.
		if (_ptr == nullptr && _len > 0) {
			ERR_PRINT("Internal bug, please report: Span was created from nullptr with size > 0. Recovering by using size = 0.");
			_len = 0;
		}
#endif
	}

	// Allows creating Span directly from C arrays and string literals.
	template <size_t N>
	_FORCE_INLINE_ constexpr Span(const T (&p_array)[N]) :
			_ptr(p_array), _len(N) {
		if constexpr (is_string) {
			// Cut off the \0 terminator implicitly added to string literals.
			if (N > 0 && p_array[N - 1] == '\0') {
				_len--;
			}
		}
	}

	_FORCE_INLINE_ constexpr uint64_t size() const { return _len; }
	_FORCE_INLINE_ constexpr bool is_empty() const { return _len == 0; }

	_FORCE_INLINE_ constexpr const T *ptr() const { return _ptr; }

	// NOTE: Span subscripts sanity check the bounds to avoid undefined behavior.
	//       This is slower than direct buffer access and can prevent autovectorization.
	//       If the bounds are known, use ptr() subscript instead.
	_FORCE_INLINE_ constexpr const T &operator[](uint64_t p_idx) const {
		CRASH_COND(p_idx >= _len);
		return _ptr[p_idx];
	}

	_FORCE_INLINE_ constexpr const T *begin() const { return _ptr; }
	_FORCE_INLINE_ constexpr const T *end() const { return _ptr + _len; }

	template <typename T1>
	_FORCE_INLINE_ constexpr Span<T1> reinterpret() const {