214 lines
6.1 KiB
C
214 lines
6.1 KiB
C
|
#ifndef __BUFFERUTILITY_H__
|
|||
|
#define __BUFFERUTILITY_H__
|
|||
|
|
|||
|
#include <algorithm>
|
|||
|
#include <cstdint>
|
|||
|
#include <stdexcept>
|
|||
|
#include <vector>
|
|||
|
|
|||
|
namespace Amass {
|
|||
|
|
|||
|
/**
|
|||
|
* @brief The Buffer class A buffer class modeled after org.jboss.netty.buffer.ChannelBuffer
|
|||
|
* +------------------+------------------+
|
|||
|
* | readable bytes | writable bytes |
|
|||
|
* | (CONTENT) | |
|
|||
|
* +------------------+------------------+
|
|||
|
* | | |
|
|||
|
* 0 <=readerIndex <= writerIndex <= size
|
|||
|
*/
|
|||
|
class Buffer {
|
|||
|
public:
|
|||
|
Buffer(size_t initialSize = 1024);
|
|||
|
void swap(Buffer &buffer);
|
|||
|
|
|||
|
int lastError();
|
|||
|
|
|||
|
inline const char *readableAddress() const {
|
|||
|
return m_buffer.data() + m_readerIndex;
|
|||
|
}
|
|||
|
inline size_t readableBytes() const {
|
|||
|
return m_writerIndex - m_readerIndex;
|
|||
|
}
|
|||
|
|
|||
|
void append(const char *data, size_t len);
|
|||
|
inline void append(std::string_view data) {
|
|||
|
append(data.data(), data.size());
|
|||
|
}
|
|||
|
|
|||
|
void appendFileContent(const std::string_view &path);
|
|||
|
|
|||
|
/**
|
|||
|
* @brief peek must POD struct
|
|||
|
* @param fd
|
|||
|
* @return [errno,size]
|
|||
|
*/
|
|||
|
template <typename T>
|
|||
|
T peek() {
|
|||
|
T t;
|
|||
|
memcpy(&t, readableAddress(), sizeof(T));
|
|||
|
return t;
|
|||
|
}
|
|||
|
|
|||
|
inline std::string peek(size_t size, bool retrieved = false) {
|
|||
|
std::string ret(readableAddress(), size);
|
|||
|
if (retrieved) retrieve(size);
|
|||
|
return ret;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @brief findCRLF
|
|||
|
* @param start if(start == nullptr),find CRLF from readableAddress.
|
|||
|
* @return
|
|||
|
*/
|
|||
|
const char *findCRLF() const;
|
|||
|
|
|||
|
const char *findCRLFCRLF() const;
|
|||
|
|
|||
|
template <typename T>
|
|||
|
const char *find(const T &data, size_t startPos = 0) {
|
|||
|
if (startPos >= readableBytes()) return nullptr;
|
|||
|
const char *pos = nullptr;
|
|||
|
if constexpr (!std::is_array_v<T>) {
|
|||
|
if (startPos + sizeof(T) > readableBytes()) return nullptr;
|
|||
|
pos = std::search(readableAddress() + startPos, (const char *)writableAddress(), (const char *)(&data),
|
|||
|
(const char *)(&data));
|
|||
|
} else {
|
|||
|
if (startPos + sizeof(T) * std::extent_v < T >> readableBytes()) return nullptr;
|
|||
|
pos = std::search(readableAddress() + startPos, (const char *)writableAddress(), (const char *)(&data[0]),
|
|||
|
(const char *)(&data[std::extent_v<T>]));
|
|||
|
}
|
|||
|
|
|||
|
return pos == writableAddress() ? nullptr : pos;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @brief findEOL
|
|||
|
* @param start if(start == nullptr),find EOL from readableAddress.
|
|||
|
* @return
|
|||
|
*/
|
|||
|
const char *findEOL(const char *start = nullptr) const;
|
|||
|
|
|||
|
/**
|
|||
|
* @brief retrieve retrieve returns void, to prevent string str(retrieve(readableBytes()),
|
|||
|
* readableBytes()); the evaluation of two functions are unspecified
|
|||
|
* @param len
|
|||
|
* @return
|
|||
|
*/
|
|||
|
bool retrieve(size_t len);
|
|||
|
|
|||
|
/**
|
|||
|
* @brief retrieveUntil retrive [begin,end)
|
|||
|
* @param end
|
|||
|
* @return
|
|||
|
*/
|
|||
|
bool retrieveUntil(const char *end);
|
|||
|
|
|||
|
/**
|
|||
|
* @brief retrieveAll
|
|||
|
* @param Return[template parameter] void,std::string,std::vector<char>
|
|||
|
* @return
|
|||
|
*/
|
|||
|
template <typename ReturnType = void>
|
|||
|
typename std::conditional_t<std::is_same_v<ReturnType, void>, void, ReturnType> retrieveAll() {
|
|||
|
if constexpr (std::is_same_v<ReturnType, std::string>) {
|
|||
|
std::string data(m_buffer.cbegin() + static_cast<int64_t>(m_readerIndex),
|
|||
|
m_buffer.cbegin() + static_cast<int64_t>(m_writerIndex));
|
|||
|
m_readerIndex = 0;
|
|||
|
m_writerIndex = 0;
|
|||
|
m_buffer[m_readerIndex] = '\0';
|
|||
|
return data;
|
|||
|
} else if constexpr (std::is_same_v<ReturnType, std::vector<char>>) {
|
|||
|
std::vector<char> data(m_buffer.cbegin() + static_cast<int64_t>(m_readerIndex),
|
|||
|
m_buffer.cbegin() + static_cast<int64_t>(m_writerIndex));
|
|||
|
m_readerIndex = 0;
|
|||
|
m_writerIndex = 0;
|
|||
|
m_buffer[m_readerIndex] = '\0';
|
|||
|
return data;
|
|||
|
} else if constexpr (std::is_same_v<ReturnType, void>) {
|
|||
|
m_readerIndex = 0;
|
|||
|
m_writerIndex = 0;
|
|||
|
m_buffer[m_readerIndex] = '\0';
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
protected:
|
|||
|
/**
|
|||
|
* @brief makeSpace 增加m_buffer的writeable区域容量,或者将可读数据前移
|
|||
|
* @param len
|
|||
|
*/
|
|||
|
void makeSpace(size_t len);
|
|||
|
|
|||
|
inline size_t writableBytes() const {
|
|||
|
return m_buffer.size() - m_writerIndex;
|
|||
|
}
|
|||
|
inline const char *writableAddress() const {
|
|||
|
return m_buffer.data() + m_writerIndex;
|
|||
|
}
|
|||
|
inline char *writableAddress() {
|
|||
|
return m_buffer.data() + m_writerIndex;
|
|||
|
}
|
|||
|
|
|||
|
private:
|
|||
|
std::vector<char> m_buffer;
|
|||
|
size_t m_readerIndex = 0;
|
|||
|
size_t m_writerIndex = 0;
|
|||
|
int m_lastError;
|
|||
|
};
|
|||
|
|
|||
|
template <typename T>
|
|||
|
class VectorView {
|
|||
|
public:
|
|||
|
using size_type = std::size_t;
|
|||
|
using const_reference = const T &;
|
|||
|
VectorView(const T *ptr, size_type length) : m_data(ptr), m_length(length) {
|
|||
|
}
|
|||
|
constexpr size_type size() const noexcept {
|
|||
|
return m_length;
|
|||
|
}
|
|||
|
constexpr size_type length() const noexcept {
|
|||
|
return m_length;
|
|||
|
}
|
|||
|
constexpr const_reference front() const {
|
|||
|
return m_data[0];
|
|||
|
}
|
|||
|
constexpr const_reference back() const {
|
|||
|
return m_data[size() - 1];
|
|||
|
}
|
|||
|
constexpr const_reference at(size_type pos) const {
|
|||
|
return m_data[pos];
|
|||
|
}
|
|||
|
|
|||
|
private:
|
|||
|
const T *m_data;
|
|||
|
size_type m_length;
|
|||
|
};
|
|||
|
|
|||
|
template <typename T>
|
|||
|
class BufferView {
|
|||
|
public:
|
|||
|
BufferView() {
|
|||
|
}
|
|||
|
BufferView(const T *data, size_t size) : m_data(data), m_length(size), m_current(data) {
|
|||
|
}
|
|||
|
bool empty() const {
|
|||
|
return m_data == nullptr || (m_current > (m_data + m_length));
|
|||
|
}
|
|||
|
size_t size() const {
|
|||
|
return m_data + m_length - m_current;
|
|||
|
}
|
|||
|
void read(T *buffer, size_t size) {
|
|||
|
std::copy(m_current, m_current + size, buffer);
|
|||
|
m_current += size;
|
|||
|
}
|
|||
|
|
|||
|
private:
|
|||
|
const T *m_data = nullptr;
|
|||
|
size_t m_length = 0;
|
|||
|
const T *m_current = nullptr;
|
|||
|
};
|
|||
|
|
|||
|
} // namespace Amass
|
|||
|
|
|||
|
#endif // __BUFFERUTILITY_H__
|