susumu.yata
null+****@clear*****
Tue Dec 16 10:39:46 JST 2014
susumu.yata 2014-10-30 18:49:12 +0900 (Thu, 30 Oct 2014) New Revision: 8457be5a2e351ddfc399bdc98669e0e27c48290b https://github.com/groonga/grnxx/commit/8457be5a2e351ddfc399bdc98669e0e27c48290b Message: Enable String. Added files: lib/grnxx/string.cpp Modified files: include/grnxx/string.hpp lib/grnxx/Makefile.am test/test_string.cpp Modified: include/grnxx/string.hpp (+239 -239) =================================================================== --- include/grnxx/string.hpp 2014-10-30 18:43:20 +0900 (c595f3a) +++ include/grnxx/string.hpp 2014-10-30 18:49:12 +0900 (0ef00a5) @@ -3,6 +3,9 @@ #include <cstring> +#include "grnxx/error.hpp" +#include "grnxx/memory.hpp" + namespace grnxx { // Reference to a byte string. @@ -188,245 +191,242 @@ inline bool operator>=(const char *lhs, const StringCRef &rhs) { return rhs <= lhs; } -//class String { -// public: -// String() : buf_(), size_(0), capacity_(0) {} -// ~String() {} - -// String(String &&arg) -// : buf_(std::move(arg.buf_)), -// size_(arg.size_), -// capacity_(arg.capacity_) { -// arg.size_ = 0; -// arg.capacity_ = 0; -// } - -// String &operator=(String &&arg) { -// buf_ = std::move(arg.buf_); -// size_ = arg.size_; -// capacity_ = arg.capacity_; -// arg.size_ = 0; -// arg.capacity_ = 0; -// return *this; -// } - -// operator StringCRef() const { -// return ref(); -// } - -// StringCRef ref(size_t offset = 0) const { -// return StringCRef(buf_.get() + offset, size_ - offset); -// } -// StringCRef ref(size_t offset, size_t size) const { -// return StringCRef(buf_.get() + offset, size); -// } - -// char &operator[](size_t i) { -// return buf_[i]; -// } -// const char &operator[](size_t i) const { -// return buf_[i]; -// } - -// char &front() { -// return buf_[0]; -// } -// const char &front() const { -// return buf_[0]; -// } - -// char &back() { -// return buf_[size_ - 1]; -// } -// const char &back() const { -// return buf_[size_ - 1]; -// } - -// char *data() { -// return buf_.get(); -// } -// const char *data() const { -// return buf_.get(); -// } - -// size_t size() const { -// return size_; -// } -// size_t capacity() const { -// return capacity_; -// } - -// bool reserve(Error *error, size_t new_size) { -// if (new_size <= capacity_) { -// return true; -// } -// return resize_buf(error, new_size); -// } - -// bool assign(Error *error, const StringCRef &arg) { -// if (arg.size() > capacity_) { -// if (!resize_buf(error, arg.size())) { -// return false; -// } -// } -// std::memcpy(buf_.get(), arg.data(), arg.size()); -// size_ = arg.size(); -// return true; -// } -// bool assign(Error *error, const char *data, size_t size) { -// return assign(error, StringCRef(data, size)); -// } - -// bool resize(Error *error, size_t new_size) { -// if (new_size > capacity_) { -// if (!resize_buf(error, new_size)) { -// return false; -// } -// } -// size_ = new_size; -// return true; -// } -// bool resize(Error *error, size_t new_size, char value) { -// if (new_size > capacity_) { -// if (!resize_buf(error, new_size)) { -// return false; -// } -// } -// if (new_size > size_) { -// std::memset(buf_.get() + size_, value, new_size - size_); -// } -// size_ = new_size; -// return true; -// } - -// void clear() { -// size_ = 0; -// } - -// bool push_back(Error *error, char value) { -// if (size_ == capacity_) { -// if (!resize_buf(error, size_ + 1)) { -// return false; -// } -// } -// buf_[size_] = value; -// ++size_; -// return true; -// } -// void pop_back() { -// --size_; -// } - -// bool append(Error *error, const StringCRef &arg) { -// if ((size_ + arg.size()) > capacity_) { -// if ((arg.data() >= buf_.get()) && (arg.data() < (buf_.get() + size_))) { -// // Note that "arg" will be deleted in resize_buf() if "arg" is a part -// // of "*this". -// return append_overlap(error, arg); -// } else if (!resize_buf(error, (size_ + arg.size()))) { -// return false; -// } -// } -// std::memcpy(buf_.get() + size_, arg.data(), arg.size()); -// size_ += arg.size(); -// return true; -// } -// bool append(Error *error, const char *data, size_t size) { -// return append(error, StringCRef(data, size)); -// } - -// void swap(size_t i, size_t j) { -// char temp = buf_[i]; -// buf_[i] = buf_[j]; -// buf_[j] = temp; -// } - -// // Compare a strings. -// bool operator==(const StringCRef &arg) const { -// return ref() == arg; -// } -// bool operator!=(const StringCRef &arg) const { -// return ref() != arg; -// } -// bool operator<(const StringCRef &arg) const { -// return ref() < arg; -// } -// bool operator>(const StringCRef &arg) const { -// return ref() > arg; -// } -// bool operator<=(const StringCRef &arg) const { -// return ref() <= arg; -// } -// bool operator>=(const StringCRef &arg) const { -// return ref() >= arg; -// } - -// // Compare a string with a zero-terminated string. -// bool operator==(const char *arg) const { -// return ref() == arg; -// } -// bool operator!=(const char *arg) const { -// return ref() != arg; -// } -// bool operator<(const char *arg) const { -// return ref() < arg; -// } -// bool operator>(const char *arg) const { -// return ref() > arg; -// } -// bool operator<=(const char *arg) const { -// return ref() <= arg; -// } -// bool operator>=(const char *arg) const { -// return ref() >= arg; -// } - -// // Return true if "*this" starts with "arg". -// bool starts_with(const StringCRef &arg) const { -// return ref().starts_with(arg); -// } -// bool starts_with(const char *arg) const { -// return ref().starts_with(arg); -// } - -// // Return true if "*this" ends with "arg". -// bool ends_with(const StringCRef &arg) const { -// return ref().ends_with(arg); -// } -// bool ends_with(const char *arg) const { -// return ref().ends_with(arg); -// } - -// private: -// unique_ptr<char[]> buf_; -// size_t size_; -// size_t capacity_; - -// // Assume new_size > capacity_. -// bool resize_buf(Error *error, size_t new_size); -// // Resize the internal buffer and append a part of "*this". -// bool append_overlap(Error *error, const StringCRef &arg); -//}; - -//// Compare a null-terminated string with a string. -//inline bool operator==(const char *lhs, const String &rhs) { -// return rhs == lhs; -//} -//inline bool operator!=(const char *lhs, const String &rhs) { -// return rhs != lhs; -//} -//inline bool operator<(const char *lhs, const String &rhs) { -// return rhs > lhs; -//} -//inline bool operator>(const char *lhs, const String &rhs) { -// return rhs < lhs; -//} -//inline bool operator<=(const char *lhs, const String &rhs) { -// return rhs >= lhs; -//} -//inline bool operator>=(const char *lhs, const String &rhs) { -// return rhs <= lhs; -//} +class String { + public: + constexpr String() : buf_(nullptr), size_(0), capacity_(0) {} + ~String(); + + String(const String &) = delete; + String& operator=(const String &) = delete; + + String(String &&rhs) + : buf_(rhs.buf_), + size_(rhs.size_), + capacity_(rhs.capacity_) { + rhs.buf_ = nullptr; + rhs.size_ = 0; + rhs.capacity_ = 0; + } + String &operator=(String &&rhs) { + buf_ = rhs.buf_; + size_ = rhs.size_; + capacity_ = rhs.capacity_; + rhs.buf_ = nullptr; + rhs.size_ = 0; + rhs.capacity_ = 0; + return *this; + } + + operator StringCRef() const { + return cref(); + } + + StringCRef cref(size_t offset = 0) const { + return StringCRef(buf_ + offset, size_ - offset); + } + StringCRef cref(size_t offset, size_t size) const { + return StringCRef(buf_ + offset, size); + } + + char &operator[](size_t i) { + return buf_[i]; + } + const char &operator[](size_t i) const { + return buf_[i]; + } + + char &front() { + return buf_[0]; + } + const char &front() const { + return buf_[0]; + } + + char &back() { + return buf_[size_ - 1]; + } + const char &back() const { + return buf_[size_ - 1]; + } + + char *data() { + return buf_; + } + const char *data() const { + return buf_; + } + size_t size() const { + return size_; + } + size_t capacity() const { + return capacity_; + } + + bool reserve(Error *error, size_t new_size) { + if (new_size <= capacity_) { + return true; + } + return resize_buf(error, new_size); + } + + bool assign(Error *error, const StringCRef &rhs) { + if (rhs.size() > capacity_) { + if (!resize_buf(error, rhs.size())) { + return false; + } + } + std::memcpy(buf_, rhs.data(), rhs.size()); + size_ = rhs.size(); + return true; + } + bool assign(Error *error, const char *data, size_t size) { + return assign(error, StringCRef(data, size)); + } + + bool resize(Error *error, size_t new_size) { + if (new_size > capacity_) { + if (!resize_buf(error, new_size)) { + return false; + } + } + size_ = new_size; + return true; + } + bool resize(Error *error, size_t new_size, char value) { + if (new_size > capacity_) { + if (!resize_buf(error, new_size)) { + return false; + } + } + if (new_size > size_) { + std::memset(buf_ + size_, value, new_size - size_); + } + size_ = new_size; + return true; + } + + void clear() { + size_ = 0; + } + + bool push_back(Error *error, char value) { + if (size_ == capacity_) { + if (!resize_buf(error, size_ + 1)) { + return false; + } + } + buf_[size_] = value; + ++size_; + return true; + } + void pop_back() { + --size_; + } + + bool append(Error *error, const StringCRef &rhs) { + if ((size_ + rhs.size()) > capacity_) { + // NOTE: If "rhs" is a part of "*this", "rhs" is destoyed in + // resize_buf(), so append_overlap() is required. + if ((rhs.data() >= buf_) && (rhs.data() < (buf_ + size_))) { + return append_overlap(error, rhs); + } else if (!resize_buf(error, (size_ + rhs.size()))) { + return false; + } + } + std::memcpy(buf_ + size_, rhs.data(), rhs.size()); + size_ += rhs.size(); + return true; + } + bool append(Error *error, const char *data, size_t size) { + return append(error, StringCRef(data, size)); + } + + // Compare a strings. + bool operator==(const StringCRef &rhs) const { + return cref() == rhs; + } + bool operator!=(const StringCRef &rhs) const { + return cref() != rhs; + } + bool operator<(const StringCRef &rhs) const { + return cref() < rhs; + } + bool operator>(const StringCRef &rhs) const { + return cref() > rhs; + } + bool operator<=(const StringCRef &rhs) const { + return cref() <= rhs; + } + bool operator>=(const StringCRef &rhs) const { + return cref() >= rhs; + } + + // Compare a string with a zero-terminated string. + bool operator==(const char *rhs) const { + return cref() == rhs; + } + bool operator!=(const char *rhs) const { + return cref() != rhs; + } + bool operator<(const char *rhs) const { + return cref() < rhs; + } + bool operator>(const char *rhs) const { + return cref() > rhs; + } + bool operator<=(const char *rhs) const { + return cref() <= rhs; + } + bool operator>=(const char *rhs) const { + return cref() >= rhs; + } + + // Return true if "*this" starts with "rhs". + bool starts_with(const StringCRef &rhs) const { + return cref().starts_with(rhs); + } + bool starts_with(const char *rhs) const { + return cref().starts_with(rhs); + } + + // Return true if "*this" ends with "rhs". + bool ends_with(const StringCRef &rhs) const { + return cref().ends_with(rhs); + } + bool ends_with(const char *rhs) const { + return cref().ends_with(rhs); + } + + private: + char *buf_; + size_t size_; + size_t capacity_; + + // Assume new_size > capacity_. + bool resize_buf(Error *error, size_t new_size); + // Resize the internal buffer and append a part of "*this". + bool append_overlap(Error *error, const StringCRef &rhs); +}; + +// Compare a null-terminated string with a string. +inline bool operator==(const char *lhs, const String &rhs) { + return rhs == lhs; +} +inline bool operator!=(const char *lhs, const String &rhs) { + return rhs != lhs; +} +inline bool operator<(const char *lhs, const String &rhs) { + return rhs > lhs; +} +inline bool operator>(const char *lhs, const String &rhs) { + return rhs < lhs; +} +inline bool operator<=(const char *lhs, const String &rhs) { + return rhs >= lhs; +} +inline bool operator>=(const char *lhs, const String &rhs) { + return rhs <= lhs; +} } // namespace grnxx Modified: lib/grnxx/Makefile.am (+2 -1) =================================================================== --- lib/grnxx/Makefile.am 2014-10-30 18:43:20 +0900 (61326f3) +++ lib/grnxx/Makefile.am 2014-10-30 18:49:12 +0900 (97d412a) @@ -10,7 +10,8 @@ libgrnxx_la_LDFLAGS = @AM_LTLDFLAGS@ libgrnxx_la_SOURCES = \ error.cpp \ - library.cpp + library.cpp \ + string.cpp # array.cpp \ # cursor.cpp \ Added: lib/grnxx/string.cpp (+48 -0) 100644 =================================================================== --- /dev/null +++ lib/grnxx/string.cpp 2014-10-30 18:49:12 +0900 (e1f70da) @@ -0,0 +1,48 @@ +#include "grnxx/string.hpp" + +#include <cstdlib> + +namespace grnxx { + +String::~String() { + std::free(buf_); +} + +bool String::resize_buf(Error *error, size_t new_size) { + size_t new_capacity = capacity_ * 2; + if (new_size > new_capacity) { + new_capacity = new_size; + } + char *new_buf = static_cast<char *>(std::malloc(new_capacity)); + if (!new_buf) { + GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); + return false; + } + std::memcpy(new_buf, buf_, size_); + std::free(buf_); + buf_ = new_buf; + capacity_ = new_capacity; + return true; +} + +bool String::append_overlap(Error *error, const StringCRef &rhs) { + size_t new_capacity = capacity_ * 2; + size_t new_size = size_ + rhs.size(); + if (new_size > new_capacity) { + new_capacity = new_size; + } + char *new_buf = static_cast<char *>(std::malloc(new_capacity)); + if (!new_buf) { + GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); + return false; + } + std::memcpy(new_buf, buf_, size_); + std::memcpy(new_buf + size_, rhs.data(), rhs.size()); + std::free(buf_); + buf_ = new_buf; + size_ = new_size; + capacity_ = new_capacity; + return true; +} + +} // namespace grnxx Modified: test/test_string.cpp (+86 -86) =================================================================== --- test/test_string.cpp 2014-10-30 18:43:20 +0900 (7bf0a99) +++ test/test_string.cpp 2014-10-30 18:49:12 +0900 (7c1e090) @@ -90,94 +90,94 @@ void test_string_cref() { } } -//void test_string() { -// constexpr size_t NUM_STRINGS = 1024; - -// grnxx::Error error; - -// std::vector<std::string> strings(NUM_STRINGS); -// std::vector<grnxx::StringCRef> refs(NUM_STRINGS); -// std::vector<grnxx::String> bodies(NUM_STRINGS); -// for (size_t i = 0; i < NUM_STRINGS; ++i) { -// std::stringstream stream; -// stream << i; -// strings[i] = stream.str(); -// refs[i] = grnxx::StringCRef(strings[i].data(), strings[i].size()); -// assert(bodies[i].assign(&error, refs[i])); -// } - -// for (size_t i = 0; i < NUM_STRINGS; ++i) { -// assert(bodies[i].size() == static_cast<size_t>(strings[i].size())); -// for (size_t j = 0; j < bodies[i].size(); ++j) { -// assert(bodies[i][j] == strings[i][j]); -// } - -// for (size_t j = 0; j < NUM_STRINGS; ++j) { -// assert((bodies[i] == bodies[j]) == (strings[i] == strings[j])); -// assert((bodies[i] != bodies[j]) == (strings[i] != strings[j])); -// assert((bodies[i] < bodies[j]) == (strings[i] < strings[j])); -// assert((bodies[i] > bodies[j]) == (strings[i] > strings[j])); -// assert((bodies[i] <= bodies[j]) == (strings[i] <= strings[j])); -// assert((bodies[i] >= bodies[j]) == (strings[i] >= strings[j])); - -// assert((bodies[i] == refs[j]) == (strings[i] == strings[j])); -// assert((bodies[i] != refs[j]) == (strings[i] != strings[j])); -// assert((bodies[i] < refs[j]) == (strings[i] < strings[j])); -// assert((bodies[i] > refs[j]) == (strings[i] > strings[j])); -// assert((bodies[i] <= refs[j]) == (strings[i] <= strings[j])); -// assert((bodies[i] >= refs[j]) == (strings[i] >= strings[j])); - -// assert((bodies[i] == strings[j].c_str()) == (strings[i] == strings[j])); -// assert((bodies[i] != strings[j].c_str()) == (strings[i] != strings[j])); -// assert((bodies[i] < strings[j].c_str()) == (strings[i] < strings[j])); -// assert((bodies[i] > strings[j].c_str()) == (strings[i] > strings[j])); -// assert((bodies[i] <= strings[j].c_str()) == (strings[i] <= strings[j])); -// assert((bodies[i] >= strings[j].c_str()) == (strings[i] >= strings[j])); - -// assert((refs[i] == bodies[j]) == (strings[i] == strings[j])); -// assert((refs[i] != bodies[j]) == (strings[i] != strings[j])); -// assert((refs[i] < bodies[j]) == (strings[i] < strings[j])); -// assert((refs[i] > bodies[j]) == (strings[i] > strings[j])); -// assert((refs[i] <= bodies[j]) == (strings[i] <= strings[j])); -// assert((refs[i] >= bodies[j]) == (strings[i] >= strings[j])); - -// assert((strings[i].c_str() == bodies[j]) == (strings[i] == strings[j])); -// assert((strings[i].c_str() != bodies[j]) == (strings[i] != strings[j])); -// assert((strings[i].c_str() < bodies[j]) == (strings[i] < strings[j])); -// assert((strings[i].c_str() > bodies[j]) == (strings[i] > strings[j])); -// assert((strings[i].c_str() <= bodies[j]) == (strings[i] <= strings[j])); -// assert((strings[i].c_str() >= bodies[j]) == (strings[i] >= strings[j])); - -// assert(bodies[i].starts_with(bodies[j]) == -// string_starts_with(strings[i], strings[j])); -// assert(bodies[i].starts_with(strings[j].c_str()) == -// string_starts_with(strings[i], strings[j])); -// assert(bodies[i].ends_with(bodies[j]) == -// string_ends_with(strings[i], strings[j])); -// assert(bodies[i].ends_with(strings[j].c_str()) == -// string_ends_with(strings[i], strings[j])); -// } -// } - -// for (size_t i = 0; i < NUM_STRINGS; ++i) { -// std::stringstream stream; -// stream << (i / 2.0); -// std::string extra_string = stream.str(); -// strings[i].append(extra_string); -// assert(bodies[i].append(&error, extra_string.data(), extra_string.size())); -// assert(bodies[i] == -// grnxx::StringCRef(strings[i].data(), strings[i].size())); -// } - -// for (size_t i = 0; i < NUM_STRINGS; ++i) { -// strings[i].append(strings[i]); -// assert(bodies[i].append(&error, bodies[i])); -// assert(std::string(bodies[i].data(), bodies[i].size()) == strings[i]); -// } -//} +void test_string() { + constexpr size_t NUM_STRINGS = 1024; + + grnxx::Error error; + + std::vector<std::string> strings(NUM_STRINGS); + std::vector<grnxx::StringCRef> refs(NUM_STRINGS); + std::vector<grnxx::String> bodies(NUM_STRINGS); + for (size_t i = 0; i < NUM_STRINGS; ++i) { + std::stringstream stream; + stream << i; + strings[i] = stream.str(); + refs[i] = grnxx::StringCRef(strings[i].data(), strings[i].size()); + assert(bodies[i].assign(&error, refs[i])); + } + + for (size_t i = 0; i < NUM_STRINGS; ++i) { + assert(bodies[i].size() == static_cast<size_t>(strings[i].size())); + for (size_t j = 0; j < bodies[i].size(); ++j) { + assert(bodies[i][j] == strings[i][j]); + } + + for (size_t j = 0; j < NUM_STRINGS; ++j) { + assert((bodies[i] == bodies[j]) == (strings[i] == strings[j])); + assert((bodies[i] != bodies[j]) == (strings[i] != strings[j])); + assert((bodies[i] < bodies[j]) == (strings[i] < strings[j])); + assert((bodies[i] > bodies[j]) == (strings[i] > strings[j])); + assert((bodies[i] <= bodies[j]) == (strings[i] <= strings[j])); + assert((bodies[i] >= bodies[j]) == (strings[i] >= strings[j])); + + assert((bodies[i] == refs[j]) == (strings[i] == strings[j])); + assert((bodies[i] != refs[j]) == (strings[i] != strings[j])); + assert((bodies[i] < refs[j]) == (strings[i] < strings[j])); + assert((bodies[i] > refs[j]) == (strings[i] > strings[j])); + assert((bodies[i] <= refs[j]) == (strings[i] <= strings[j])); + assert((bodies[i] >= refs[j]) == (strings[i] >= strings[j])); + + assert((bodies[i] == strings[j].c_str()) == (strings[i] == strings[j])); + assert((bodies[i] != strings[j].c_str()) == (strings[i] != strings[j])); + assert((bodies[i] < strings[j].c_str()) == (strings[i] < strings[j])); + assert((bodies[i] > strings[j].c_str()) == (strings[i] > strings[j])); + assert((bodies[i] <= strings[j].c_str()) == (strings[i] <= strings[j])); + assert((bodies[i] >= strings[j].c_str()) == (strings[i] >= strings[j])); + + assert((refs[i] == bodies[j]) == (strings[i] == strings[j])); + assert((refs[i] != bodies[j]) == (strings[i] != strings[j])); + assert((refs[i] < bodies[j]) == (strings[i] < strings[j])); + assert((refs[i] > bodies[j]) == (strings[i] > strings[j])); + assert((refs[i] <= bodies[j]) == (strings[i] <= strings[j])); + assert((refs[i] >= bodies[j]) == (strings[i] >= strings[j])); + + assert((strings[i].c_str() == bodies[j]) == (strings[i] == strings[j])); + assert((strings[i].c_str() != bodies[j]) == (strings[i] != strings[j])); + assert((strings[i].c_str() < bodies[j]) == (strings[i] < strings[j])); + assert((strings[i].c_str() > bodies[j]) == (strings[i] > strings[j])); + assert((strings[i].c_str() <= bodies[j]) == (strings[i] <= strings[j])); + assert((strings[i].c_str() >= bodies[j]) == (strings[i] >= strings[j])); + + assert(bodies[i].starts_with(bodies[j]) == + string_starts_with(strings[i], strings[j])); + assert(bodies[i].starts_with(strings[j].c_str()) == + string_starts_with(strings[i], strings[j])); + assert(bodies[i].ends_with(bodies[j]) == + string_ends_with(strings[i], strings[j])); + assert(bodies[i].ends_with(strings[j].c_str()) == + string_ends_with(strings[i], strings[j])); + } + } + + for (size_t i = 0; i < NUM_STRINGS; ++i) { + std::stringstream stream; + stream << (i / 2.0); + std::string extra_string = stream.str(); + strings[i].append(extra_string); + assert(bodies[i].append(&error, extra_string.data(), extra_string.size())); + assert(bodies[i] == + grnxx::StringCRef(strings[i].data(), strings[i].size())); + } + + for (size_t i = 0; i < NUM_STRINGS; ++i) { + strings[i].append(strings[i]); + assert(bodies[i].append(&error, bodies[i])); + assert(std::string(bodies[i].data(), bodies[i].size()) == strings[i]); + } +} int main() { test_string_cref(); -// test_string(); + test_string(); return 0; } -------------- next part -------------- HTML����������������������������...Download