/**************************************************************************/1/* span.h */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#pragma once3132#include "core/error/error_macros.h"33#include "core/typedefs.h"3435// Equivalent of std::span.36// Represents a view into a contiguous memory space.37// DISCLAIMER: This data type does not own the underlying buffer. DO NOT STORE IT.38// Additionally, for the lifetime of the Span, do not resize the buffer, and do not insert or remove elements from it.39// Failure to respect this may lead to crashes or undefined behavior.40template <typename T>41class Span {42const T *_ptr = nullptr;43uint64_t _len = 0;4445public:46static constexpr bool is_string = std::disjunction_v<47std::is_same<T, char>,48std::is_same<T, char16_t>,49std::is_same<T, char32_t>,50std::is_same<T, wchar_t>>;5152_FORCE_INLINE_ constexpr Span() = default;5354_FORCE_INLINE_ Span(const T *p_ptr, uint64_t p_len) :55_ptr(p_ptr), _len(p_len) {56#ifdef DEBUG_ENABLED57// TODO In c++20, make this check run only in non-consteval, and make this constructor constexpr.58if (_ptr == nullptr && _len > 0) {59ERR_PRINT("Internal bug, please report: Span was created from nullptr with size > 0. Recovering by using size = 0.");60_len = 0;61}62#endif63}6465// Allows creating Span directly from C arrays and string literals.66template <size_t N>67_FORCE_INLINE_ constexpr Span(const T (&p_array)[N]) :68_ptr(p_array), _len(N) {69if constexpr (is_string) {70// Cut off the \0 terminator implicitly added to string literals.71if (N > 0 && p_array[N - 1] == '\0') {72_len--;73}74}75}7677_FORCE_INLINE_ constexpr uint64_t size() const { return _len; }78_FORCE_INLINE_ constexpr bool is_empty() const { return _len == 0; }7980_FORCE_INLINE_ constexpr const T *ptr() const { return _ptr; }8182// NOTE: Span subscripts sanity check the bounds to avoid undefined behavior.83// This is slower than direct buffer access and can prevent autovectorization.84// If the bounds are known, use ptr() subscript instead.85_FORCE_INLINE_ constexpr const T &operator[](uint64_t p_idx) const {86CRASH_COND(p_idx >= _len);87return _ptr[p_idx];88}8990_FORCE_INLINE_ constexpr const T *begin() const { return _ptr; }91_FORCE_INLINE_ constexpr const T *end() const { return _ptr + _len; }9293template <typename T1>94_FORCE_INLINE_ constexpr Span<T1> reinterpret() const {95return Span<T1>(reinterpret_cast<const T1 *>(_ptr), _len * sizeof(T) / sizeof(T1));96}9798// Algorithms.99constexpr int64_t find(const T &p_val, uint64_t p_from = 0) const;100constexpr int64_t rfind(const T &p_val, uint64_t p_from) const;101_FORCE_INLINE_ constexpr int64_t rfind(const T &p_val) const { return rfind(p_val, size() - 1); }102constexpr uint64_t count(const T &p_val) const;103/// Find the index of the given value using binary search.104/// Note: Assumes that elements in the span are sorted. Otherwise, use find() instead.105template <typename Comparator = Comparator<T>>106constexpr uint64_t bisect(const T &p_value, bool p_before, Comparator compare = Comparator()) const;107};108109template <typename T>110constexpr int64_t Span<T>::find(const T &p_val, uint64_t p_from) const {111for (uint64_t i = p_from; i < size(); i++) {112if (ptr()[i] == p_val) {113return i;114}115}116return -1;117}118119template <typename T>120constexpr int64_t Span<T>::rfind(const T &p_val, uint64_t p_from) const {121for (int64_t i = p_from; i >= 0; i--) {122if (ptr()[i] == p_val) {123return i;124}125}126return -1;127}128129template <typename T>130constexpr uint64_t Span<T>::count(const T &p_val) const {131uint64_t amount = 0;132for (uint64_t i = 0; i < size(); i++) {133if (ptr()[i] == p_val) {134amount++;135}136}137return amount;138}139140template <typename T>141template <typename Comparator>142constexpr uint64_t Span<T>::bisect(const T &p_value, bool p_before, Comparator compare) const {143uint64_t lo = 0;144uint64_t hi = size();145if (p_before) {146while (lo < hi) {147const uint64_t mid = (lo + hi) / 2;148if (compare(ptr()[mid], p_value)) {149lo = mid + 1;150} else {151hi = mid;152}153}154} else {155while (lo < hi) {156const uint64_t mid = (lo + hi) / 2;157if (compare(p_value, ptr()[mid])) {158hi = mid;159} else {160lo = mid + 1;161}162}163}164return lo;165}166167// Zero-constructing Span initializes _ptr and _len to 0 (and thus empty).168template <typename T>169struct is_zero_constructible<Span<T>> : std::true_type {};170171172