// Copyright 2021 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CORE_FXCRT_SPAN_UTIL_H_ #define CORE_FXCRT_SPAN_UTIL_H_ #include #include #include #include "core/fxcrt/check_op.h" #include "core/fxcrt/fx_memcpy_wrappers.h" #include "core/fxcrt/span.h" namespace fxcrt { // Bounds-checked byte-for-byte copies from spans into spans. Returns a // span describing the remaining portion of the destination span. template && std::is_trivially_copyable_v>> inline pdfium::span spancpy(pdfium::span dst, pdfium::span src) { CHECK_GE(dst.size(), src.size()); // SAFETY: SFINAE ensures `sizeof(T1)` equals `sizeof(T2)`, so comparing // `size()` for equality ensures `size_bytes()` are equal, and `size_bytes()` // accurately describes `data()`. UNSAFE_BUFFERS(FXSYS_memcpy(dst.data(), src.data(), src.size_bytes())); return dst.subspan(src.size()); } // Bounds-checked byte-for-byte moves from spans into spans. Returns a // span describing the remaining portion of the destination span. template && std::is_trivially_copyable_v>> inline pdfium::span spanmove(pdfium::span dst, pdfium::span src) { CHECK_GE(dst.size(), src.size()); // SAFETY: SFINAE ensures `sizeof(T1)` equals `sizeof(T2)`, so comparing // `size()` for equality ensures `size_bytes()` are equal, and `size_bytes()` // accurately describes `data()`. UNSAFE_BUFFERS(FXSYS_memmove(dst.data(), src.data(), src.size_bytes())); return dst.subspan(src.size()); } // Bounds-checked byte-for-byte copies from spans into spans. Performs the // copy if there is room, and returns true. Otherwise does not copy anything // and returns false. template && std::is_trivially_copyable_v>> inline bool try_spancpy(pdfium::span dst, pdfium::span src) { if (dst.size() < src.size()) { return false; } // SAFETY: SFINAE ensures `sizeof(T1)` equals `sizeof(T2)`, the test above // ensures `src.size()` <= `dst.size()` which implies `src.size_bytes()` // <= `dst.size_bytes()`, and `dst.size_bytes()` describes `dst.data()`. UNSAFE_BUFFERS(FXSYS_memcpy(dst.data(), src.data(), src.size_bytes())); return true; } // Bounds-checked byte-for-byte moves from spans into spans. Peforms the // move if there is room, and returns true. Otherwise does not move anything // and returns false. template && std::is_trivially_copyable_v>> inline bool try_spanmove(pdfium::span dst, pdfium::span src) { if (dst.size() < src.size()) { return false; } // SAFETY: SFINAE ensures `sizeof(T1)` equals `sizeof(T2)`, the test above // ensures `src.size()` <= `dst.size()` which implies `src.size_bytes()` // <= `dst.size_bytes()`, and `dst.size_bytes()` describes `dst.data()`. UNSAFE_BUFFERS(FXSYS_memmove(dst.data(), src.data(), src.size_bytes())); return true; } // Bounds-checked byte-for-byte equality of same-sized spans. This is // helpful because span does not (yet) have an operator==(). template && std::is_trivially_copyable_v>> bool span_equals(pdfium::span s1, pdfium::span s2) { // SAFETY: For both `s1` and `s2`, there are `size_bytes()` valid bytes at // the corresponding `data()`, and the sizes are the same. return s1.size_bytes() == s2.size_bytes() && UNSAFE_BUFFERS(FXSYS_memcmp(s1.data(), s2.data(), s1.size_bytes())) == 0; } // Returns the first position where `needle` occurs in `haystack`. template && std::is_trivially_copyable_v>> std::optional spanpos(pdfium::span haystack, pdfium::span needle) { if (needle.empty() || needle.size() > haystack.size()) { return std::nullopt; } // After this `end_pos`, not enough characters remain in `haystack` for // a full match to occur. size_t end_pos = haystack.size() - needle.size(); for (size_t haystack_pos = 0; haystack_pos <= end_pos; ++haystack_pos) { auto candidate = haystack.subspan(haystack_pos, needle.size()); if (fxcrt::span_equals(candidate, needle)) { return haystack_pos; } } return std::nullopt; } template || !std::is_const_v>> inline pdfium::span reinterpret_span(pdfium::span s) noexcept { CHECK(alignof(T) == alignof(U) || reinterpret_cast(s.data()) % alignof(T) == 0u); // SAFETY: relies on correct conversion of size_bytes() result. return UNSAFE_BUFFERS(pdfium::make_span(reinterpret_cast(s.data()), s.size_bytes() / sizeof(T))); } } // namespace fxcrt #endif // CORE_FXCRT_SPAN_UTIL_H_