folly/folly/io/Cursor.h

/*
 * 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>