HEX
Server: Apache/2.4.59 (Debian)
System: Linux keymana 4.19.0-21-cloud-amd64 #1 SMP Debian 4.19.249-2 (2022-06-30) x86_64
User: lijunjie (1003)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: //home/lijunjie/swoole-cli/swoole-src-4.8.13/src/memory/buffer.cc
/*
  +----------------------------------------------------------------------+
  | Swoole                                                               |
  +----------------------------------------------------------------------+
  | This source file is subject to version 2.0 of the Apache license,    |
  | that is bundled with this package in the file LICENSE, and is        |
  | available through the world-wide-web at the following url:           |
  | http://www.apache.org/licenses/LICENSE-2.0.html                      |
  | If you did not receive a copy of the Apache2.0 license and are unable|
  | to obtain it through the world-wide-web, please send a note to       |
  | license@swoole.com so we can mail you a copy immediately.            |
  +----------------------------------------------------------------------+
  | Author: Tianfeng Han  <rango@swoole.com>                             |
  +----------------------------------------------------------------------+
*/

#include "swoole.h"
#include "swoole_buffer.h"

namespace swoole {

BufferChunk::BufferChunk(Type type, uint32_t size) : type(type), size(size) {
    if (type == TYPE_DATA && size > 0) {
        value.ptr = new char[size];
    }
}

BufferChunk::~BufferChunk() {
    if (type == TYPE_DATA) {
        delete[] value.ptr;
    }
    if (destroy) {
        destroy(this);
    }
}

Buffer::Buffer(uint32_t _chunk_size) {
    chunk_size = _chunk_size == 0 ? INT_MAX : _chunk_size;
}

BufferChunk *Buffer::alloc(BufferChunk::Type type, uint32_t size) {
    auto *chunk = new BufferChunk(type, size);
    queue_.push(chunk);
    return chunk;
}

void Buffer::pop() {
    BufferChunk *chunk = queue_.front();
    total_length -= chunk->size;
    delete chunk;
    queue_.pop();
}

Buffer::~Buffer() {
    while (!queue_.empty()) {
        pop();
    }
}

void Buffer::append(const void *data, uint32_t size) {
    uint32_t _length = size;
    char *_pos = (char *) data;
    uint32_t _n;

    assert(size > 0);

    // buffer enQueue
    while (_length > 0) {
        _n = _length >= chunk_size ? chunk_size : _length;

        BufferChunk *chunk = alloc(BufferChunk::TYPE_DATA, _n);

        total_length += _n;

        memcpy(chunk->value.ptr, _pos, _n);
        chunk->length = _n;

        swoole_trace_log(SW_TRACE_BUFFER, "chunk_n=%lu|size=%u|chunk_len=%u|chunk=%p", count(), _n, chunk->length, chunk);

        _pos += _n;
        _length -= _n;
    }
}

void Buffer::append(const struct iovec *iov, size_t iovcnt, off_t offset) {
    size_t _length = 0;

    SW_LOOP_N(iovcnt) {
        assert(iov[i].iov_len > 0);
        assert(iov[i].iov_base != nullptr);
        _length += iov[i].iov_len;
    }

    char *pos = (char *) iov[0].iov_base;
    BufferChunk *chunk = nullptr;
    size_t iov_remain_len = iov[0].iov_len, chunk_remain_len;
    size_t i = 0;

    while (true) {
        if (chunk) {
            if (chunk->size == chunk->length) {
                chunk = nullptr;
                continue;
            } else {
                chunk_remain_len = chunk->size - chunk->length;
            }
        } else {
            if (offset > 0) {
                if (offset >= (off_t) iov[i].iov_len) {
                    offset -= iov[i].iov_len;
                    i++;
                    continue;
                } else {
                    pos = (char *) iov[i].iov_base + offset;
                    iov_remain_len = iov[i].iov_len - offset;
                    offset = 0;
                }
            }
            chunk_remain_len = _length >= chunk_size ? chunk_size : _length;
            chunk = alloc(BufferChunk::TYPE_DATA, chunk_remain_len);
        }

        size_t _n = std::min(iov_remain_len, chunk_remain_len);
        memcpy(chunk->value.ptr + chunk->length, pos, _n);
        total_length += _n;
        _length -= _n;

        swoole_trace_log(SW_TRACE_BUFFER, "chunk_n=%lu|size=%lu|chunk_len=%u|chunk=%p", count(), _n, chunk->length, chunk);

        chunk->length += _n;
        iov_remain_len -= _n;

        if (iov_remain_len == 0) {
            i++;
            if (i == iovcnt) {
                break;
            }
            iov_remain_len = iov[i].iov_len;
            pos = (char *) iov[i].iov_base;
        } else {
            pos += _n;
        }
    }
}
}  // namespace swoole