mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 03:52:35 +01:00
187 lines
5.6 KiB
C++
187 lines
5.6 KiB
C++
/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
|
|
#ident "$Id$"
|
|
/*======
|
|
This file is part of TokuDB
|
|
|
|
|
|
Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
|
|
|
|
TokuDBis is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License, version 2,
|
|
as published by the Free Software Foundation.
|
|
|
|
TokuDB is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with TokuDB. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
======= */
|
|
|
|
#ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
|
|
|
|
#ifndef _TOKUDB_BUFFER_H
|
|
#define _TOKUDB_BUFFER_H
|
|
|
|
#include "hatoku_defines.h"
|
|
#include "tokudb_debug.h"
|
|
#include "tokudb_thread.h"
|
|
#include "tokudb_vlq.h"
|
|
|
|
namespace tokudb {
|
|
|
|
// A Buffer manages a contiguous chunk of memory and supports appending new
|
|
// data to the end of the buffer, and consuming chunks from the beginning of
|
|
// the buffer. The buffer will reallocate memory when appending new data to
|
|
// a full buffer.
|
|
|
|
class buffer {
|
|
public:
|
|
inline buffer(
|
|
void* the_data,
|
|
size_t s,
|
|
size_t l) :
|
|
m_data(the_data),
|
|
m_size(s),
|
|
m_limit(l),
|
|
m_is_static(true) {
|
|
}
|
|
inline buffer() :
|
|
m_data(NULL),
|
|
m_size(0),
|
|
m_limit(0),
|
|
m_is_static(false) {
|
|
}
|
|
virtual ~buffer() {
|
|
if (!m_is_static)
|
|
free(m_data);
|
|
}
|
|
|
|
// Return a pointer to the end of the buffer suitable for appending a
|
|
// fixed number of bytes.
|
|
void* append_ptr(size_t s) {
|
|
maybe_realloc(s);
|
|
void* p = (char*)m_data + m_size;
|
|
m_size += s;
|
|
return p;
|
|
}
|
|
|
|
// Append bytes to the buffer
|
|
void append(void* p, size_t s) {
|
|
memcpy(append_ptr(s), p, s);
|
|
}
|
|
|
|
// Append an unsigned int to the buffer.
|
|
// Returns the number of bytes used to encode the number.
|
|
// Returns 0 if the number could not be encoded.
|
|
template<class T> size_t append_ui(T n) {
|
|
maybe_realloc(10); // 10 bytes is big enough for up to 64 bit number
|
|
size_t s = tokudb::vlq_encode_ui<T>(n, (char *) m_data + m_size, 10);
|
|
m_size += s;
|
|
return s;
|
|
}
|
|
|
|
// Return a pointer to the next location in the buffer where bytes are
|
|
// consumed from.
|
|
void* consume_ptr(size_t s) {
|
|
if (m_size + s > m_limit)
|
|
return NULL;
|
|
void* p = (char*)m_data + m_size;
|
|
m_size += s;
|
|
return p;
|
|
}
|
|
|
|
// Consume bytes from the buffer.
|
|
void consume(void* p, size_t s) {
|
|
memcpy(p, consume_ptr(s), s);
|
|
}
|
|
|
|
// Consume an unsigned int from the buffer.
|
|
// Returns 0 if the unsigned int could not be decoded, probably because
|
|
// the buffer is too short.
|
|
// Otherwise return the number of bytes consumed, and stuffs the decoded
|
|
// number in *p.
|
|
template<class T> size_t consume_ui(T* p) {
|
|
size_t s = tokudb::vlq_decode_ui<T>(
|
|
p,
|
|
(char*)m_data + m_size,
|
|
m_limit - m_size);
|
|
m_size += s;
|
|
return s;
|
|
}
|
|
|
|
// Write p_length bytes at an offset in the buffer
|
|
void write(void* p, size_t p_length, size_t offset) {
|
|
assert_always(offset + p_length <= m_size);
|
|
memcpy((char*)m_data + offset, p, p_length);
|
|
}
|
|
|
|
// Read p_length bytes at an offset in the buffer
|
|
void read(void* p, size_t p_length, size_t offset) {
|
|
assert_always(offset + p_length <= m_size);
|
|
memcpy(p, (char*)m_data + offset, p_length);
|
|
}
|
|
|
|
// Replace a field in the buffer with new data. If the new data size is
|
|
// different, then readjust the size of the buffer and move things around.
|
|
void replace(size_t offset, size_t old_s, void* new_p, size_t new_s) {
|
|
assert_always(offset + old_s <= m_size);
|
|
if (new_s > old_s)
|
|
maybe_realloc(new_s - old_s);
|
|
char* data_offset = (char*)m_data + offset;
|
|
if (new_s != old_s) {
|
|
size_t n = m_size - (offset + old_s);
|
|
assert_always(offset + new_s + n <= m_limit);
|
|
assert_always(offset + old_s + n <= m_limit);
|
|
memmove(data_offset + new_s, data_offset + old_s, n);
|
|
if (new_s > old_s)
|
|
m_size += new_s - old_s;
|
|
else
|
|
m_size -= old_s - new_s;
|
|
assert_always(m_size <= m_limit);
|
|
}
|
|
memcpy(data_offset, new_p, new_s);
|
|
}
|
|
|
|
// Return a pointer to the data in the buffer
|
|
void* data() const {
|
|
return m_data;
|
|
}
|
|
|
|
// Return the size of the data in the buffer
|
|
size_t size() const {
|
|
return m_size;
|
|
}
|
|
|
|
// Return the size of the underlying memory in the buffer
|
|
size_t limit() const {
|
|
return m_limit;
|
|
}
|
|
|
|
private:
|
|
// Maybe reallocate the buffer when it becomes full by doubling its size.
|
|
void maybe_realloc(size_t s) {
|
|
if (m_size + s > m_limit) {
|
|
size_t new_limit = m_limit * 2;
|
|
if (new_limit < m_size + s)
|
|
new_limit = m_size + s;
|
|
assert_always(!m_is_static);
|
|
void *new_data = realloc(m_data, new_limit);
|
|
assert_always(new_data != NULL);
|
|
m_data = new_data;
|
|
m_limit = new_limit;
|
|
}
|
|
}
|
|
private:
|
|
void* m_data;
|
|
size_t m_size;
|
|
size_t m_limit;
|
|
bool m_is_static;
|
|
};
|
|
|
|
};
|
|
|
|
#endif
|