blob: a1c3733370efcd6f00b75399d8f671d7458917da [file] [log] [blame]
/* ----------------------------------------------------------------------- *//**
*
* @file OutputStreamBufferBase_impl.hpp
*
*//* ----------------------------------------------------------------------- */
#ifndef MADLIB_DBAL_OUTPUTSTREAMBUFFERBASE_IMPL_HPP
#define MADLIB_DBAL_OUTPUTSTREAMBUFFERBASE_IMPL_HPP
#include <cstring> // Needed for std::memcpy
namespace madlib {
namespace dbal {
/**
* @internal One extra byte is allocated for the terminating null character.
*/
template <class Derived, typename C, class Allocator>
OutputStreamBufferBase<Derived, C, Allocator>::OutputStreamBufferBase()
: mAllocator(), mStorageSize(kInitialBufferSize),
mStorage(mAllocator.allocate(mStorageSize + 1)) {
this->setp(mStorage, mStorage + mStorageSize);
}
template <class Derived, typename C, class Allocator>
OutputStreamBufferBase<Derived, C, Allocator>::~OutputStreamBufferBase() {
mAllocator.deallocate(mStorage, mStorageSize + 1);
}
/**
* @brief Output a string
*
* Subclasses are required to implement this method and to feed the message
* to the DBMS-specific logging routine.
* @param inMsg Null-terminated string to be output.
* @param inLength Length of inMsg (for convenience).
*/
template <class Derived, typename C, class Allocator>
void
OutputStreamBufferBase<Derived, C, Allocator>::output(C* inMsg,
std::size_t inLength) const {
static_cast<const Derived*>(this)->output(inMsg, inLength);
}
/**
* @brief Handle case when stream receives a character that does not fit
* into the current buffer any more
*
* This function will allocate a new buffer of twice the old buffer size. If
* the buffer has already the maximum size kMaxBufferSize, eof is returned
* to indicate that the buffer cannot take any more input before a flush.
*/
template <class Derived, typename C, class Allocator>
typename OutputStreamBufferBase<Derived, C, Allocator>::int_type
OutputStreamBufferBase<Derived, C, Allocator>::overflow(int_type c) {
if (this->pptr() >= this->epptr()) {
if (mStorageSize >= kMaxBufferSize)
return traits_type::eof();
uint32_t newStorageSize = mStorageSize * 2;
C* newStorage = mAllocator.allocate(newStorageSize + 1);
std::copy(mStorage, mStorage + mStorageSize, newStorage);
mAllocator.deallocate(mStorage, mStorageSize + 1);
mStorage = newStorage;
madlib_assert(
this->pptr() == this->epptr() &&
this->pptr() - this->pbase() == static_cast<int64_t>(mStorageSize),
std::logic_error("Internal error: Logging buffer has become "
"inconsistent"));
this->setp(mStorage, mStorage + newStorageSize);
this->pbump(mStorageSize);
mStorageSize = newStorageSize;
} else if (c == traits_type::eof())
return traits_type::eof();
*this->pptr() = static_cast<C>(c);
this->pbump(1);
return traits_type::not_eof(c);
}
/**
* @brief Flush and reset buffer.
*/
template <class Derived, typename C, class Allocator>
int
OutputStreamBufferBase<Derived, C, Allocator>::sync() {
std::ptrdiff_t length = this->pptr() - this->pbase();
mStorage[length] = '\0';
output(mStorage, length);
this->setp(mStorage, mStorage + mStorageSize);
return 0;
}
} // namespace dbal
} // namespace madlib
#endif // defined(MADLIB_OUTPUTSTREAMBUFFERBASE_IMPL_HPP)