/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include <cassert> #include <cstdarg> #include <cstdint> #include <cstring> #include <memory> #include <stdexcept> #include <string_view> #include <type_traits> #include <folly/Likely.h> #include <folly/Memory.h> #include <folly/Portability.h> #include <folly/Range.h> #include <folly/io/IOBuf.h> #include <folly/io/IOBufQueue.h> #include <folly/lang/Bits.h> #include <folly/lang/Exception.h> /** * IOBuf Cursors provide fast iteration over IOBuf chains. * * - Cursor - Read-only access * - RWPrivateCursor - Read-write access, assumes private access to IOBuf chain * - RWUnshareCursor - Read-write access, calls unshare on write (COW) * - Appender - Write access, assumes private access to IOBuf chain * * Note that RW cursors write in the preallocated part of buffers (that is, * between the buffer's data() and tail()), while Appenders append to the end * of the buffer (between the buffer's tail() and bufferEnd()). Appenders * automatically adjust the buffer pointers, so you may only use one * Appender with a buffer chain; for this reason, Appenders assume private * access to the buffer (you need to call unshare() yourself if necessary). * * @file Cursor.h */ namespace folly { namespace io { class Cursor; class ThinCursor; // This is very useful in development, but the size perturbation is currently // causing some previously undetected bugs in unrelated projects to manifest in // CI-breaking ways. // TODO(davidgoldblatt): Fix this. #define FOLLY_IO_CURSOR_BORROW_CHECKING … #if FOLLY_IO_CURSOR_BORROW_CHECKING #define FOLLY_IO_CURSOR_BORROW_DCHECK … #else #define FOLLY_IO_CURSOR_BORROW_DCHECK(ignored) … #endif template <class Derived, class BufType> class CursorBase { … }; namespace detail { template <typename T> ThinCursor thinCursorReadSlow(ThinCursor, T&, Cursor&); ThinCursor thinCursorSkipSlow(ThinCursor, Cursor&, size_t); } // namespace detail // A register-pass facade for a Cursor. It strips out state that's only needed // down slow paths, so that it can be passed and returned efficiently in // registers. This gives up some convenience (users need to maintain that state // in a fallback Cursor), to gain performance. class ThinCursor { … }; class Cursor : public CursorBase<Cursor, const IOBuf> { … }; namespace detail { template <typename T> ThinCursor thinCursorReadSlow(ThinCursor borrowed, T& val, Cursor& fallback) { … } inline ThinCursor thinCursorSkipSlow( ThinCursor borrowed, Cursor& fallback, size_t len) { … } } // namespace detail template <class Derived> class Writable { … }; enum class CursorAccess { … }; template <CursorAccess access> class RWCursor : public CursorBase<RWCursor<access>, IOBuf>, public Writable<RWCursor<access>> { … }; RWPrivateCursor; RWUnshareCursor; /** * Append to the end of a buffer chain, growing the chain (by allocating new * buffers) in increments of at least growth bytes every time. Won't grow * (and push() and ensure() will throw) if growth == 0. * * TODO(tudorb): add a flavor of Appender that reallocates one IOBuf instead * of chaining. */ class Appender : public Writable<Appender> { … }; class QueueAppender : public Writable<QueueAppender> { … }; } // namespace io } // namespace folly #include <folly/io/Cursor-inl.h>