123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- #ifndef STRINGBUFFER_H
- #define STRINGBUFFER_H
- #include <cstdarg>
- #include <cstring>
- #include <iostream>
- #include "utils/Check.h"
- #include "utils/Types.h"
- // ignore buffer overflow warnings with snprintf
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wformat-truncation"
- template<int N>
- class StringBuffer final {
- int length;
- Hash hash;
- static_assert(N > 0, "StringBuffer must have a positive size");
- char data[static_cast<unsigned int>(N)];
- void addToHash(char c) {
- hash = static_cast<Hash>(2120251889) * hash + static_cast<Hash>(c);
- }
- void addToHash(int from, int to) {
- for(int i = from; i < to; i++) {
- addToHash(data[i]);
- }
- }
- public:
- StringBuffer() : length(0), hash(0) {
- data[0] = '\0';
- }
- template<typename T>
- StringBuffer(const T& t) : StringBuffer() {
- append(t);
- }
- bool operator==(const char* str) const {
- return strcmp(data, str) == 0;
- }
- bool operator==(const StringBuffer& other) const {
- return length == other.length && other == data;
- }
- bool operator!=(const char* str) const {
- return !((*this) == str);
- }
- bool operator!=(const StringBuffer& other) const {
- return !((*this) == other);
- }
- operator const char*() const {
- return data;
- }
- char operator[](int index) const {
- return data[index];
- }
- int getLength() const {
- return length;
- }
- StringBuffer& append(char c) {
- if(length < N - 1) {
- data[length++] = c;
- addToHash(c);
- data[length] = '\0';
- }
- return *this;
- }
- StringBuffer& append(signed char c) {
- return append(static_cast<char>(c));
- }
- StringBuffer& append(unsigned char c) {
- return append(static_cast<char>(c));
- }
- StringBuffer& append(const char* str) {
- return appendString<const char*>(str);
- }
- StringBuffer& append(const signed char* str) {
- return appendString<const char*>(str);
- }
- StringBuffer& append(const unsigned char* str) {
- return appendString<const unsigned char*>(str);
- }
- check_format(2, 3) StringBuffer& appendFormat(const char* format, ...) {
- int left = N - length;
- va_list args;
- va_start(args, format);
- int written = vsnprintf(data + length, static_cast<unsigned int>(left),
- format, args);
- va_end(args);
- int oldLength = length;
- if(written < left) {
- length += written;
- } else {
- length = N - 1;
- }
- addToHash(oldLength, length);
- return *this;
- }
- StringBuffer& append(signed short s) {
- return appendFormat("%hd", s);
- }
- StringBuffer& append(unsigned short s) {
- return appendFormat("%hu", s);
- }
- StringBuffer& append(signed int i) {
- return appendFormat("%d", i);
- }
- StringBuffer& append(unsigned int i) {
- return appendFormat("%u", i);
- }
- StringBuffer& append(float f) {
- return appendFormat("%.2f", static_cast<double>(f));
- }
- StringBuffer& append(bool b) {
- return b ? append("true") : append("false");
- }
- template<typename T>
- StringBuffer& append(const T& t) {
- t.toString(*this);
- return *this;
- }
- template<int L>
- void toString(StringBuffer<L>& s) const {
- if(reinterpret_cast<const void*>(this) ==
- reinterpret_cast<const void*>(&s)) {
- return;
- }
- s.append(data);
- }
- StringBuffer& appendUnicode(unsigned int c) {
- if(c < (1 << 7)) {
- append(static_cast<char>(c & 0x7F));
- } else if(c < (1 << 11)) {
- append(static_cast<char>(((c >> 6) & 0x1F) | 0xC0));
- append(static_cast<char>(((c >> 0) & 0x3F) | 0x80));
- } else if(c < (1 << 16)) {
- append(static_cast<char>(((c >> 12) & 0x0F) | 0xE0));
- append(static_cast<char>(((c >> 6) & 0x3F) | 0x80));
- append(static_cast<char>(((c >> 0) & 0x3F) | 0x80));
- } else if(c < (1 << 21)) {
- append(static_cast<char>(((c >> 18) & 0x07) | 0xF0));
- append(static_cast<char>(((c >> 12) & 0x3F) | 0x80));
- append(static_cast<char>(((c >> 6) & 0x3F) | 0x80));
- append(static_cast<char>(((c >> 0) & 0x3F) | 0x80));
- }
- return *this;
- }
- StringBuffer& clear() {
- length = 0;
- hash = 0;
- data[0] = '\0';
- return *this;
- }
- Hash hashCode() const {
- return hash;
- }
- void print() const {
- std::cout << data;
- }
- void printLine() const {
- std::cout << data << '\n';
- }
- private:
- template<typename T>
- StringBuffer& appendString(T str) {
- for(int i = 0; length < N - 1 && str[i] != '\0'; length++, i++) {
- data[length] = static_cast<char>(str[i]);
- addToHash(static_cast<char>(str[i]));
- }
- data[length] = '\0';
- return *this;
- }
- };
- template<int N>
- bool operator==(const char* str, const StringBuffer<N> buffer) {
- return buffer == str;
- }
- template<int N>
- bool operator!=(const char* str, const StringBuffer<N> buffer) {
- return buffer != str;
- }
- #pragma GCC diagnostic pop
- #endif
|