diff options
103 files changed, 2594 insertions, 1130 deletions
diff --git a/Makefile.in b/Makefile.in index 3f6ba3f..77c9873 100644 --- a/Makefile.in +++ b/Makefile.in @@ -53,7 +53,7 @@ ifeq '${MAKEFILE_LIST}' ' Makefile' # should be used only in special circumstances." # If you do not understand *exactly* why I do this instead of # %::;${MAKE}, stay away from this code. You have been warned. -.default-target-wrapper ${MAKECMDGOALS}: .all-target-wrapper +.default-target-wrapper ${MAKECMDGOALS}: .all-target-wrapper ; @: .all-target-wrapper: ${MAKE} -rRf ${SRC_DIR}/real.make ${MAKECMDGOALS} endif @@ -67,7 +67,7 @@ # 10. Support per-target build flags? (requires renaming) ifeq ($(findstring s,$(firstword ${MAKEFLAGS})),) -ifeq (${MAKE_RESTARTS},) +ifndef MAKE_RESTARTS # TODO: should I write this in tengwar? # The major problem is that it's usually encoded in the PUA # and thus requires a font specification. @@ -237,6 +237,8 @@ distclean: clean %.cpp %.hpp: %.ypp $(MKDIR_FIRST) ${BISON} -d -o $*.cpp $< +ifndef MAKE_RESTARTS +# prevent errors if missing header obj/%.d: src/%.cpp $(MKDIR_FIRST) set -o pipefail; \ @@ -245,6 +247,7 @@ obj/%.d: src/%.cpp | sed -e ':again; s:/[^/ ]*/../:/:; t again' \ -e 's: ${SRC_DIR}/: :g' \ > $@ +endif # the above SRC_DIR replacement is not really safe, but it works okayish. obj/%.ii: src/%.cpp $(MKDIR_FIRST) @@ -308,8 +311,8 @@ tags: ${SOURCES} ${HEADERS} ctags --totals --c-kinds=+px -f $@ $^ Makefile: ${SRC_DIR}/Makefile.in - @echo Makefile.in updated, you must rerun configure - @false + @echo Makefile.in updated, reconfiguring ... + ./config.status include ${SRC_DIR}/version.make diff --git a/src/admin/ladmin.cpp b/src/admin/ladmin.cpp index fe4ba01..8a79662 100644 --- a/src/admin/ladmin.cpp +++ b/src/admin/ladmin.cpp @@ -8,6 +8,14 @@ #include <fstream> #include <iostream> +#include "../strings/mstring.hpp" +#include "../strings/fstring.hpp" +#include "../strings/tstring.hpp" +#include "../strings/sstring.hpp" +#include "../strings/zstring.hpp" +#include "../strings/xstring.hpp" +#include "../strings/vstring.hpp" + #include "../common/core.hpp" #include "../common/cxxstdio.hpp" #include "../common/human_time_diff.hpp" diff --git a/src/char/char.cpp b/src/char/char.cpp index 071076e..35e5841 100644 --- a/src/char/char.cpp +++ b/src/char/char.cpp @@ -16,6 +16,13 @@ #include <fstream> #include <set> +#include "../strings/mstring.hpp" +#include "../strings/fstring.hpp" +#include "../strings/tstring.hpp" +#include "../strings/sstring.hpp" +#include "../strings/zstring.hpp" +#include "../strings/xstring.hpp" + #include "../common/core.hpp" #include "../common/cxxstdio.hpp" #include "../common/db.hpp" diff --git a/src/char/char.hpp b/src/char/char.hpp index abd5381..78c68cb 100644 --- a/src/char/char.hpp +++ b/src/char/char.hpp @@ -1,6 +1,8 @@ #ifndef CHAR_HPP #define CHAR_HPP +#include "../strings/fwd.hpp" + #include "../common/const_array.hpp" #include "../common/ip.hpp" #include "../common/mmo.hpp" diff --git a/src/char/int_party.cpp b/src/char/int_party.cpp index d2c64e1..0597efd 100644 --- a/src/char/int_party.cpp +++ b/src/char/int_party.cpp @@ -5,6 +5,10 @@ #include <fstream> +#include "../strings/mstring.hpp" +#include "../strings/fstring.hpp" +#include "../strings/xstring.hpp" + #include "../common/cxxstdio.hpp" #include "../common/db.hpp" #include "../common/extract.hpp" diff --git a/src/char/int_party.hpp b/src/char/int_party.hpp index d003250..2793257 100644 --- a/src/char/int_party.hpp +++ b/src/char/int_party.hpp @@ -1,7 +1,7 @@ #ifndef INT_PARTY_HPP #define INT_PARTY_HPP -#include "../common/strings.hpp" +#include "../strings/fwd.hpp" int inter_party_init(void); int inter_party_save(void); diff --git a/src/char/int_storage.cpp b/src/char/int_storage.cpp index aa605bf..205b21e 100644 --- a/src/char/int_storage.cpp +++ b/src/char/int_storage.cpp @@ -6,6 +6,10 @@ #include <functional> #include <fstream> +#include "../strings/mstring.hpp" +#include "../strings/fstring.hpp" +#include "../strings/xstring.hpp" + #include "../common/cxxstdio.hpp" #include "../common/db.hpp" #include "../common/extract.hpp" diff --git a/src/char/int_storage.hpp b/src/char/int_storage.hpp index a03d70f..2585d63 100644 --- a/src/char/int_storage.hpp +++ b/src/char/int_storage.hpp @@ -1,7 +1,7 @@ #ifndef INT_STORAGE_HPP #define INT_STORAGE_HPP -#include "../common/strings.hpp" +#include "../strings/fwd.hpp" int inter_storage_init(void); int inter_storage_save(void); diff --git a/src/char/inter.cpp b/src/char/inter.cpp index 81c4a9d..b6bc417 100644 --- a/src/char/inter.cpp +++ b/src/char/inter.cpp @@ -7,6 +7,13 @@ #include <fstream> #include <vector> +#include "../strings/mstring.hpp" +#include "../strings/fstring.hpp" +#include "../strings/tstring.hpp" +#include "../strings/sstring.hpp" +#include "../strings/zstring.hpp" +#include "../strings/xstring.hpp" + #include "../common/cxxstdio.hpp" #include "../common/db.hpp" #include "../common/extract.hpp" diff --git a/src/char/inter.hpp b/src/char/inter.hpp index 447ab53..5216d57 100644 --- a/src/char/inter.hpp +++ b/src/char/inter.hpp @@ -1,7 +1,7 @@ #ifndef INTER_HPP #define INTER_HPP -#include "../common/strings.hpp" +#include "../strings/fwd.hpp" void inter_init(ZString file); void inter_save(void); diff --git a/src/common/core.cpp b/src/common/core.cpp index 76aa09c..727babd 100644 --- a/src/common/core.cpp +++ b/src/common/core.cpp @@ -8,6 +8,8 @@ #include <cstdlib> #include <ctime> +#include "../strings/zstring.hpp" + #include "random.hpp" #include "socket.hpp" #include "timer.hpp" @@ -79,7 +81,7 @@ int main(int argc, char **argv) // ZString args[argc]; is (deliberately!) not supported by clang yet ZString *args = static_cast<ZString *>(alloca(argc * sizeof(ZString))); for (int i = 0; i < argc; ++i) - args[i] = ZString(ZString::really_construct_from_a_pointer, argv[i], nullptr); + args[i] = ZString(strings::really_construct_from_a_pointer, argv[i], nullptr); do_init(argc, args); // set up exit handlers *after* the initialization has happened. // This is because term_func is likely to depend on successful init. diff --git a/src/common/core.hpp b/src/common/core.hpp index f1473ed..1cbd0c2 100644 --- a/src/common/core.hpp +++ b/src/common/core.hpp @@ -3,7 +3,7 @@ #include "sanity.hpp" -#include "strings.hpp" +#include "../strings/fwd.hpp" /// core.c contains a server-independent main() function /// and then runs a do_sendrecv loop diff --git a/src/common/dumb_ptr.hpp b/src/common/dumb_ptr.hpp index fe5031a..bcc9dda 100644 --- a/src/common/dumb_ptr.hpp +++ b/src/common/dumb_ptr.hpp @@ -25,8 +25,11 @@ #include <algorithm> +#include "../strings/fstring.hpp" +#include "../strings/zstring.hpp" +#include "../strings/xstring.hpp" + #include "const_array.hpp" -#include "strings.hpp" // unmanaged new/delete-able pointer // should be replaced by std::unique_ptr<T> @@ -240,7 +243,7 @@ struct dumb_string operator ZString() const { - return ZString(ZString::really_construct_from_a_pointer, c_str(), nullptr); + return ZString(strings::really_construct_from_a_pointer, c_str(), nullptr); } FString str() const diff --git a/src/common/extract.cpp b/src/common/extract.cpp index 720e6df..bac7b38 100644 --- a/src/common/extract.cpp +++ b/src/common/extract.cpp @@ -18,6 +18,10 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. +#include "../strings/fstring.hpp" +#include "../strings/xstring.hpp" +#include "../strings/vstring.hpp" + #include "../poison.hpp" bool extract(XString str, XString *rv) diff --git a/src/common/extract.hpp b/src/common/extract.hpp index c7bdbcb..dd0a8a3 100644 --- a/src/common/extract.hpp +++ b/src/common/extract.hpp @@ -23,6 +23,8 @@ #include <algorithm> +#include "../strings/xstring.hpp" + #include "const_array.hpp" #include "mmo.hpp" #include "utils.hpp" diff --git a/src/common/extract_test.cpp b/src/common/extract_test.cpp index 78478c2..3d0610e 100644 --- a/src/common/extract_test.cpp +++ b/src/common/extract_test.cpp @@ -2,6 +2,8 @@ #include <gtest/gtest.h> +#include "../strings/xstring.hpp" + TEST(extract, record_int) { int x, y, z; diff --git a/src/common/human_time_diff.hpp b/src/common/human_time_diff.hpp index 3fc0f09..a937316 100644 --- a/src/common/human_time_diff.hpp +++ b/src/common/human_time_diff.hpp @@ -21,8 +21,9 @@ #include "sanity.hpp" +#include "../strings/xstring.hpp" + #include "extract.hpp" -#include "strings.hpp" struct HumanTimeDiff { diff --git a/src/common/intern-pool.hpp b/src/common/intern-pool.hpp index db840a2..204b659 100644 --- a/src/common/intern-pool.hpp +++ b/src/common/intern-pool.hpp @@ -6,7 +6,9 @@ #include <map> #include <vector> -#include "strings.hpp" +#include "../strings/fstring.hpp" +#include "../strings/zstring.hpp" +#include "../strings/xstring.hpp" class InternPool { diff --git a/src/common/intern-pool_test.cpp b/src/common/intern-pool_test.cpp index 3bbca7b..bf17b67 100644 --- a/src/common/intern-pool_test.cpp +++ b/src/common/intern-pool_test.cpp @@ -2,6 +2,8 @@ #include <gtest/gtest.h> +#include "../strings/base.hpp" + TEST(InternPool, whydoesthisalwaysneedasecondname) { InternPool p; diff --git a/src/common/io.hpp b/src/common/io.hpp index 1831651..27bf4e2 100644 --- a/src/common/io.hpp +++ b/src/common/io.hpp @@ -4,7 +4,7 @@ #include <istream> #include <ostream> -#include "strings.hpp" +#include "../strings/fstring.hpp" namespace io { diff --git a/src/common/ip.cpp b/src/common/ip.cpp index 4734a8b..a1fdfda 100644 --- a/src/common/ip.cpp +++ b/src/common/ip.cpp @@ -18,6 +18,9 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. +#include "../strings/xstring.hpp" +#include "../strings/vstring.hpp" + #include "cxxstdio.hpp" #include "../poison.hpp" diff --git a/src/common/ip.hpp b/src/common/ip.hpp index aceb765..cce6c2b 100644 --- a/src/common/ip.hpp +++ b/src/common/ip.hpp @@ -23,8 +23,9 @@ #include <netinet/in.h> +#include "../strings/fwd.hpp" + #include "extract.hpp" -#include "strings.hpp" // TODO - in the long run ports belong here also // and of course, IPv6 stuff. diff --git a/src/common/lock.cpp b/src/common/lock.cpp index f19cd92..e21aee5 100644 --- a/src/common/lock.cpp +++ b/src/common/lock.cpp @@ -4,6 +4,9 @@ #include <cstdio> +#include "../strings/fstring.hpp" +#include "../strings/zstring.hpp" + #include "cxxstdio.hpp" #include "socket.hpp" diff --git a/src/common/lock.hpp b/src/common/lock.hpp index df4d1f8..5ca1aed 100644 --- a/src/common/lock.hpp +++ b/src/common/lock.hpp @@ -5,7 +5,7 @@ #include <cstdio> -#include "strings.hpp" +#include "../strings/fwd.hpp" // TODO replace with a class diff --git a/src/common/md5calc.cpp b/src/common/md5calc.cpp index 1c48a24..1961fa6 100644 --- a/src/common/md5calc.cpp +++ b/src/common/md5calc.cpp @@ -2,6 +2,9 @@ #include <cstring> +#include "../strings/xstring.hpp" +#include "../strings/vstring.hpp" + #include "cxxstdio.hpp" #include "random.hpp" #include "utils.hpp" diff --git a/src/common/md5calc.hpp b/src/common/md5calc.hpp index 70a996e..e44a7a7 100644 --- a/src/common/md5calc.hpp +++ b/src/common/md5calc.hpp @@ -11,9 +11,11 @@ #include <array> +#include "../strings/fwd.hpp" +#include "../strings/vstring.hpp" + #include "ip.hpp" #include "mmo.hpp" -#include "strings.hpp" /// The digest state - becomes the output struct MD5_state diff --git a/src/common/md5calc_test.cpp b/src/common/md5calc_test.cpp index 51b0b68..ab5f242 100644 --- a/src/common/md5calc_test.cpp +++ b/src/common/md5calc_test.cpp @@ -2,6 +2,9 @@ #include <gtest/gtest.h> +#include "../strings/xstring.hpp" +#include "../strings/vstring.hpp" + #include "utils.hpp" // This should be made part of the main API, diff --git a/src/common/mmo.hpp b/src/common/mmo.hpp index 0d3403c..16acb88 100644 --- a/src/common/mmo.hpp +++ b/src/common/mmo.hpp @@ -3,6 +3,9 @@ #define MMO_HPP # include "sanity.hpp" + +# include "../strings/vstring.hpp" + # include "timer.t.hpp" # include "utils2.hpp" @@ -57,7 +60,7 @@ T stringish(VString<sizeof(T) - 1> iv) #define DEFAULT_EMAIL stringish<AccountEmail>("a@a.com") // It is decreed: a mapname shall not contain an extension -class MapName : public strings::_crtp_string<MapName, MapName, ZString, XString> +class MapName : public strings::_crtp_string<MapName, MapName, strings::ZPair> { VString<15> _impl; public: diff --git a/src/common/socket.hpp b/src/common/socket.hpp index 91a8c49..1ff400a 100644 --- a/src/common/socket.hpp +++ b/src/common/socket.hpp @@ -9,6 +9,10 @@ # include <array> +# include "../strings/fstring.hpp" +# include "../strings/vstring.hpp" +# include "../strings/xstring.hpp" + # include "dumb_ptr.hpp" # include "ip.hpp" # include "utils.hpp" diff --git a/src/common/strings.hpp b/src/common/strings.hpp deleted file mode 100644 index 0b10570..0000000 --- a/src/common/strings.hpp +++ /dev/null @@ -1,1092 +0,0 @@ -#ifndef TMWA_COMMON_STRINGS_HPP -#define TMWA_COMMON_STRINGS_HPP -// strings.hpp - All the string classes you'll ever need. -// -// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> -// -// This file is part of The Mana World (Athena server) -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program 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 this program. If not, see <http://www.gnu.org/licenses/>. - -#include "sanity.hpp" - -#include <cassert> -#include <cstdarg> -#include <cstring> - -#include <algorithm> -#include <deque> -#include <iterator> -#include <memory> -#include <type_traits> -#include <vector> - -#include "utils2.hpp" - -// It is a common mistake to assume that one string class for everything. -// Because C++ and TMWA have a C legacy, there are a few more here -// than would probably be necessary in an ideal language. -namespace strings -{ - // owning - class MString; - class FString; - class TString; // C legacy version of SString - class SString; // is this one really worth it? - - // non-owning - class ZString; // C legacy version of XString - class XString; - - // semi-owning - template<uint8_t len> - class VString; - - // simple pointer-wrapping iterator that can be used to get distinct - // types for different containers. - template<class Tag> - class _iterator - { - typedef _iterator X; - - const char *_ptr; - public: - typedef ptrdiff_t difference_type; - typedef char value_type; - typedef const char *pointer; - typedef const char& reference; - typedef std::random_access_iterator_tag iterator_category; - - _iterator(const char *p=nullptr) : _ptr(p) {} - - // iterator - reference operator *() const { return *_ptr; } - X& operator ++() { ++_ptr; return *this; } - // equality comparable - friend bool operator == (X l, X r) { return l._ptr == r._ptr; } - // input iterator - friend bool operator != (X l, X r) { return !(l == r); } - pointer operator->() const { return _ptr; } - X operator++ (int) { X out = *this; ++*this; return out; } - // forward iterator is mostly semantical, and the ctor is above - // bidirectional iterator - X& operator --() { --_ptr; return *this; } - X operator-- (int) { X out = *this; --*this; return out; } - // random access iterator - X& operator += (difference_type n) { _ptr += n; return *this; } - friend X operator + (X a, difference_type n) { return a += n; } - friend X operator + (difference_type n, X a) { return a += n; } - X& operator -= (difference_type n) { _ptr -= n; return *this; } - friend X operator - (X a, difference_type n) { return a -= n; } - friend difference_type operator - (X b, X a) { return b._ptr - a._ptr; } - reference operator[](difference_type n) const { return _ptr[n]; } - friend bool operator < (X a, X b) { return a._ptr < b._ptr; } - friend bool operator > (X a, X b) { return b < a; } - friend bool operator >= (X a, X b) { return !(a < b); } - friend bool operator <= (X a, X b) { return !(a > b); } - }; - - /// A helper class that implements all the interesting stuff that can - /// be done on any constant string, in terms of .begin() and .end(). - template<class T, class O, class Z, class X=XString> - class _crtp_string - { - public: - // this will have to be changed if MString decides to join in. - typedef _iterator<T> iterator; - typedef std::reverse_iterator<iterator> reverse_iterator; - private: - const T& _ref() const { return static_cast<const T&>(*this); } - iterator begin() const { return _ref().begin(); } - iterator end() const { return _ref().end(); } - const FString *base() const { return _ref().base(); } - public: - size_t size() const { return end() - begin(); } - reverse_iterator rbegin() const { return reverse_iterator(end()); } - reverse_iterator rend() const { return reverse_iterator(begin()); } - explicit - operator bool() const { return size(); } - bool operator !() const { return !size(); } - - // the existence of this has led to bugs - // it's not really sane from a unicode perspective anyway ... - // prefer startswith or extract - __attribute__((deprecated)) - char operator[](size_t i) const { return begin()[i]; } - char front() const { return *begin(); } - char back() const { return end()[-1]; } - const char *data() { return &*begin(); } - - Z xslice_t(size_t o) const; - X xslice_h(size_t o) const; - Z xrslice_t(size_t no) const; - X xrslice_h(size_t no) const; - Z xislice_t(iterator it) const; - X xislice_h(iterator it) const; - X xlslice(size_t o, size_t l) const; - X xpslice(size_t b, size_t e) const; - X xislice(iterator b, iterator e) const; - Z lstrip() const; - X rstrip() const; - X strip() const; - - bool startswith(XString x) const; - bool endswith(XString x) const; - bool startswith(char c) const; - bool endswith(char c) const; - - bool contains(char c) const; - bool contains_seq(XString s) const; - bool contains_any(XString s) const; - - bool has_print() const; - bool is_print() const; - __attribute__((deprecated)) - O to_print() const; - - bool is_graph() const; - bool has_graph() const; - - bool has_lower() const; - bool is_lower() const; - O to_lower() const; - - bool has_upper() const; - bool is_upper() const; - O to_upper() const; - - bool has_alpha() const; // equivalent to has_lower || has_upper - bool is_alpha() const; // NOT equivalent to is_lower || is_upper - - bool has_digit2() const; - bool is_digit2() const; - bool has_digit8() const; - bool is_digit8() const; - bool has_digit10() const; - bool is_digit10() const; - bool has_digit16() const; - bool is_digit16() const; - - bool has_alnum() const; // equivalent to has_alpha || has_digit10 - bool is_alnum() const; // NOT equivalent to is_alpha || is_digit10 - }; - - - /// An owning string that is still expected to change. - /// The storage might not be contiguous, but it still offers - /// random-access iterators. - /// TODO implement a special one, to avoid quirks of std::string. - class MString - { - public: - typedef std::deque<char>::iterator iterator; - typedef std::deque<char>::const_iterator const_iterator; - typedef std::reverse_iterator<iterator> reverse_iterator; - typedef std::reverse_iterator<const_iterator> const_reverse_iterator; - private: - std::deque<char> _hack; - public: - iterator begin() { return _hack.begin(); } - iterator end() { return _hack.end(); } - const_iterator begin() const { return _hack.begin(); } - const_iterator end() const { return _hack.end(); } - reverse_iterator rbegin() { return reverse_iterator(end()); } - reverse_iterator rend() { return reverse_iterator(begin()); } - const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } - const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } - - size_t size() const { return _hack.size(); } - explicit - operator bool() const { return size(); } - bool operator !() const { return !size(); } - - MString& operator += (MString rhs) - { - _hack.insert(_hack.end(), rhs.begin(), rhs.end()); - return *this; - } - MString& operator += (char c) - { - _hack.push_back(c); - return *this; - } - MString& operator += (XString xs); - - void pop_back(size_t n=1) - { - while (n--) - _hack.pop_back(); - } - char& front() - { - return _hack.front(); - } - char& back() - { - return _hack.back(); - } - }; - - /// An owning string that has reached its final contents. - /// The storage is NUL-terminated - /// TODO implement a special one, that guarantees refcounting. - class FString : public _crtp_string<FString, FString, ZString, XString> - { - std::shared_ptr<std::vector<char>> _hack2; - - template<class It> - void _assign(It b, It e) - { - if (b == e) - { - // TODO use a special empty object - // return; - } - if (!std::is_base_of<std::forward_iterator_tag, typename std::iterator_traits<It>::iterator_category>::value) - { - // can't use std::distance - _hack2 = std::make_shared<std::vector<char>>(); - for (; b != e; ++b) - _hack2->push_back(*b); - _hack2->push_back('\0'); - _hack2->shrink_to_fit(); - } - size_t diff = std::distance(b, e); - _hack2 = std::make_shared<std::vector<char>>(diff + 1, '\0'); - std::copy(b, e, _hack2->begin()); - } - public: - FString() - { - const char *sadness = ""; - _assign(sadness, sadness); - } - - explicit FString(const MString& s) - { - _assign(s.begin(), s.end()); - } - - template<size_t n> - FString(char (&s)[n]) = delete; - - template<size_t n> - FString(const char (&s)[n]) - { - _assign(s, s + strlen(s)); - } - - template<class It> - FString(It b, It e) - { - _assign(b, e); - } - - - iterator begin() const { return &_hack2->begin()[0]; } - iterator end() const { return &_hack2->end()[-1]; } - const FString *base() const { return this; } - const char *c_str() const { return &*begin(); } - - TString oslice_t(size_t o) const; - SString oslice_h(size_t o) const; - TString orslice_t(size_t no) const; - SString orslice_h(size_t no) const; - TString oislice_t(iterator it) const; - SString oislice_h(iterator it) const; - SString olslice(size_t o, size_t l) const; - SString opslice(size_t b, size_t e) const; - SString oislice(iterator b, iterator e) const; - }; - - /// An owning string that represents a tail slice of an FString. - /// Guaranteed to be NUL-terminated. - class TString : public _crtp_string<TString, TString, ZString, XString> - { - friend class SString; - FString _s; - size_t _o; - public: - TString() : _s(), _o() {} - TString(FString b, size_t i=0) : _s(std::move(b)), _o(i) {} - template<size_t n> - TString(char (&s)[n]) = delete; - template<size_t n> - TString(const char (&s)[n]) : _s(s), _o(0) {} - //template<class It> - //TString(It b, It e) : _s(b, e), _o(0) {} - - iterator begin() const { return &_s.begin()[_o]; } - iterator end() const { return &*_s.end(); } - const FString *base() const { return &_s; } - const char *c_str() const { return &*begin(); } - - TString oslice_t(size_t o) const; - SString oslice_h(size_t o) const; - TString orslice_t(size_t no) const; - SString orslice_h(size_t no) const; - TString oislice_t(iterator it) const; - SString oislice_h(iterator it) const; - SString olslice(size_t o, size_t l) const; - SString opslice(size_t b, size_t e) const; - SString oislice(iterator b, iterator e) const; - - operator FString() const - { if (_o) return FString(begin(), end()); else return _s; } - }; - - /// An owning string that represents a arbitrary slice of an FString. - /// Not guaranteed to be NUL-terminated. - class SString : public _crtp_string<SString, SString, XString, XString> - { - FString _s; - size_t _b, _e; - public: - SString() : _s(), _b(), _e() {} - SString(FString f) : _s(std::move(f)), _b(), _e(_s.size()) {} - SString(TString t) : _s(t._s), _b(0), _e(_s.size()) {} - template<size_t n> - SString(char (&s)[n]) = delete; - template<size_t n> - SString(const char (&s)[n]) : _s(s), _b(0), _e(_s.size()) {} - //template<class It> - //SString(It b, It e) : _s(b, e), _b(0), _e(_s.size()) {} - SString(FString f, size_t b, size_t e) : _s(std::move(f)), _b(b), _e(e) {} - - iterator begin() const { return &_s.begin()[_b]; } - iterator end() const { return &_s.begin()[_e]; } - const FString *base() const { return &_s; } - - SString oslice_t(size_t o) const; - SString oslice_h(size_t o) const; - SString orslice_t(size_t no) const; - SString orslice_h(size_t no) const; - SString oislice_t(iterator it) const; - SString oislice_h(iterator it) const; - SString olslice(size_t o, size_t l) const; - SString opslice(size_t b, size_t e) const; - SString oislice(iterator b, iterator e) const; - - operator FString() const - { if (_b == 0 && _e == _s.size()) return _s; else return FString(begin(), end()); } - operator TString() const - { if (_e == _s.size()) return TString(_s, _b); else return FString(begin(), end()); } - }; - - /// A non-owning string that is guaranteed to be NUL-terminated. - /// This should be only used as a parameter. - class ZString : public _crtp_string<ZString, FString, ZString, XString> - { - iterator _b, _e; - // optional - const FString *_base; - public: - enum { really_construct_from_a_pointer }; - ZString() { *this = ZString(""); } - // no MString - ZString(const FString& s) : _b(&*s.begin()), _e(&*s.end()), _base(s.base()) {} - ZString(const TString& s) : _b(&*s.begin()), _e(&*s.end()), _base(s.base()) {} - ZString(const SString&) = delete; - // dangerous - ZString(const char *b, const char *e, const FString *base_) : _b(b), _e(e), _base(base_) {} - ZString(decltype(really_construct_from_a_pointer), const char *s, const FString *base_) : _b(s), _e(s + strlen(s)), _base(base_) {} - template<size_t n> - ZString(char (&s)[n]) = delete; - template<size_t n> - ZString(const char (&s)[n], const FString *base_=nullptr) : _b(s), _e(s + strlen(s)), _base(base_) {} - - iterator begin() const { return _b; } - iterator end() const { return _e; } - const FString *base() const { return _base; } - const char *c_str() const { return &*begin(); } - - ZString oslice_t(size_t o) const; - XString oslice_h(size_t o) const; - ZString orslice_t(size_t no) const; - XString orslice_h(size_t no) const; - ZString oislice_t(iterator it) const; - XString oislice_h(iterator it) const; - XString olslice(size_t o, size_t l) const; - XString opslice(size_t b, size_t e) const; - XString oislice(iterator b, iterator e) const; - - operator FString() const - { if (_base) return SString(*_base, &*_b - &*_base->begin(), &*_e - &*_base->begin()); else return FString(_b, _e); } - operator TString() const - { if (_base) return SString(*_base, &*_b - &*_base->begin(), &*_e - &*_base->begin()); else return FString(_b, _e); } - operator SString() const - { if (_base) return SString(*_base, &*_b - &*_base->begin(), &*_e - &*_base->begin()); else return FString(_b, _e); } - }; - - /// A non-owning string that is not guaranteed to be NUL-terminated. - /// This should be only used as a parameter. - class XString : public _crtp_string<XString, FString, XString, XString> - { - iterator _b, _e; - // optional - const FString *_base; - public: - // do I really want this? - XString() : _b(""), _e(_b), _base() {} - XString(std::nullptr_t) = delete; - // no MString - XString(const FString& s) : _b(&*s.begin()), _e(&*s.end()), _base(s.base()) {} - XString(const TString& s) : _b(&*s.begin()), _e(&*s.end()), _base(s.base()) {} - XString(const SString& s) : _b(&*s.begin()), _e(&*s.end()), _base(s.base()) {} - XString(const ZString& s) : _b(&*s.begin()), _e(&*s.end()), _base(s.base()) {} - template<size_t n> - XString(char (&s)[n]) = delete; - template<size_t n> - XString(const char (&s)[n]) : _b(s), _e(s + strlen(s)), _base(nullptr) {} - // mostly internal - XString(const char *b, const char *e, const FString *base_) : _b(b), _e(e), _base(base_) {} - XString(decltype(ZString::really_construct_from_a_pointer) e, const char *s, const FString *base_) - { - *this = ZString(e, s, base_); - } - - iterator begin() const { return _b; } - iterator end() const { return _e; } - const FString *base() const { return _base; } - - XString oslice_t(size_t o) const { return xslice_t(o); } - XString oslice_h(size_t o) const { return xslice_h(o); } - XString orslice_t(size_t no) const { return xrslice_t(no); } - XString orslice_h(size_t no) const { return xrslice_h(no); } - XString oislice_t(iterator it) const { return xislice_t(it); } - XString oislice_h(iterator it) const { return xislice_h(it); } - XString olslice(size_t o, size_t l) const { return xlslice(o, l); } - XString opslice(size_t b, size_t e) const { return xpslice(b, e); } - XString oislice(iterator b, iterator e) const { return xislice(b, e); } - - operator FString() const - { if (_base) return SString(*_base, &*_b - &*_base->begin(), &*_e - &*_base->begin()); else return FString(_b, _e); } - operator TString() const - { if (_base) return SString(*_base, &*_b - &*_base->begin(), &*_e - &*_base->begin()); else return FString(_b, _e); } - operator SString() const - { if (_base) return SString(*_base, &*_b - &*_base->begin(), &*_e - &*_base->begin()); else return FString(_b, _e); } - operator ZString() const = delete; - }; - - template<uint8_t n> - class VString : public _crtp_string<VString<n>, VString<n>, ZString, XString> - { - char _data[n]; - unsigned char _special; - public: - typedef typename _crtp_string<VString<n>, VString<n>, ZString, XString>::iterator iterator; - VString(XString x) : _data(), _special() - { - if (x.size() > n) - // we're hoping this doesn't happen - // hopefully there will be few enough users of this class - x = x.xslice_h(n); - char *e = std::copy(x.begin(), x.end(), std::begin(_data)); - _special = std::end(_data) - e; - assert (_special == n - x.size()); // 0 when it needs to be - } - // poor man's delegated constructors - // needed for gcc 4.6 compatibility - VString(FString f) - { - *this = XString(f); - } - VString(TString t) - { - *this = XString(t); - } - VString(SString s) - { - *this = XString(s); - } - VString(ZString z) - { - *this = XString(z); - } - template<size_t m> - VString(char (&s)[m]) = delete; - template<size_t m> - VString(const char (&s)[m]) - { - static_assert(m <= n + 1, "string would truncate"); - *this = XString(s); - } - VString(decltype(ZString::really_construct_from_a_pointer) e, const char *s) - { - *this = XString(e, s, nullptr); - } - VString(char c) - { - *this = XString(&c, &c + 1, nullptr); - } - VString() - { - *this = XString(); - } - - // hopefully this is obvious - iterator begin() const { return std::begin(_data); } - iterator end() const { return std::end(_data) - _special; } - const FString *base() const { return nullptr; } - const char *c_str() const { return &*begin(); } - - VString oslice_t(size_t o) const { return this->xslice_t(o); } - VString oslice_h(size_t o) const { return this->xslice_h(o); } - VString orslice_t(size_t no) const { return this->xrslice_t(no); } - VString orslice_h(size_t no) const { return this->xrslice_h(no); } - VString oislice_t(iterator it) const { return this->xislice_t(it); } - VString oislice_h(iterator it) const { return this->xislice_h(it); } - VString olslice(size_t o, size_t l) const { return this->xlslice(o, l); } - VString opslice(size_t b, size_t e) const { return this->xpslice(b, e); } - VString oislice(iterator b, iterator e) const { return this->xislice(b, e); } - - operator FString() const { return FString(begin(), end()); } - operator TString() const { return FString(begin(), end()); } - operator SString() const { return FString(begin(), end()); } - operator ZString() const { return ZString(_data); } - operator XString() const { return XString(&*begin(), &*end(), nullptr); } - - template<uint8_t m> - operator VString<m>() const - { - static_assert(m > n, "can only grow"); - XString x = *this; - return VString<m>(XString(x)); - } - }; - - // not really intended for public use - inline - int xstr_compare(XString l, XString r) - { - bool less = std::lexicographical_compare( - l.begin(), l.end(), - r.begin(), r.end()); - bool greater = std::lexicographical_compare( - r.begin(), r.end(), - l.begin(), l.end()); - return greater - less; - } - - - template<class L, class R> - class string_comparison_allowed - { - constexpr static bool l_is_vstring_exact = std::is_same<VString<sizeof(L) - 1>, L>::value; - constexpr static bool l_is_vstring_approx = std::is_base_of<VString<sizeof(L) - 1>, L>::value; - constexpr static bool r_is_vstring_exact = std::is_same<VString<sizeof(R) - 1>, R>::value; - constexpr static bool r_is_vstring_approx = std::is_base_of<VString<sizeof(R) - 1>, R>::value; - - constexpr static bool l_is_restricted = l_is_vstring_approx && !l_is_vstring_exact; - constexpr static bool r_is_restricted = r_is_vstring_approx && !r_is_vstring_exact; - public: - constexpr static bool value = std::is_same<L, R>::value || (!l_is_restricted && !r_is_restricted); - }; - - struct _test : VString<1> {}; - struct _test2 : VString<1> {}; - - static_assert(string_comparison_allowed<_test, _test>::value, "tt"); - static_assert(string_comparison_allowed<VString<1>, VString<1>>::value, "vv"); - static_assert(!string_comparison_allowed<_test, XString>::value, "tx"); - static_assert(!string_comparison_allowed<_test, VString<1>>::value, "tv"); - static_assert(!string_comparison_allowed<_test, _test2>::value, "t2"); - static_assert(string_comparison_allowed<VString<1>, XString>::value, "vx"); - static_assert(string_comparison_allowed<XString, XString>::value, "xx"); - static_assert(string_comparison_allowed<XString, FString>::value, "xf"); - - template<class L, class R, typename=typename std::enable_if<string_comparison_allowed<L, R>::value>::type> - auto operator == (const L& l, const R& r) -> decltype((xstr_compare(l, r), true)) - { - return xstr_compare(l, r) == 0; - } - template<class L, class R, typename=typename std::enable_if<string_comparison_allowed<L, R>::value>::type> - auto operator != (const L& l, const R& r) -> decltype((xstr_compare(l, r), true)) - { - return xstr_compare(l, r) != 0; - } - template<class L, class R, typename=typename std::enable_if<string_comparison_allowed<L, R>::value>::type> - auto operator < (const L& l, const R& r) -> decltype((xstr_compare(l, r), true)) - { - return xstr_compare(l, r) < 0; - } - template<class L, class R, typename=typename std::enable_if<string_comparison_allowed<L, R>::value>::type> - auto operator <= (const L& l, const R& r) -> decltype((xstr_compare(l, r), true)) - { - return xstr_compare(l, r) <= 0; - } - template<class L, class R, typename=typename std::enable_if<string_comparison_allowed<L, R>::value>::type> - auto operator > (const L& l, const R& r) -> decltype((xstr_compare(l, r), true)) - { - return xstr_compare(l, r) > 0; - } - template<class L, class R, typename=typename std::enable_if<string_comparison_allowed<L, R>::value>::type> - auto operator >= (const L& l, const R& r) -> decltype((xstr_compare(l, r), true)) - { - return xstr_compare(l, r) >= 0; - } - - namespace detail - { - constexpr - bool is_print(char c) - { - return ' ' <= c && c <= '~'; - } - constexpr - bool is_graph(char c) - { - return is_print(c) && c != ' '; - } - constexpr - bool is_lower(char c) - { - return 'a' <= c && c <= 'z'; - } - constexpr - bool is_upper(char c) - { - return 'A' <= c && c <= 'Z'; - } - constexpr - bool is_alpha(char c) - { - return is_lower(c) || is_upper(c); - } - constexpr - bool is_digit2(char c) - { - return '0' <= c && c <= '1'; - } - constexpr - bool is_digit8(char c) - { - return '0' <= c && c <= '7'; - } - constexpr - bool is_digit10(char c) - { - return '0' <= c && c <= '9'; - } - constexpr - bool is_digit16(char c) - { - return ('0' <= c && c <= '9') || ('A' <= c && c <= 'F') || ('a' <= c && c <= 'f'); - } - constexpr - bool is_alnum(char c) - { - return is_alpha(c) || is_digit10(c); - } - - constexpr - char to_lower(char c) - { - return is_upper(c) ? c | ' ' : c; - } - constexpr - char to_upper(char c) - { - return is_lower(c) ? c & ~' ' : c; - } - } - - // sadness - typedef MString MS; - typedef FString FS; - typedef SString SS; - typedef TString TS; - typedef ZString ZS; - typedef XString XS; - - // _crtp_string - template<class T, class O, class Z, class X> - Z _crtp_string<T, O, Z, X>::xslice_t(size_t o) const - { return Z(&begin()[o], &*end(), base()); } - template<class T, class O, class Z, class X> - X _crtp_string<T, O, Z, X>::xslice_h(size_t o) const - { return X(&*begin(), &begin()[o], base()); } - template<class T, class O, class Z, class X> - Z _crtp_string<T, O, Z, X>::xrslice_t(size_t no) const - { return Z(&end()[-no], &*end(), base()); } - template<class T, class O, class Z, class X> - X _crtp_string<T, O, Z, X>::xrslice_h(size_t no) const - { return X(&*begin(), &end()[-no], base()); } - template<class T, class O, class Z, class X> - Z _crtp_string<T, O, Z, X>::xislice_t(iterator it) const - { return Z(&*it, &*end(), base()); } - template<class T, class O, class Z, class X> - X _crtp_string<T, O, Z, X>::xislice_h(iterator it) const - { return X(&*begin(), &*it, base()); } - template<class T, class O, class Z, class X> - X _crtp_string<T, O, Z, X>::xlslice(size_t o, size_t l) const - { return X(&begin()[o], &begin()[o + l], base()); } - template<class T, class O, class Z, class X> - X _crtp_string<T, O, Z, X>::xpslice(size_t b, size_t e) const - { return X(&begin()[b], &begin()[e], base()); } - template<class T, class O, class Z, class X> - X _crtp_string<T, O, Z, X>::xislice(iterator b, iterator e) const - { return X(&*b, &*e, base()); } - template<class T, class O, class Z, class X> - Z _crtp_string<T, O, Z, X>::lstrip() const - { - Z z = _ref(); - while (z.startswith(' ')) - z = z.xslice_t(1); - return z; - } - template<class T, class O, class Z, class X> - X _crtp_string<T, O, Z, X>::rstrip() const - { - X x = _ref(); - while (x.endswith(' ')) - x = x.xrslice_h(1); - return x; - } - template<class T, class O, class Z, class X> - X _crtp_string<T, O, Z, X>::strip() const - { return lstrip().rstrip(); } - - template<class T, class O, class Z, class X> - bool _crtp_string<T, O, Z, X>::startswith(XS x) const - { return size() >= x.size() && xslice_h(x.size()) == x; } - template<class T, class O, class Z, class X> - bool _crtp_string<T, O, Z, X>::endswith(XS x) const - { return size() > x.size() && xrslice_t(x.size()) == x; } - template<class T, class O, class Z, class X> - bool _crtp_string<T, O, Z, X>::startswith(char c) const - { return size() && front() == c; } - template<class T, class O, class Z, class X> - bool _crtp_string<T, O, Z, X>::endswith(char c) const - { return size() && back() == c; } - template<class T, class O, class Z, class X> - bool _crtp_string<T, O, Z, X>::contains(char c) const - { return std::find(begin(), end(), c) != end(); } - template<class T, class O, class Z, class X> - bool _crtp_string<T, O, Z, X>::contains_seq(XString s) const - { return std::search(begin(), end(), s.begin(), s.end()) != end(); } - template<class T, class O, class Z, class X> - bool _crtp_string<T, O, Z, X>::contains_any(XString s) const - { return std::find_if(begin(), end(), [s](char c) { return s.contains(c); }) != end(); } - - template<class T, class O, class Z, class X> - bool _crtp_string<T, O, Z, X>::has_print() const - { return std::find_if(begin(), end(), detail::is_print) != end(); } - template<class T, class O, class Z, class X> - bool _crtp_string<T, O, Z, X>::is_print() const - { return std::find_if_not(begin(), end(), detail::is_print) == end(); } - template<class T, class O, class Z, class X> - O _crtp_string<T, O, Z, X>::to_print() const - { - if (is_print()) return _ref(); - char buf[size()]; - char *const b = buf; - char *const e = std::transform(begin(), end(), b, [](char c) { return detail::is_print(c) ? c : '_'; }); - return XString(b, e, nullptr); - } - - template<class T, class O, class Z, class X> - bool _crtp_string<T, O, Z, X>::has_graph() const - { return std::find_if(begin(), end(), detail::is_graph) != end(); } - template<class T, class O, class Z, class X> - bool _crtp_string<T, O, Z, X>::is_graph() const - { return std::find_if_not(begin(), end(), detail::is_graph) == end(); } - - template<class T, class O, class Z, class X> - bool _crtp_string<T, O, Z, X>::has_lower() const - { return std::find_if(begin(), end(), detail::is_lower) != end(); } - template<class T, class O, class Z, class X> - bool _crtp_string<T, O, Z, X>::is_lower() const - { return std::find_if_not(begin(), end(), detail::is_lower) == end(); } - template<class T, class O, class Z, class X> - O _crtp_string<T, O, Z, X>::to_lower() const - { - if (!has_upper()) return _ref(); - char buf[size()]; - char *const b = buf; - char *const e = std::transform(begin(), end(), b, detail::to_lower); - return XString(b, e, nullptr); - } - - template<class T, class O, class Z, class X> - bool _crtp_string<T, O, Z, X>::has_upper() const - { return std::find_if(begin(), end(), detail::is_upper) != end(); } - template<class T, class O, class Z, class X> - bool _crtp_string<T, O, Z, X>::is_upper() const - { return std::find_if_not(begin(), end(), detail::is_upper) == end(); } - template<class T, class O, class Z, class X> - O _crtp_string<T, O, Z, X>::to_upper() const - { - if (!has_lower()) return _ref(); - char buf[size()]; - char *const b = buf; - char *const e = std::transform(begin(), end(), b, detail::to_upper); - return XString(b, e, nullptr); - } - - template<class T, class O, class Z, class X> - bool _crtp_string<T, O, Z, X>::has_alpha() const - { return std::find_if(begin(), end(), detail::is_alpha) != end(); } - template<class T, class O, class Z, class X> - bool _crtp_string<T, O, Z, X>::is_alpha() const - { return std::find_if_not(begin(), end(), detail::is_alpha) == end(); } - - template<class T, class O, class Z, class X> - bool _crtp_string<T, O, Z, X>::has_digit2() const - { return std::find_if(begin(), end(), detail::is_digit2) != end(); } - template<class T, class O, class Z, class X> - bool _crtp_string<T, O, Z, X>::is_digit2() const - { return std::find_if_not(begin(), end(), detail::is_digit2) == end(); } - template<class T, class O, class Z, class X> - bool _crtp_string<T, O, Z, X>::has_digit8() const - { return std::find_if(begin(), end(), detail::is_digit8) != end(); } - template<class T, class O, class Z, class X> - bool _crtp_string<T, O, Z, X>::is_digit8() const - { return std::find_if_not(begin(), end(), detail::is_digit8) == end(); } - template<class T, class O, class Z, class X> - bool _crtp_string<T, O, Z, X>::has_digit10() const - { return std::find_if(begin(), end(), detail::is_digit10) != end(); } - template<class T, class O, class Z, class X> - bool _crtp_string<T, O, Z, X>::is_digit10() const - { return std::find_if_not(begin(), end(), detail::is_digit10) == end(); } - template<class T, class O, class Z, class X> - bool _crtp_string<T, O, Z, X>::has_digit16() const - { return std::find_if(begin(), end(), detail::is_digit16) != end(); } - template<class T, class O, class Z, class X> - bool _crtp_string<T, O, Z, X>::is_digit16() const - { return std::find_if_not(begin(), end(), detail::is_digit16) == end(); } - - template<class T, class O, class Z, class X> - bool _crtp_string<T, O, Z, X>::has_alnum() const - { return std::find_if(begin(), end(), detail::is_alnum) != end(); } - template<class T, class O, class Z, class X> - bool _crtp_string<T, O, Z, X>::is_alnum() const - { return std::find_if_not(begin(), end(), detail::is_alnum) == end(); } - - // MString - inline - MS& MS::operator += (XS x) - { - _hack.insert(_hack.end(), x.begin(), x.end()); - return *this; - } - - // FString - inline - TS FS::oslice_t(size_t o) const - { return TS(*this, o); } - inline - SS FS::oslice_h(size_t o) const - { return SS(*this, 0, o); } - inline - TS FS::orslice_t(size_t no) const - { return TS(*this, size() - no); } - inline - SS FS::orslice_h(size_t no) const - { return SS(*this, 0, size() - no); } - inline - TS FS::oislice_t(iterator it) const - { return TS(*this, it - begin()); } - inline - SS FS::oislice_h(iterator it) const - { return SS(*this, 0, it - begin()); } - inline - SS FS::olslice(size_t o, size_t l) const - { return SS(*this, o, o + l); } - inline - SS FS::opslice(size_t b, size_t e) const - { return SS(*this, b, e); } - inline - SS FS::oislice(iterator b, iterator e) const - { return SS(*this, b - begin(), e - begin()); } - - // TString - inline - TS TS::oslice_t(size_t o) const - { return TS(_s, _o + o); } - inline - SS TS::oslice_h(size_t o) const - { return SS(_s, _o, _o + o); } - inline - TS TS::orslice_t(size_t no) const - { return TS(_s, _s.size() - no); } - inline - SS TS::orslice_h(size_t no) const - { return SS(_s, _o, _s.size() - no); } - inline - TS TS::oislice_t(iterator it) const - { return TS(_s, _o + it - begin()); } - inline - SS TS::oislice_h(iterator it) const - { return SS(_s, _o, _o + it - begin()); } - inline - SS TS::olslice(size_t o, size_t l) const - { return SS(_s, _o + o, _o + o + l); } - inline - SS TS::opslice(size_t b, size_t e) const - { return SS(_s, _o + b, _o + e); } - inline - SS TS::oislice(iterator b, iterator e) const - { return SS(_s, _o + b - begin(), _o + e - begin()); } - - // SString - inline - SS SS::oslice_t(size_t o) const - { return SS(_s, _b + o, _e); } - inline - SS SS::oslice_h(size_t o) const - { return SS(_s, _b, _b + o); } - inline - SS SS::orslice_t(size_t no) const - { return SS(_s, _e - no, _e); } - inline - SS SS::orslice_h(size_t no) const - { return SS(_s, _b, _e - no); } - inline - SS SS::oislice_t(iterator it) const - { return SS(_s, _b + it - begin(), _e); } - inline - SS SS::oislice_h(iterator it) const - { return SS(_s, _b, _b + it - begin()); } - inline - SS SS::olslice(size_t o, size_t l) const - { return SS(_s, _b + o, _b + o + l); } - inline - SS SS::opslice(size_t b, size_t e) const - { return SS(_s, _b + b, _b + e); } - inline - SS SS::oislice(iterator b, iterator e) const - { return SS(_s, _b + b - begin(), _b + e - begin()); } - - // ZString - inline - ZS ZS::oslice_t(size_t o) const - { return ZS(really_construct_from_a_pointer, &begin()[o], base()); } - inline - XS ZS::oslice_h(size_t o) const - { return XS(&*begin(), &begin()[o], base()); } - inline - ZS ZS::orslice_t(size_t no) const - { return ZS(really_construct_from_a_pointer, &end()[-no], base()); } - inline - XS ZS::orslice_h(size_t no) const - { return XS(&*begin(), &end()[-no], base()); } - inline - ZS ZS::oislice_t(iterator it) const - { return ZS(really_construct_from_a_pointer, &*it, base()); } - inline - XS ZS::oislice_h(iterator it) const - { return XS(&*begin(), &*it, base()); } - inline - XS ZS::olslice(size_t o, size_t l) const - { return XS(&begin()[o], &begin()[o + l], base()); } - inline - XS ZS::opslice(size_t b, size_t e) const - { return XS(&begin()[b], &begin()[e], base()); } - inline - XS ZS::oislice(iterator b, iterator e) const - { return XS(&*b, &*e, base()); } - - - // cxxstdio helpers - // I think the conversion will happen automatically. TODO test this. - // Nope, it doesn't, since there's a template - // Actually, it might now. - inline - const char *decay_for_printf(const FString& fs) { return fs.c_str(); } - inline - const char *decay_for_printf(const TString& ts) { return ts.c_str(); } - inline - const char *decay_for_printf(const ZString& zs) { return zs.c_str(); } - template<uint8_t n> - inline - const char *decay_for_printf(const VString<n>& vs) { return vs.c_str(); } - - template<uint8_t len> - inline __attribute__((format(printf, 2, 0))) - int do_vprint(VString<len>& out, const char *fmt, va_list ap) - { - char buffer[len + 1]; - vsnprintf(buffer, len + 1, fmt, ap); - - out = const_(buffer); - return len; - } - - inline __attribute__((format(printf, 2, 0))) - int do_vprint(FString& out, const char *fmt, va_list ap) - { - int len; - { - va_list ap2; - va_copy(ap2, ap); - len = vsnprintf(nullptr, 0, fmt, ap2); - va_end(ap2); - } - char buffer[len + 1]; - vsnprintf(buffer, len + 1, fmt, ap); - - out = FString(buffer, buffer + len); - return len; - } - - inline __attribute__((format(scanf, 2, 0))) - int do_vscan(ZString in, const char *fmt, va_list ap) - { - return vsscanf(in.c_str(), fmt, ap); - } - - class StringConverter - { - FString& out; - char *mid; - public: - StringConverter(FString& s) - : out(s), mid(nullptr) - {} - ~StringConverter() - { - if (mid) - { - out = ZString(ZString::really_construct_from_a_pointer, mid, nullptr); - free(mid); - } - } - char **operator &() - { - return ∣ - } - }; - - inline - StringConverter convert_for_scanf(FString& s) - { - return StringConverter(s); - } -} // namespace strings - -// owning -using strings::MString; -using strings::FString; -using strings::SString; -using strings::TString; - -// non-owning -using strings::ZString; -using strings::XString; - -// semi-owning -using strings::VString; - -#endif // TMWA_COMMON_STRINGS_HPP diff --git a/src/common/timer.cpp b/src/common/timer.cpp index c00f06d..17c6d80 100644 --- a/src/common/timer.cpp +++ b/src/common/timer.cpp @@ -8,6 +8,8 @@ #include <queue> +#include "../strings/zstring.hpp" + #include "cxxstdio.hpp" #include "utils.hpp" diff --git a/src/common/timer.hpp b/src/common/timer.hpp index b9c9588..de867ab 100644 --- a/src/common/timer.hpp +++ b/src/common/timer.hpp @@ -5,7 +5,7 @@ # include "sanity.hpp" -# include "strings.hpp" +# include "../strings/fwd.hpp" // updated automatically when using milli_clock::now() // which is done only by core.cpp diff --git a/src/common/utils.cpp b/src/common/utils.cpp index 9ab470b..21440a4 100644 --- a/src/common/utils.cpp +++ b/src/common/utils.cpp @@ -5,6 +5,12 @@ #include <algorithm> +#include "../strings/fstring.hpp" +#include "../strings/tstring.hpp" +#include "../strings/sstring.hpp" +#include "../strings/zstring.hpp" +#include "../strings/xstring.hpp" + #include "cxxstdio.hpp" #include "extract.hpp" @@ -42,7 +48,7 @@ bool e_mail_check(XString email) // Return numerical value of a switch configuration // on/off, english, français, deutsch, español //------------------------------------------------- -int config_switch (ZString str) +int config_switch(ZString str) { if (str == "true" || str == "on" || str == "yes" || str == "oui" || str == "ja" diff --git a/src/common/utils.hpp b/src/common/utils.hpp index 4f6190a..66b1654 100644 --- a/src/common/utils.hpp +++ b/src/common/utils.hpp @@ -8,9 +8,11 @@ #include <type_traits> +#include "../strings/fwd.hpp" +#include "../strings/vstring.hpp" + #include "const_array.hpp" #include "operators.hpp" -#include "strings.hpp" #include "utils2.hpp" template<class T> diff --git a/src/login/login.cpp b/src/login/login.cpp index 342de5d..c029844 100644 --- a/src/login/login.cpp +++ b/src/login/login.cpp @@ -15,6 +15,14 @@ #include <set> #include <type_traits> +#include "../strings/mstring.hpp" +#include "../strings/fstring.hpp" +#include "../strings/tstring.hpp" +#include "../strings/sstring.hpp" +#include "../strings/zstring.hpp" +#include "../strings/xstring.hpp" +#include "../strings/vstring.hpp" + #include "../common/core.hpp" #include "../common/cxxstdio.hpp" #include "../common/db.hpp" diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp index 4b41c7b..b7a0caa 100644 --- a/src/map/atcommand.cpp +++ b/src/map/atcommand.cpp @@ -6,6 +6,14 @@ #include <fstream> +#include "../strings/mstring.hpp" +#include "../strings/fstring.hpp" +#include "../strings/tstring.hpp" +#include "../strings/sstring.hpp" +#include "../strings/zstring.hpp" +#include "../strings/xstring.hpp" +#include "../strings/vstring.hpp" + #include "../common/core.hpp" #include "../common/cxxstdio.hpp" #include "../common/extract.hpp" diff --git a/src/map/atcommand.hpp b/src/map/atcommand.hpp index 280372e..aff09b7 100644 --- a/src/map/atcommand.hpp +++ b/src/map/atcommand.hpp @@ -1,6 +1,8 @@ #ifndef ATCOMMAND_HPP #define ATCOMMAND_HPP +#include "../strings/fwd.hpp" + #include "../common/const_array.hpp" #include "map.hpp" diff --git a/src/map/battle.cpp b/src/map/battle.cpp index 02ea370..c5cb8e3 100644 --- a/src/map/battle.cpp +++ b/src/map/battle.cpp @@ -4,6 +4,11 @@ #include <fstream> +#include "../strings/fstring.hpp" +#include "../strings/tstring.hpp" +#include "../strings/sstring.hpp" +#include "../strings/zstring.hpp" + #include "../common/cxxstdio.hpp" #include "../common/io.hpp" #include "../common/nullpo.hpp" diff --git a/src/map/battle.hpp b/src/map/battle.hpp index c933e28..2d9cd7f 100644 --- a/src/map/battle.hpp +++ b/src/map/battle.hpp @@ -3,6 +3,8 @@ #include "battle.t.hpp" +#include "../strings/fwd.hpp" + #include "../common/timer.t.hpp" #include "magic-interpreter.t.hpp" diff --git a/src/map/chrif.cpp b/src/map/chrif.cpp index c9020a3..1f7d1cc 100644 --- a/src/map/chrif.cpp +++ b/src/map/chrif.cpp @@ -4,6 +4,9 @@ #include <cstring> +#include "../strings/fstring.hpp" +#include "../strings/zstring.hpp" + #include "../common/cxxstdio.hpp" #include "../common/nullpo.hpp" #include "../common/socket.hpp" diff --git a/src/map/chrif.hpp b/src/map/chrif.hpp index dfcc12b..db7ad0e 100644 --- a/src/map/chrif.hpp +++ b/src/map/chrif.hpp @@ -1,6 +1,8 @@ #ifndef CHRIF_HPP #define CHRIF_HPP +#include "../strings/fwd.hpp" + #include "../common/dumb_ptr.hpp" #include "../common/human_time_diff.hpp" #include "../common/ip.hpp" diff --git a/src/map/clif.cpp b/src/map/clif.cpp index 26c7f0c..90c9f4d 100644 --- a/src/map/clif.cpp +++ b/src/map/clif.cpp @@ -6,6 +6,10 @@ #include <cstring> #include <ctime> +#include "../strings/fstring.hpp" +#include "../strings/zstring.hpp" +#include "../strings/xstring.hpp" + #include "../common/cxxstdio.hpp" #include "../common/md5calc.hpp" #include "../common/random.hpp" diff --git a/src/map/clif.hpp b/src/map/clif.hpp index fa68e23..a605e73 100644 --- a/src/map/clif.hpp +++ b/src/map/clif.hpp @@ -5,9 +5,10 @@ #include <functional> +#include "../strings/fwd.hpp" + #include "../common/const_array.hpp" #include "../common/ip.hpp" -#include "../common/strings.hpp" #include "../common/timer.t.hpp" #include "battle.t.hpp" diff --git a/src/map/grfio.cpp b/src/map/grfio.cpp index cbb5a86..41a285f 100644 --- a/src/map/grfio.cpp +++ b/src/map/grfio.cpp @@ -13,6 +13,9 @@ #include <fstream> #include <map> +#include "../strings/mstring.hpp" +#include "../strings/fstring.hpp" + #include "../common/cxxstdio.hpp" #include "../common/extract.hpp" #include "../common/io.hpp" diff --git a/src/map/grfio.hpp b/src/map/grfio.hpp index aa222c6..599064d 100644 --- a/src/map/grfio.hpp +++ b/src/map/grfio.hpp @@ -6,7 +6,6 @@ #include <vector> #include "../common/mmo.hpp" -#include "../common/strings.hpp" /// Load a resource into memory, subject to data/resnametable.txt. /// Normally, resourcename is xxx-y.gat and the file is xxx-y.wlk. diff --git a/src/map/intif.cpp b/src/map/intif.cpp index a3865b2..18415d0 100644 --- a/src/map/intif.cpp +++ b/src/map/intif.cpp @@ -3,6 +3,10 @@ #include <cstdlib> #include <cstring> +#include "../strings/fstring.hpp" +#include "../strings/zstring.hpp" +#include "../strings/xstring.hpp" + #include "../common/cxxstdio.hpp" #include "../common/nullpo.hpp" #include "../common/socket.hpp" diff --git a/src/map/intif.hpp b/src/map/intif.hpp index 08added..a3e1d17 100644 --- a/src/map/intif.hpp +++ b/src/map/intif.hpp @@ -1,6 +1,8 @@ #ifndef INTIF_HPP #define INTIF_HPP +#include "../strings/fwd.hpp" + #include "../common/const_array.hpp" #include "map.hpp" diff --git a/src/map/itemdb.cpp b/src/map/itemdb.cpp index cb47b21..588acd9 100644 --- a/src/map/itemdb.cpp +++ b/src/map/itemdb.cpp @@ -5,6 +5,10 @@ #include <fstream> +#include "../strings/fstring.hpp" +#include "../strings/zstring.hpp" +#include "../strings/xstring.hpp" + #include "../common/cxxstdio.hpp" #include "../common/db.hpp" #include "../common/extract.hpp" diff --git a/src/map/magic-expr-eval.hpp b/src/map/magic-expr-eval.hpp index 76b86f8..29fdab6 100644 --- a/src/map/magic-expr-eval.hpp +++ b/src/map/magic-expr-eval.hpp @@ -1,6 +1,8 @@ #ifndef MAGIC_EXPR_EVAL_HPP #define MAGIC_EXPR_EVAL_HPP +#include "../strings/zstring.hpp" + #include "../common/utils2.hpp" #include "magic-interpreter.hpp" diff --git a/src/map/magic-expr.cpp b/src/map/magic-expr.cpp index 872ba6f..8f4a5eb 100644 --- a/src/map/magic-expr.cpp +++ b/src/map/magic-expr.cpp @@ -5,6 +5,11 @@ #include <cassert> #include <cmath> +#include "../strings/mstring.hpp" +#include "../strings/fstring.hpp" +#include "../strings/zstring.hpp" +#include "../strings/vstring.hpp" + #include "../common/cxxstdio.hpp" #include "../common/random.hpp" diff --git a/src/map/magic-expr.hpp b/src/map/magic-expr.hpp index 2bffcbc..0d1bd4f 100644 --- a/src/map/magic-expr.hpp +++ b/src/map/magic-expr.hpp @@ -3,6 +3,9 @@ #include "magic-interpreter.hpp" +#include "../strings/fwd.hpp" +#include "../strings/zstring.hpp" + /* * Argument types: * i : int diff --git a/src/map/magic-interpreter-base.cpp b/src/map/magic-interpreter-base.cpp index 3167efb..09656c6 100644 --- a/src/map/magic-interpreter-base.cpp +++ b/src/map/magic-interpreter-base.cpp @@ -3,6 +3,9 @@ #include "magic-interpreter-aux.hpp" #include "magic-interpreter.hpp" +#include "../strings/fstring.hpp" +#include "../strings/xstring.hpp" + #include "../common/cxxstdio.hpp" #include "../common/timer.hpp" diff --git a/src/map/magic-interpreter-parser.ypp b/src/map/magic-interpreter-parser.ypp index e6d69b4..8a654cd 100644 --- a/src/map/magic-interpreter-parser.ypp +++ b/src/map/magic-interpreter-parser.ypp @@ -10,6 +10,9 @@ #include <cassert> #include <cstdarg> // exception to "no va_list" rule, even after cxxstdio +#include "../strings/fstring.hpp" +#include "../strings/zstring.hpp" + #include "../common/const_array.hpp" #include "../common/cxxstdio.hpp" diff --git a/src/map/magic-interpreter.hpp b/src/map/magic-interpreter.hpp index 13c91e9..a0abe7a 100644 --- a/src/map/magic-interpreter.hpp +++ b/src/map/magic-interpreter.hpp @@ -5,6 +5,9 @@ #include <cassert> +#include "../strings/fwd.hpp" +#include "../strings/fstring.hpp" + #include "magic.hpp" #include "map.hpp" #include "script.hpp" diff --git a/src/map/magic-stmt.cpp b/src/map/magic-stmt.cpp index ebf75c5..2d246de 100644 --- a/src/map/magic-stmt.cpp +++ b/src/map/magic-stmt.cpp @@ -2,6 +2,8 @@ #include <cassert> +#include "../strings/zstring.hpp" + #include "../common/cxxstdio.hpp" #include "../common/random2.hpp" #include "../common/timer.hpp" diff --git a/src/map/magic.cpp b/src/map/magic.cpp index 84d133a..75a76ae 100644 --- a/src/map/magic.cpp +++ b/src/map/magic.cpp @@ -1,5 +1,7 @@ #include <cstring> +#include "../strings/xstring.hpp" + #include "../common/cxxstdio.hpp" #include "magic-interpreter.hpp" diff --git a/src/map/magic.hpp b/src/map/magic.hpp index 5b10367..84e3387 100644 --- a/src/map/magic.hpp +++ b/src/map/magic.hpp @@ -1,6 +1,8 @@ #ifndef MAGIC_HPP #define MAGIC_HPP +#include "../strings/fwd.hpp" + #include "../common/dumb_ptr.hpp" #include "map.hpp" diff --git a/src/map/map.cpp b/src/map/map.cpp index cff97e2..9c5f074 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -12,6 +12,13 @@ #include <fstream> +#include "../strings/fstring.hpp" +#include "../strings/tstring.hpp" +#include "../strings/sstring.hpp" +#include "../strings/zstring.hpp" +#include "../strings/xstring.hpp" +#include "../strings/vstring.hpp" + #include "../common/core.hpp" #include "../common/cxxstdio.hpp" #include "../common/db.hpp" diff --git a/src/map/map.hpp b/src/map/map.hpp index 4d5ac9d..b0e6f18 100644 --- a/src/map/map.hpp +++ b/src/map/map.hpp @@ -8,11 +8,14 @@ #include <functional> #include <list> +#include "../strings/fwd.hpp" +#include "../strings/fstring.hpp" +#include "../strings/vstring.hpp" + #include "../common/cxxstdio.hpp" #include "../common/db.hpp" #include "../common/matrix.hpp" #include "../common/socket.hpp" -#include "../common/strings.hpp" #include "../common/timer.t.hpp" #include "battle.t.hpp" diff --git a/src/map/map.t.hpp b/src/map/map.t.hpp index 19f80c3..2255f60 100644 --- a/src/map/map.t.hpp +++ b/src/map/map.t.hpp @@ -1,6 +1,8 @@ #ifndef MAP_T_HPP #define MAP_T_HPP +#include "../strings/vstring.hpp" + #include "../common/mmo.hpp" #include "../common/utils2.hpp" diff --git a/src/map/mob.cpp b/src/map/mob.cpp index f8edff9..ee74b08 100644 --- a/src/map/mob.cpp +++ b/src/map/mob.cpp @@ -9,6 +9,9 @@ #include <algorithm> #include <fstream> +#include "../strings/fstring.hpp" +#include "../strings/xstring.hpp" + #include "../common/cxxstdio.hpp" #include "../common/extract.hpp" #include "../common/io.hpp" diff --git a/src/map/npc.cpp b/src/map/npc.cpp index bca4eab..28f348e 100644 --- a/src/map/npc.cpp +++ b/src/map/npc.cpp @@ -7,6 +7,11 @@ #include <list> +#include "../strings/mstring.hpp" +#include "../strings/fstring.hpp" +#include "../strings/zstring.hpp" +#include "../strings/xstring.hpp" + #include "../common/cxxstdio.hpp" #include "../common/db.hpp" #include "../common/extract.hpp" @@ -1208,7 +1213,7 @@ int npc_parse_script(XString w1, XString w2, NpcName w3, ZString w4, (*lines)++; if (feof(fp)) break; - ZString line(ZString::really_construct_from_a_pointer, line_, nullptr); + ZString line(strings::really_construct_from_a_pointer, line_, nullptr); if (!srcbuf) { // may be a no-op @@ -1403,7 +1408,7 @@ int npc_parse_function(XString, XString, XString w3, ZString, (*lines)++; if (feof(fp)) break; - ZString line(ZString::really_construct_from_a_pointer, line_, nullptr); + ZString line(strings::really_construct_from_a_pointer, line_, nullptr); if (!srcbuf) { srcbuf += line.xislice_t(std::find(line.begin(), line.end(), '{')); @@ -1731,7 +1736,7 @@ int do_init_npc(void) { // because it's still fgets line_[strlen(line_) - 1] = '\0'; - ZString zline(ZString::really_construct_from_a_pointer, line_, nullptr); + ZString zline(strings::really_construct_from_a_pointer, line_, nullptr); XString w1, w2, w3, w4x; ZString w4z; lines++; diff --git a/src/map/npc.hpp b/src/map/npc.hpp index 36f4e4d..ee9ed91 100644 --- a/src/map/npc.hpp +++ b/src/map/npc.hpp @@ -4,6 +4,8 @@ #include <cstddef> #include <cstdint> +#include "../strings/fwd.hpp" + #include "../common/timer.t.hpp" #include "map.hpp" diff --git a/src/map/party.cpp b/src/map/party.cpp index c6b0bcc..d0039de 100644 --- a/src/map/party.cpp +++ b/src/map/party.cpp @@ -2,6 +2,8 @@ #include <cstring> +#include "../strings/xstring.hpp" + #include "../common/cxxstdio.hpp" #include "../common/db.hpp" #include "../common/nullpo.hpp" diff --git a/src/map/party.hpp b/src/map/party.hpp index 80679ad..5ad6c03 100644 --- a/src/map/party.hpp +++ b/src/map/party.hpp @@ -3,6 +3,8 @@ #include <functional> +#include "../strings/fwd.hpp" + #include "map.hpp" struct party; diff --git a/src/map/pc.cpp b/src/map/pc.cpp index 0068ab3..b622cc0 100644 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -6,6 +6,9 @@ #include <fstream> +#include "../strings/fstring.hpp" +#include "../strings/zstring.hpp" + #include "../common/cxxstdio.hpp" #include "../common/io.hpp" #include "../common/nullpo.hpp" diff --git a/src/map/pc.hpp b/src/map/pc.hpp index 4796011..77d1288 100644 --- a/src/map/pc.hpp +++ b/src/map/pc.hpp @@ -3,6 +3,8 @@ #include "pc.t.hpp" +#include "../strings/fwd.hpp" + #include "clif.t.hpp" #include "map.hpp" diff --git a/src/map/script.cpp b/src/map/script.cpp index f705909..2f4d1cb 100644 --- a/src/map/script.cpp +++ b/src/map/script.cpp @@ -9,6 +9,11 @@ #include <fstream> +#include "../strings/mstring.hpp" +#include "../strings/fstring.hpp" +#include "../strings/zstring.hpp" +#include "../strings/xstring.hpp" + #include "../common/cxxstdio.hpp" #include "../common/db.hpp" #include "../common/extract.hpp" diff --git a/src/map/script.hpp b/src/map/script.hpp index 4e8f9ac..e593cfa 100644 --- a/src/map/script.hpp +++ b/src/map/script.hpp @@ -6,6 +6,9 @@ #include <vector> +#include "../strings/fstring.hpp" +#include "../strings/zstring.hpp" + #include "../common/db.hpp" #include "../common/dumb_ptr.hpp" #include "../common/utils.hpp" @@ -17,6 +20,8 @@ struct str_data_t; class ScriptBuffer { + typedef ZString::iterator ZSit; + std::vector<ByteCode> script_buf; public: // construction methods used only by script.cpp @@ -25,17 +30,17 @@ public: void add_scripti(uint32_t a); void add_scriptl(str_data_t *a); void set_label(str_data_t *ld, int pos_); - ZString::iterator parse_simpleexpr(ZString::iterator p); - ZString::iterator parse_subexpr(ZString::iterator p, int limit); - ZString::iterator parse_expr(ZString::iterator p); - ZString::iterator parse_line(ZString::iterator p); + ZSit parse_simpleexpr(ZSit p); + ZSit parse_subexpr(ZSit p, int limit); + ZSit parse_expr(ZSit p); + ZSit parse_line(ZSit p); void parse_script(ZString src, int line); // consumption methods used only by script.cpp ByteCode operator[](size_t i) const { return script_buf[i]; } ZString get_str(size_t i) const { - return ZString(ZString::really_construct_from_a_pointer, reinterpret_cast<const char *>(&script_buf[i]), nullptr); + return ZString(strings::really_construct_from_a_pointer, reinterpret_cast<const char *>(&script_buf[i]), nullptr); } // method used elsewhere diff --git a/src/map/skill.cpp b/src/map/skill.cpp index f868b41..46b8dda 100644 --- a/src/map/skill.cpp +++ b/src/map/skill.cpp @@ -7,6 +7,10 @@ #include <fstream> +#include "../strings/mstring.hpp" +#include "../strings/fstring.hpp" +#include "../strings/xstring.hpp" + #include "../common/cxxstdio.hpp" #include "../common/extract.hpp" #include "../common/io.hpp" diff --git a/src/map/skill.hpp b/src/map/skill.hpp index a233ed4..d816161 100644 --- a/src/map/skill.hpp +++ b/src/map/skill.hpp @@ -4,7 +4,8 @@ #include "skill.t.hpp" #include "skill-pools.hpp" -#include "../common/strings.hpp" +#include "../strings/fwd.hpp" +#include "../strings/fstring.hpp" #include "map.hpp" diff --git a/src/map/tmw.cpp b/src/map/tmw.cpp index ed00110..d4beef4 100644 --- a/src/map/tmw.cpp +++ b/src/map/tmw.cpp @@ -3,6 +3,10 @@ #include <cctype> #include <cstring> +#include "../strings/fstring.hpp" +#include "../strings/zstring.hpp" +#include "../strings/xstring.hpp" + #include "../common/cxxstdio.hpp" #include "../common/nullpo.hpp" diff --git a/src/map/tmw.hpp b/src/map/tmw.hpp index 5f1d215..d9147c9 100644 --- a/src/map/tmw.hpp +++ b/src/map/tmw.hpp @@ -1,6 +1,8 @@ #ifndef TMW_HPP #define TMW_HPP +#include "../strings/fwd.hpp" + #include "../common/const_array.hpp" #include "../common/dumb_ptr.hpp" diff --git a/src/monitor/main.cpp b/src/monitor/main.cpp index f6e8271..2ab0a79 100644 --- a/src/monitor/main.cpp +++ b/src/monitor/main.cpp @@ -16,6 +16,13 @@ #include <fstream> +#include "../strings/mstring.hpp" +#include "../strings/fstring.hpp" +#include "../strings/tstring.hpp" +#include "../strings/sstring.hpp" +#include "../strings/zstring.hpp" +#include "../strings/xstring.hpp" + #include "../common/cxxstdio.hpp" #include "../common/io.hpp" #include "../common/utils.hpp" @@ -142,11 +149,11 @@ int main(int argc, char *argv[]) signal(SIGQUIT, stop_process); signal(SIGABRT, stop_process); - workdir = make_path(ZString(ZString::really_construct_from_a_pointer, getenv("HOME"), nullptr), "tmwserver"); + workdir = make_path(ZString(strings::really_construct_from_a_pointer, getenv("HOME"), nullptr), "tmwserver"); ZString config = CONFIG; if (argc > 1) - config = ZString(ZString::really_construct_from_a_pointer, argv[1], nullptr); + config = ZString(strings::really_construct_from_a_pointer, argv[1], nullptr); read_config(config); if (chdir(workdir.c_str()) < 0) diff --git a/src/strings/all.hpp b/src/strings/all.hpp new file mode 100644 index 0000000..333cb4b --- /dev/null +++ b/src/strings/all.hpp @@ -0,0 +1,31 @@ +#ifndef TMWA_STRINGS_ALL_HPP +#define TMWA_STRINGS_ALL_HPP +// strings/all.hpp - All the string classes you'll ever need. +// +// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> +// +// This file is part of The Mana World (Athena server) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + +#include "base.hpp" +#include "mstring.hpp" +#include "fstring.hpp" +#include "tstring.hpp" +#include "sstring.hpp" +#include "zstring.hpp" +#include "xstring.hpp" +#include "vstring.hpp" + +#endif // TMWA_STRINGS_ALL_HPP diff --git a/src/strings/base.hpp b/src/strings/base.hpp new file mode 100644 index 0000000..2ea303f --- /dev/null +++ b/src/strings/base.hpp @@ -0,0 +1,205 @@ +#ifndef TMWA_STRINGS_BASE_HPP +#define TMWA_STRINGS_BASE_HPP +// strings/base.cls.hpp - CRTP base for string implementations. +// +// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> +// +// This file is part of The Mana World (Athena server) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + +#include "fwd.hpp" +#include "pair.hpp" + +#include <iterator> + +// It is a common mistake to assume that one string class for everything. +// Because C++ and TMWA have a C legacy, there are a few more here +// than would probably be necessary in an ideal language. +namespace strings +{ + // simple pointer-wrapping iterator that can be used to get distinct + // types for different containers. + template<class Tag> + class _iterator + { + typedef _iterator X; + + const char *_ptr; + public: + typedef ptrdiff_t difference_type; + typedef char value_type; + typedef const char *pointer; + typedef const char& reference; + typedef std::random_access_iterator_tag iterator_category; + + _iterator(const char *p=nullptr) : _ptr(p) {} + + // iterator + reference operator *() const { return *_ptr; } + X& operator ++() { ++_ptr; return *this; } + // equality comparable + friend bool operator == (X l, X r) { return l._ptr == r._ptr; } + // input iterator + friend bool operator != (X l, X r) { return !(l == r); } + pointer operator->() const { return _ptr; } + X operator++ (int) { X out = *this; ++*this; return out; } + // forward iterator is mostly semantical, and the ctor is above + // bidirectional iterator + X& operator --() { --_ptr; return *this; } + X operator-- (int) { X out = *this; --*this; return out; } + // random access iterator + X& operator += (difference_type n) { _ptr += n; return *this; } + friend X operator + (X a, difference_type n) { return a += n; } + friend X operator + (difference_type n, X a) { return a += n; } + X& operator -= (difference_type n) { _ptr -= n; return *this; } + friend X operator - (X a, difference_type n) { return a -= n; } + friend difference_type operator - (X b, X a) { return b._ptr - a._ptr; } + reference operator[](difference_type n) const { return _ptr[n]; } + friend bool operator < (X a, X b) { return a._ptr < b._ptr; } + friend bool operator > (X a, X b) { return b < a; } + friend bool operator >= (X a, X b) { return !(a < b); } + friend bool operator <= (X a, X b) { return !(a > b); } + }; + + /// A helper class that implements all the interesting stuff that can + /// be done on any constant string, in terms of .begin() and .end(). + template<class T, class O, class P> + class _crtp_string + { + typedef typename P::TailSlice Z; + typedef typename P::FullSlice X; + public: + // this will have to be changed if MString decides to join in. + typedef _iterator<T> iterator; + typedef std::reverse_iterator<iterator> reverse_iterator; + private: + const T& _ref() const; + iterator begin() const; + iterator end() const; + const FString *base() const; + public: + size_t size() const; + reverse_iterator rbegin() const; + reverse_iterator rend() const; + explicit + operator bool() const; + bool operator !() const; + operator P() const; + + // the existence of this has led to bugs + // it's not really sane from a unicode perspective anyway ... + // prefer startswith or extract + __attribute__((deprecated)) + char operator[](size_t i) const; + char front() const; + char back() const; + const char *data(); + + Z xslice_t(size_t o) const; + X xslice_h(size_t o) const; + Z xrslice_t(size_t no) const; + X xrslice_h(size_t no) const; + Z xislice_t(iterator it) const; + X xislice_h(iterator it) const; + X xlslice(size_t o, size_t l) const; + X xpslice(size_t b, size_t e) const; + X xislice(iterator b, iterator e) const; + Z lstrip() const; + X rstrip() const; + X strip() const; + + bool startswith(XPair x) const; + bool endswith(XPair x) const; + bool startswith(char c) const; + bool endswith(char c) const; + + bool contains(char c) const; + bool contains_seq(XPair s) const; + bool contains_any(XPair s) const; + + bool has_print() const; + bool is_print() const; + __attribute__((deprecated)) + O to_print() const; + + bool is_graph() const; + bool has_graph() const; + + bool has_lower() const; + bool is_lower() const; + O to_lower() const; + + bool has_upper() const; + bool is_upper() const; + O to_upper() const; + + bool has_alpha() const; // equivalent to has_lower || has_upper + bool is_alpha() const; // NOT equivalent to is_lower || is_upper + + bool has_digit2() const; + bool is_digit2() const; + bool has_digit8() const; + bool is_digit8() const; + bool has_digit10() const; + bool is_digit10() const; + bool has_digit16() const; + bool is_digit16() const; + + bool has_alnum() const; // equivalent to has_alpha || has_digit10 + bool is_alnum() const; // NOT equivalent to is_alpha || is_digit10 + }; + + template<class L, class R> + class string_comparison_allowed + { + constexpr static bool l_is_vstring_exact = std::is_same<VString<sizeof(L) - 1>, L>::value; + constexpr static bool l_is_vstring_approx = std::is_base_of<VString<sizeof(L) - 1>, L>::value; + constexpr static bool r_is_vstring_exact = std::is_same<VString<sizeof(R) - 1>, R>::value; + constexpr static bool r_is_vstring_approx = std::is_base_of<VString<sizeof(R) - 1>, R>::value; + + constexpr static bool l_is_restricted = l_is_vstring_approx && !l_is_vstring_exact; + constexpr static bool r_is_restricted = r_is_vstring_approx && !r_is_vstring_exact; + public: + constexpr static bool value = std::is_same<L, R>::value || (!l_is_restricted && !r_is_restricted); + }; + + // not really intended for public use + int pair_compare(XPair l, XPair r); + + template<class L, class R, typename=typename std::enable_if<string_comparison_allowed<L, R>::value>::type> + auto operator == (const L& l, const R& r) -> decltype((pair_compare(l, r), true)); + template<class L, class R, typename=typename std::enable_if<string_comparison_allowed<L, R>::value>::type> + auto operator != (const L& l, const R& r) -> decltype((pair_compare(l, r), true)); + template<class L, class R, typename=typename std::enable_if<string_comparison_allowed<L, R>::value>::type> + auto operator < (const L& l, const R& r) -> decltype((pair_compare(l, r), true)); + template<class L, class R, typename=typename std::enable_if<string_comparison_allowed<L, R>::value>::type> + auto operator <= (const L& l, const R& r) -> decltype((pair_compare(l, r), true)); + template<class L, class R, typename=typename std::enable_if<string_comparison_allowed<L, R>::value>::type> + auto operator > (const L& l, const R& r) -> decltype((pair_compare(l, r), true)); + template<class L, class R, typename=typename std::enable_if<string_comparison_allowed<L, R>::value>::type> + auto operator >= (const L& l, const R& r) -> decltype((pair_compare(l, r), true)); + + // sadness + typedef MString MS; + typedef FString FS; + typedef TString TS; + typedef SString SS; + typedef ZString ZS; + typedef XString XS; +} // namespace strings + +#include "base.tcc" + +#endif // TMWA_STRINGS_BASE_HPP diff --git a/src/strings/base.tcc b/src/strings/base.tcc new file mode 100644 index 0000000..cde277f --- /dev/null +++ b/src/strings/base.tcc @@ -0,0 +1,442 @@ +// strings/base.tcc - Inline functions for strings/base.hpp +// +// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> +// +// This file is part of The Mana World (Athena server) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + +#include <algorithm> + +#include "pair.hpp" + +namespace strings +{ + namespace detail + { + constexpr + bool is_print(char c) + { + return ' ' <= c && c <= '~'; + } + constexpr + bool is_graph(char c) + { + return is_print(c) && c != ' '; + } + constexpr + bool is_lower(char c) + { + return 'a' <= c && c <= 'z'; + } + constexpr + bool is_upper(char c) + { + return 'A' <= c && c <= 'Z'; + } + constexpr + bool is_alpha(char c) + { + return is_lower(c) || is_upper(c); + } + constexpr + bool is_digit2(char c) + { + return '0' <= c && c <= '1'; + } + constexpr + bool is_digit8(char c) + { + return '0' <= c && c <= '7'; + } + constexpr + bool is_digit10(char c) + { + return '0' <= c && c <= '9'; + } + constexpr + bool is_digit16(char c) + { + return ('0' <= c && c <= '9') || ('A' <= c && c <= 'F') || ('a' <= c && c <= 'f'); + } + constexpr + bool is_alnum(char c) + { + return is_alpha(c) || is_digit10(c); + } + + constexpr + char to_lower(char c) + { + return is_upper(c) ? c | ' ' : c; + } + constexpr + char to_upper(char c) + { + return is_lower(c) ? c & ~' ' : c; + } + } // namespace detail + + template<class T, class O, class P> + const T& _crtp_string<T, O, P>::_ref() const + { + return static_cast<const T&>(*this); + } + template<class T, class O, class P> + typename _crtp_string<T, O, P>::iterator _crtp_string<T, O, P>::begin() const + { + return _ref().begin(); + } + template<class T, class O, class P> + typename _crtp_string<T, O, P>::iterator _crtp_string<T, O, P>::end() const + { + return _ref().end(); + } + template<class T, class O, class P> + const FString *_crtp_string<T, O, P>::base() const + { + return _ref().base(); + } + template<class T, class O, class P> + size_t _crtp_string<T, O, P>::size() const + { + return end() - begin(); + } + template<class T, class O, class P> + typename _crtp_string<T, O, P>::reverse_iterator _crtp_string<T, O, P>::rbegin() const + { + return reverse_iterator(end()); + } + template<class T, class O, class P> + typename _crtp_string<T, O, P>::reverse_iterator _crtp_string<T, O, P>::rend() const + { + return reverse_iterator(begin()); + } + template<class T, class O, class P> + _crtp_string<T, O, P>::operator bool() const + { + return size(); + } + template<class T, class O, class P> + bool _crtp_string<T, O, P>::operator !() const + { + return !size(); + } + template<class T, class O, class P> + _crtp_string<T, O, P>::operator P() const + { + return {&*begin(), &*end()}; + } + + template<class T, class O, class P> + __attribute__((deprecated)) + char _crtp_string<T, O, P>::operator[](size_t i) const + { + return begin()[i]; + } + template<class T, class O, class P> + char _crtp_string<T, O, P>::front() const + { + return *begin(); + } + template<class T, class O, class P> + char _crtp_string<T, O, P>::back() const + { + return end()[-1]; + } + template<class T, class O, class P> + const char *_crtp_string<T, O, P>::data() + { + return &*begin(); + } + + template<class T, class O, class P> + typename P::TailSlice _crtp_string<T, O, P>::xslice_t(size_t o) const + { + return typename P::TailSlice(&begin()[o], &*end(), base()); + } + template<class T, class O, class P> + typename P::FullSlice _crtp_string<T, O, P>::xslice_h(size_t o) const + { + return typename P::FullSlice(&*begin(), &begin()[o], base()); + } + template<class T, class O, class P> + typename P::TailSlice _crtp_string<T, O, P>::xrslice_t(size_t no) const + { + return typename P::TailSlice(&end()[-no], &*end(), base()); + } + template<class T, class O, class P> + typename P::FullSlice _crtp_string<T, O, P>::xrslice_h(size_t no) const + { + return typename P::FullSlice(&*begin(), &end()[-no], base()); + } + template<class T, class O, class P> + typename P::TailSlice _crtp_string<T, O, P>::xislice_t(iterator it) const + { + return typename P::TailSlice(&*it, &*end(), base()); + } + template<class T, class O, class P> + typename P::FullSlice _crtp_string<T, O, P>::xislice_h(iterator it) const + { + return typename P::FullSlice(&*begin(), &*it, base()); + } + template<class T, class O, class P> + typename P::FullSlice _crtp_string<T, O, P>::xlslice(size_t o, size_t l) const + { + return typename P::FullSlice(&begin()[o], &begin()[o + l], base()); + } + template<class T, class O, class P> + typename P::FullSlice _crtp_string<T, O, P>::xpslice(size_t b, size_t e) const + { + return typename P::FullSlice(&begin()[b], &begin()[e], base()); + } + template<class T, class O, class P> + typename P::FullSlice _crtp_string<T, O, P>::xislice(iterator b, iterator e) const + { + return typename P::FullSlice(&*b, &*e, base()); + } + template<class T, class O, class P> + typename P::TailSlice _crtp_string<T, O, P>::lstrip() const + { + typename P::TailSlice z = _ref(); + while (z.startswith(' ')) + z = z.xslice_t(1); + return z; + } + template<class T, class O, class P> + typename P::FullSlice _crtp_string<T, O, P>::rstrip() const + { + typename P::FullSlice x = _ref(); + while (x.endswith(' ')) + x = x.xrslice_h(1); + return x; + } + template<class T, class O, class P> + typename P::FullSlice _crtp_string<T, O, P>::strip() const + { + return lstrip().rstrip(); + } + + template<class T, class O, class P> + bool _crtp_string<T, O, P>::startswith(XPair x) const + { + return size() >= x.size() && pair_compare(xslice_h(x.size()), x) == 0; + } + template<class T, class O, class P> + bool _crtp_string<T, O, P>::endswith(XPair x) const + { + return size() > x.size() && pair_compare(xrslice_t(x.size()), x) == 0; + } + template<class T, class O, class P> + bool _crtp_string<T, O, P>::startswith(char c) const + { + return size() && front() == c; + } + template<class T, class O, class P> + bool _crtp_string<T, O, P>::endswith(char c) const + { + return size() && back() == c; + } + template<class T, class O, class P> + bool _crtp_string<T, O, P>::contains(char c) const + { + return std::find(begin(), end(), c) != end(); + } + template<class T, class O, class P> + bool _crtp_string<T, O, P>::contains_seq(XPair s) const + { + return std::search(begin(), end(), s.begin(), s.end()) != end(); + } + template<class T, class O, class P> + bool _crtp_string<T, O, P>::contains_any(XPair s) const + { + return std::find_if(s.begin(), s.end(), [this](char c) { return this->contains(c); }) != end(); + } + + template<class T, class O, class P> + bool _crtp_string<T, O, P>::has_print() const + { + return std::find_if(begin(), end(), detail::is_print) != end(); } + template<class T, class O, class P> + bool _crtp_string<T, O, P>::is_print() const + { + return std::find_if_not(begin(), end(), detail::is_print) == end(); } + template<class T, class O, class P> + O _crtp_string<T, O, P>::to_print() const + { + if (is_print()) return _ref(); + char buf[size()]; + char *const b = buf; + char *const e = std::transform(begin(), end(), b, [](char c) { return detail::is_print(c) ? c : '_'; }); + return XPair(b, e); + } + + template<class T, class O, class P> + bool _crtp_string<T, O, P>::has_graph() const + { + return std::find_if(begin(), end(), detail::is_graph) != end(); + } + template<class T, class O, class P> + bool _crtp_string<T, O, P>::is_graph() const + { + return std::find_if_not(begin(), end(), detail::is_graph) == end(); + } + + template<class T, class O, class P> + bool _crtp_string<T, O, P>::has_lower() const + { + return std::find_if(begin(), end(), detail::is_lower) != end(); + } + template<class T, class O, class P> + bool _crtp_string<T, O, P>::is_lower() const + { + return std::find_if_not(begin(), end(), detail::is_lower) == end(); + } + template<class T, class O, class P> + O _crtp_string<T, O, P>::to_lower() const + { + if (!has_upper()) return _ref(); + char buf[size()]; + char *const b = buf; + char *const e = std::transform(begin(), end(), b, detail::to_lower); + return XPair(b, e); + } + + template<class T, class O, class P> + bool _crtp_string<T, O, P>::has_upper() const + { + return std::find_if(begin(), end(), detail::is_upper) != end(); + } + template<class T, class O, class P> + bool _crtp_string<T, O, P>::is_upper() const + { + return std::find_if_not(begin(), end(), detail::is_upper) == end(); + } + template<class T, class O, class P> + O _crtp_string<T, O, P>::to_upper() const + { + if (!has_lower()) return _ref(); + char buf[size()]; + char *const b = buf; + char *const e = std::transform(begin(), end(), b, detail::to_upper); + return XPair(b, e); + } + + template<class T, class O, class P> + bool _crtp_string<T, O, P>::has_alpha() const + { + return std::find_if(begin(), end(), detail::is_alpha) != end(); + } + template<class T, class O, class P> + bool _crtp_string<T, O, P>::is_alpha() const + { + return std::find_if_not(begin(), end(), detail::is_alpha) == end(); + } + + template<class T, class O, class P> + bool _crtp_string<T, O, P>::has_digit2() const + { + return std::find_if(begin(), end(), detail::is_digit2) != end(); + } + template<class T, class O, class P> + bool _crtp_string<T, O, P>::is_digit2() const + { + return std::find_if_not(begin(), end(), detail::is_digit2) == end(); + } + template<class T, class O, class P> + bool _crtp_string<T, O, P>::has_digit8() const + { + return std::find_if(begin(), end(), detail::is_digit8) != end(); + } + template<class T, class O, class P> + bool _crtp_string<T, O, P>::is_digit8() const + { + return std::find_if_not(begin(), end(), detail::is_digit8) == end(); + } + template<class T, class O, class P> + bool _crtp_string<T, O, P>::has_digit10() const + { + return std::find_if(begin(), end(), detail::is_digit10) != end(); + } + template<class T, class O, class P> + bool _crtp_string<T, O, P>::is_digit10() const + { + return std::find_if_not(begin(), end(), detail::is_digit10) == end(); + } + template<class T, class O, class P> + bool _crtp_string<T, O, P>::has_digit16() const + { + return std::find_if(begin(), end(), detail::is_digit16) != end(); + } + template<class T, class O, class P> + bool _crtp_string<T, O, P>::is_digit16() const + { + return std::find_if_not(begin(), end(), detail::is_digit16) == end(); + } + + template<class T, class O, class P> + bool _crtp_string<T, O, P>::has_alnum() const + { + return std::find_if(begin(), end(), detail::is_alnum) != end(); + } + template<class T, class O, class P> + bool _crtp_string<T, O, P>::is_alnum() const + { + return std::find_if_not(begin(), end(), detail::is_alnum) == end(); + } + + // not really intended for public use + inline + int pair_compare(XPair l, XPair r) + { + bool less = std::lexicographical_compare( + l.begin(), l.end(), + r.begin(), r.end()); + bool greater = std::lexicographical_compare( + r.begin(), r.end(), + l.begin(), l.end()); + return greater - less; + } + + template<class L, class R, typename> + auto operator == (const L& l, const R& r) -> decltype((pair_compare(l, r), true)) + { + return pair_compare(l, r) == 0; + } + template<class L, class R, typename> + auto operator != (const L& l, const R& r) -> decltype((pair_compare(l, r), true)) + { + return pair_compare(l, r) != 0; + } + template<class L, class R, typename> + auto operator < (const L& l, const R& r) -> decltype((pair_compare(l, r), true)) + { + return pair_compare(l, r) < 0; + } + template<class L, class R, typename> + auto operator <= (const L& l, const R& r) -> decltype((pair_compare(l, r), true)) + { + return pair_compare(l, r) <= 0; + } + template<class L, class R, typename> + auto operator > (const L& l, const R& r) -> decltype((pair_compare(l, r), true)) + { + return pair_compare(l, r) > 0; + } + template<class L, class R, typename> + auto operator >= (const L& l, const R& r) -> decltype((pair_compare(l, r), true)) + { + return pair_compare(l, r) >= 0; + } +} // namespace strings diff --git a/src/strings/base_test.cpp b/src/strings/base_test.cpp new file mode 100644 index 0000000..836ea4b --- /dev/null +++ b/src/strings/base_test.cpp @@ -0,0 +1,18 @@ +#include "base.hpp" +#include "vstring.hpp" +#include "xstring.hpp" +#include "fstring.hpp" + +using namespace strings; + +struct _test : VString<1> {}; +struct _test2 : VString<1> {}; + +static_assert(string_comparison_allowed<_test, _test>::value, "tt"); +static_assert(string_comparison_allowed<VString<1>, VString<1>>::value, "vv"); +static_assert(!string_comparison_allowed<_test, XString>::value, "tx"); +static_assert(!string_comparison_allowed<_test, VString<1>>::value, "tv"); +static_assert(!string_comparison_allowed<_test, _test2>::value, "t2"); +static_assert(string_comparison_allowed<VString<1>, XString>::value, "vx"); +static_assert(string_comparison_allowed<XString, XString>::value, "xx"); +static_assert(string_comparison_allowed<XString, FString>::value, "xf"); diff --git a/src/strings/fstring.cpp b/src/strings/fstring.cpp new file mode 100644 index 0000000..4b20852 --- /dev/null +++ b/src/strings/fstring.cpp @@ -0,0 +1,150 @@ +#include "fstring.hpp" +// strings/fstring.cpp - Functions for fstring.hpp +// +// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> +// +// This file is part of The Mana World (Athena server) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + +#include "mstring.hpp" +#include "tstring.hpp" +#include "sstring.hpp" +#include "zstring.hpp" +#include "xstring.hpp" +#include "vstring.hpp" + +namespace strings +{ + FString::FString() + { + const char *sadness = ""; + _assign(sadness, sadness); + } + + FString::FString(const MString& s) + { + _assign(s.begin(), s.end()); + } + + FString::FString(XPair p) + { + _assign(p.begin(), p.end()); + } + + FString::FString(const TString& t) + { + *this = XString(t); + } + FString::FString(const SString& s) + { + *this = XString(s); + } + FString::FString(ZString z) + { + *this = XString(z); + } + FString::FString(XString x) + { + const FString *f = x.base(); + const char *xb = &*x.begin(); + const char *xe = &*x.end(); + const char *fb = f ? &*f->begin() : nullptr; + const char *fe = f ? &*f->end() : nullptr; + if (f && xb == fb && xe == fe) + *this = *f; + else + _assign(x.begin(), x.end()); + } + + FString::iterator FString::begin() const + { + return &_hack2->begin()[0]; + } + FString::iterator FString::end() const + { + return &_hack2->end()[-1]; + } + const FString *FString::base() const + { + return this; + } + const char *FString::c_str() const + { + return &*begin(); + } + + TS FS::oslice_t(size_t o) const + { return TS(*this, o); } + SS FS::oslice_h(size_t o) const + { return SS(*this, 0, o); } + TS FS::orslice_t(size_t no) const + { return TS(*this, size() - no); } + SS FS::orslice_h(size_t no) const + { return SS(*this, 0, size() - no); } + TS FS::oislice_t(iterator it) const + { return TS(*this, it - begin()); } + SS FS::oislice_h(iterator it) const + { return SS(*this, 0, it - begin()); } + SS FS::olslice(size_t o, size_t l) const + { return SS(*this, o, o + l); } + SS FS::opslice(size_t b, size_t e) const + { return SS(*this, b, e); } + SS FS::oislice(iterator b, iterator e) const + { return SS(*this, b - begin(), e - begin()); } + + const char *decay_for_printf(const FString& fs) + { + return fs.c_str(); + } + + int do_vprint(FString& out, const char *fmt, va_list ap) + { + int len; + { + va_list ap2; + va_copy(ap2, ap); + len = vsnprintf(nullptr, 0, fmt, ap2); + va_end(ap2); + } + char buffer[len + 1]; + vsnprintf(buffer, len + 1, fmt, ap); + + out = FString(buffer, buffer + len); + return len; + } + + StringConverter::StringConverter(FString& s) + : out(s), mid(nullptr) + {} + + StringConverter::~StringConverter() + { + if (mid) + { + out = ZString(really_construct_from_a_pointer, mid, nullptr); + free(mid); + } + } + + char **StringConverter::operator &() + { + return ∣ + } + + StringConverter convert_for_scanf(FString& s) + { + return StringConverter(s); + } +} // namespace strings diff --git a/src/strings/fstring.hpp b/src/strings/fstring.hpp new file mode 100644 index 0000000..0f4f09d --- /dev/null +++ b/src/strings/fstring.hpp @@ -0,0 +1,104 @@ +#ifndef TMWA_STRINGS_FSTRING_HPP +#define TMWA_STRINGS_FSTRING_HPP +// strings/fstring.hpp - An owned, reference-counted immutable string. +// +// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> +// +// This file is part of The Mana World (Athena server) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + +#include <cstdarg> +#include <cstring> + +#include <memory> +#include <vector> + +#include "base.hpp" + +namespace strings +{ + /// An owning string that has reached its final contents. + /// The storage is NUL-terminated + /// TODO reimplement without std::shared_ptr + class FString : public _crtp_string<FString, FString, ZPair> + { + std::shared_ptr<std::vector<char>> _hack2; + + template<class It> + void _assign(It b, It e); + public: + FString(); + + explicit FString(const MString& s); + + template<size_t n> + FString(char (&s)[n]) = delete; + + template<size_t n> + FString(const char (&s)[n]); + + template<class It> + FString(It b, It e); + + FString(XPair p); + //FString(const FString&) + FString(const TString&); + FString(const SString&); + FString(ZString); + FString(XString); + template<uint8_t n> + FString(const VString<n>& v); + + iterator begin() const; + iterator end() const; + const FString *base() const; + const char *c_str() const; + + TString oslice_t(size_t o) const; + SString oslice_h(size_t o) const; + TString orslice_t(size_t no) const; + SString orslice_h(size_t no) const; + TString oislice_t(iterator it) const; + SString oislice_h(iterator it) const; + SString olslice(size_t o, size_t l) const; + SString opslice(size_t b, size_t e) const; + SString oislice(iterator b, iterator e) const; + }; + + // cxxstdio helpers + // I think the conversion will happen automatically. TODO test this. + // Nope, it doesn't, since there's a template + // Actually, it might now. + const char *decay_for_printf(const FString& fs); + + __attribute__((format(printf, 2, 0))) + int do_vprint(FString& out, const char *fmt, va_list ap); + + class StringConverter + { + FString& out; + char *mid; + public: + StringConverter(FString& s); + ~StringConverter(); + char **operator &(); + }; + + StringConverter convert_for_scanf(FString& s); +} // namespace strings + +#include "fstring.tcc" + +#endif // TMWA_STRINGS_FSTRING_HPP diff --git a/src/strings/fstring.tcc b/src/strings/fstring.tcc new file mode 100644 index 0000000..388aef1 --- /dev/null +++ b/src/strings/fstring.tcc @@ -0,0 +1,62 @@ +// strings/fstring.tcc - Inline functions for fstring.hpp +// +// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> +// +// This file is part of The Mana World (Athena server) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + +namespace strings +{ + template<class It> + void FString::_assign(It b, It e) + { + if (b == e) + { + // TODO use a special empty object + // return; + } + if (!std::is_base_of<std::forward_iterator_tag, typename std::iterator_traits<It>::iterator_category>::value) + { + // can't use std::distance + _hack2 = std::make_shared<std::vector<char>>(); + for (; b != e; ++b) + _hack2->push_back(*b); + _hack2->push_back('\0'); + _hack2->shrink_to_fit(); + return; + } + size_t diff = std::distance(b, e); + _hack2 = std::make_shared<std::vector<char>>(diff + 1, '\0'); + std::copy(b, e, _hack2->begin()); + } + + template<size_t n> + FString::FString(const char (&s)[n]) + { + _assign(s, s + strlen(s)); + } + + template<class It> + FString::FString(It b, It e) + { + _assign(b, e); + } + + template<uint8_t n> + FString::FString(const VString<n>& v) + { + _assign(v.begin(), v.end()); + } +} // namespace strings diff --git a/src/strings/fwd.hpp b/src/strings/fwd.hpp new file mode 100644 index 0000000..41abbbb --- /dev/null +++ b/src/strings/fwd.hpp @@ -0,0 +1,58 @@ +#ifndef TMWA_STRINGS_FWD_HPP +#define TMWA_STRINGS_FWD_HPP +// strings/fwd.hpp - Forward declarations for all the string classes. +// +// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> +// +// This file is part of The Mana World (Athena server) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + +#include "../common/sanity.hpp" + +// It is a common mistake to assume that one string class for everything. +// Because C++ and TMWA have a C legacy, there are a few more here +// than would probably be necessary in an ideal language. +namespace strings +{ + // owning + class MString; + class FString; + class TString; // C legacy version of SString + class SString; // is this one really worth it? + + // non-owning + class ZString; // C legacy version of XString + class XString; + + // semi-owning + template<uint8_t len> + class VString; + + // refactor this into a function? + enum _type_that_just_has_a_name_to_fix_linkage + { really_construct_from_a_pointer }; +} // namespace strings + +using strings::MString; +using strings::FString; +using strings::TString; +using strings::SString; + +using strings::ZString; +using strings::XString; + +using strings::VString; + +#endif // TMWA_STRINGS_FWD_HPP diff --git a/src/strings/mstring.cpp b/src/strings/mstring.cpp new file mode 100644 index 0000000..0d496a5 --- /dev/null +++ b/src/strings/mstring.cpp @@ -0,0 +1,100 @@ +#include "mstring.hpp" +// strings/mstring.cpp - Functions for mstring.hpp +// +// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> +// +// This file is part of The Mana World (Athena server) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + +#include "xstring.hpp" + +namespace strings +{ + MString::iterator MString::begin() + { + return _hack.begin(); + } + MString::iterator MString::end() + { + return _hack.end(); + } + MString::const_iterator MString::begin() const + { + return _hack.begin(); + } + MString::const_iterator MString::end() const + { + return _hack.end(); + } + MString::reverse_iterator MString::rbegin() + { + return reverse_iterator(end()); + } + MString::reverse_iterator MString::rend() + { + return reverse_iterator(begin()); + } + MString::const_reverse_iterator MString::rbegin() const + { + return const_reverse_iterator(end()); + } + MString::const_reverse_iterator MString::rend() const + { + return const_reverse_iterator(begin()); + } + + size_t MString::size() const + { + return _hack.size(); + } + MString::operator bool() const + { + return size(); + } + bool MString::operator !() const + { + return !size(); + } + + MString& MString::operator += (MString rhs) + { + _hack.insert(_hack.end(), rhs.begin(), rhs.end()); + return *this; + } + MString& MString::operator += (char c) + { + _hack.push_back(c); + return *this; + } + MString& MString::operator += (XString x) + { + _hack.insert(_hack.end(), x.begin(), x.end()); + return *this; + } + + void MString::pop_back(size_t n) + { + while (n--) + _hack.pop_back(); + } + char& MString::front() + { + return _hack.front(); + } + char& MString::back() + { + return _hack.back(); + } +} // namespace strings diff --git a/src/strings/mstring.hpp b/src/strings/mstring.hpp new file mode 100644 index 0000000..9658601 --- /dev/null +++ b/src/strings/mstring.hpp @@ -0,0 +1,66 @@ +#ifndef TMWA_STRINGS_MSTRING_HPP +#define TMWA_STRINGS_MSTRING_HPP +// strings/mstring.hpp - A mutable string. +// +// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> +// +// This file is part of The Mana World (Athena server) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + +#include <deque> + +#include "base.hpp" + +namespace strings +{ + /// An owning string that is still expected to change. + /// The storage might not be contiguous, but it still offers + /// random-access iterators. + /// TODO implement a special one, to avoid quirks of std::deque. + class MString + { + public: + typedef std::deque<char>::iterator iterator; + typedef std::deque<char>::const_iterator const_iterator; + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + private: + std::deque<char> _hack; + public: + iterator begin(); + iterator end(); + const_iterator begin() const; + const_iterator end() const; + reverse_iterator rbegin(); + reverse_iterator rend(); + const_reverse_iterator rbegin() const; + const_reverse_iterator rend() const; + + size_t size() const; + explicit + operator bool() const; + bool operator !() const; + + MString& operator += (MString rhs); + MString& operator += (char c); + MString& operator += (XString xs); + + void pop_back(size_t n=1); + char& front(); + char& back(); + }; +} // namespace strings + +#endif // TMWA_STRINGS_MSTRING_HPP diff --git a/src/strings/pair.hpp b/src/strings/pair.hpp new file mode 100644 index 0000000..88422be --- /dev/null +++ b/src/strings/pair.hpp @@ -0,0 +1,73 @@ +#ifndef TMWA_STRINGS_PAIR_HPP +#define TMWA_STRINGS_PAIR_HPP +// strings/pair.hpp - Internal contiguous range. +// +// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> +// +// This file is part of The Mana World (Athena server) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + +#include "../common/sanity.hpp" + +#include <cstring> + +#include "fwd.hpp" + +namespace strings +{ + // TODO instead typedef ranges::Contiguous<const char> + // or whatever it becomes once it exists. + // const_array is just a hack, as evidenced by the fact + // that it's not really const. + class XPair + { + const char *_begin; + const char *_end; + public: + typedef XString TailSlice; + typedef XString FullSlice; + + XPair(const char *b, const char *e) + : _begin(b), _end(e) + {} + template<size_t n> + XPair(char (&arr)[n]) = delete; + template<size_t n> + XPair(const char (&arr)[n]) + : _begin(arr), _end(arr + strlen(arr)) + {} + + const char *begin() const { return _begin; } + const char *end() const { return _end; } + size_t size() { return end() - begin(); } + }; + struct ZPair : XPair + { + typedef ZString TailSlice; + typedef XString FullSlice; + + ZPair(const char *b, const char *e) + : XPair(b, e) + {} + template<size_t n> + ZPair(char (&arr)[n]) = delete; + template<size_t n> + ZPair(const char (&arr)[n]) + : XPair(arr) + {} + }; +} // namespace strings + +#endif // TMWA_STRINGS_PAIR_HPP diff --git a/src/strings/sstring.cpp b/src/strings/sstring.cpp new file mode 100644 index 0000000..bcbcb58 --- /dev/null +++ b/src/strings/sstring.cpp @@ -0,0 +1,91 @@ +#include "sstring.hpp" +// strings/sstring.cpp - Functions for sstring.hpp +// +// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> +// +// This file is part of The Mana World (Athena server) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + +#include "tstring.hpp" +#include "zstring.hpp" +#include "xstring.hpp" + +namespace strings +{ + SString::SString() + : _s(), _b(), _e() + {} + SString::SString(FString f) + : _s(std::move(f)), _b(), _e(_s.size()) + {} + SString::SString(TString t) + : _s(t._s), _b(0), _e(_s.size()) + {} + SString::SString(const ZString& z) + { + *this = XString(z); + } + SString::SString(const XString& x) + { + const FString *f = x.base(); + const char *xb = &*x.begin(); + const char *xe = &*x.end(); + const char *fb = f ? &*f->begin() : nullptr; + //const char *fe = f ? &*f->end() : nullptr; + if (f) + *this = SString(*f, xb - fb, xe - fb); + else + *this = FString(x); + } + + SString::SString(FString f, size_t b, size_t e) + : _s(std::move(f)), _b(b), _e(e) + {} + SString::SString(XPair p) + : _s(p), _b(0), _e(p.size()) + {} + + SString::iterator SString::begin() const + { + return &_s.begin()[_b]; + } + SString::iterator SString::end() const + { + return &_s.begin()[_e]; + } + const FString *SString::base() const + { + return &_s; + } + + SS SS::oslice_t(size_t o) const + { return SS(_s, _b + o, _e); } + SS SS::oslice_h(size_t o) const + { return SS(_s, _b, _b + o); } + SS SS::orslice_t(size_t no) const + { return SS(_s, _e - no, _e); } + SS SS::orslice_h(size_t no) const + { return SS(_s, _b, _e - no); } + SS SS::oislice_t(iterator it) const + { return SS(_s, _b + it - begin(), _e); } + SS SS::oislice_h(iterator it) const + { return SS(_s, _b, _b + it - begin()); } + SS SS::olslice(size_t o, size_t l) const + { return SS(_s, _b + o, _b + o + l); } + SS SS::opslice(size_t b, size_t e) const + { return SS(_s, _b + b, _b + e); } + SS SS::oislice(iterator b, iterator e) const + { return SS(_s, _b + b - begin(), _b + e - begin()); } +} // namespace strings diff --git a/src/strings/sstring.hpp b/src/strings/sstring.hpp new file mode 100644 index 0000000..6f55f9a --- /dev/null +++ b/src/strings/sstring.hpp @@ -0,0 +1,69 @@ +#ifndef TMWA_STRINGS_SSTRING_HPP +#define TMWA_STRINGS_SSTRING_HPP +// strings/sstring.hpp - A full slice of an FString. +// +// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> +// +// This file is part of The Mana World (Athena server) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + +#include "base.hpp" +#include "fstring.hpp" + +namespace strings +{ + /// An owning string that represents a arbitrary slice of an FString. + /// Not guaranteed to be NUL-terminated. + class SString : public _crtp_string<SString, SString, XPair> + { + FString _s; + size_t _b, _e; + public: + SString(); + SString(FString f); + SString(TString t); + //SString(const SString&); + SString(const ZString&); + SString(const XString&); + template<uint8_t n> + SString(const VString<n>& v); + template<size_t n> + SString(char (&s)[n]) = delete; + template<size_t n> + SString(const char (&s)[n]); + //template<class It> + //SString(It b, It e) : _s(b, e), _b(0), _e(_s.size()) {} + SString(FString f, size_t b, size_t e); + SString(XPair p); + + iterator begin() const; + iterator end() const; + const FString *base() const; + + SString oslice_t(size_t o) const; + SString oslice_h(size_t o) const; + SString orslice_t(size_t no) const; + SString orslice_h(size_t no) const; + SString oislice_t(iterator it) const; + SString oislice_h(iterator it) const; + SString olslice(size_t o, size_t l) const; + SString opslice(size_t b, size_t e) const; + SString oislice(iterator b, iterator e) const; + }; +} // namespace strings + +#include "sstring.tcc" + +#endif // TMWA_STRINGS_SSTRING_HPP diff --git a/src/strings/sstring.tcc b/src/strings/sstring.tcc new file mode 100644 index 0000000..4be33dd --- /dev/null +++ b/src/strings/sstring.tcc @@ -0,0 +1,33 @@ +// strings/sstring.tcc - Inline functions for fstring.hpp +// +// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> +// +// This file is part of The Mana World (Athena server) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + +#include "vstring.hpp" + +namespace strings +{ + template<uint8_t n> + SString::SString(const VString<n>& v) + : _s(v), _b(0), _e(_s.size()) + {} + + template<size_t n> + SString::SString(const char (&s)[n]) + : _s(s), _b(0), _e(_s.size()) + {} +} // namespace strings diff --git a/src/common/strings2_test.cpp b/src/strings/strings2_test.cpp index fa4dc6f..3f8662a 100644 --- a/src/common/strings2_test.cpp +++ b/src/strings/strings2_test.cpp @@ -1,4 +1,4 @@ -#include "strings.hpp" +#include "all.hpp" #include <gtest/gtest.h> diff --git a/src/common/strings_test.cpp b/src/strings/strings_test.cpp index fa04f1c..b7a7d39 100644 --- a/src/common/strings_test.cpp +++ b/src/strings/strings_test.cpp @@ -1,4 +1,4 @@ -#include "strings.hpp" +#include "all.hpp" #include <algorithm> @@ -228,6 +228,24 @@ TYPED_TEST_P(StringTest, convert) EXPECT_EQ(v, v3); EXPECT_EQ(l, l3); EXPECT_EQ(hi, hi3); + + TypeParam f4(f); + TypeParam t4(t); + TypeParam s4(s); + TypeParam z4(z); + TypeParam x4(x); + TypeParam v4(v); + TypeParam l4(l); + TypeParam hi4(hi); + + EXPECT_EQ(f, f4); + EXPECT_EQ(t, t4); + EXPECT_EQ(s, s4); + EXPECT_EQ(z, z4); + EXPECT_EQ(x, x4); + EXPECT_EQ(v, v4); + EXPECT_EQ(l, l4); + EXPECT_EQ(hi, hi4); } REGISTER_TYPED_TEST_CASE_P(StringTest, @@ -244,7 +262,7 @@ TEST(VStringTest, basic) EXPECT_EQ(5, hi.size()); EXPECT_EQ(hi, hi); // truncation - VString<5> hi2(ZString::really_construct_from_a_pointer, "Hello, world!"); + VString<5> hi2(strings::really_construct_from_a_pointer, "Hello, world!"); EXPECT_EQ(5, hi2.size()); EXPECT_EQ(hi, hi2); // short diff --git a/src/strings/tstring.cpp b/src/strings/tstring.cpp new file mode 100644 index 0000000..9decc61 --- /dev/null +++ b/src/strings/tstring.cpp @@ -0,0 +1,98 @@ +#include "tstring.hpp" +// strings/tstring.cpp - Functions for tstring.hpp +// +// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> +// +// This file is part of The Mana World (Athena server) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + +#include "sstring.hpp" +#include "zstring.hpp" +#include "xstring.hpp" + +namespace strings +{ + TString::TString() + : _s(), _o() + {} + TString::TString(FString b, size_t i) + : _s(std::move(b)), _o(i) + {} + TString::TString(const SString& s) + { + *this = XString(s); + } + TString::TString(const ZString& z) + { + *this = XString(z); + } + TString::TString(const XString& x) + { + const FString *f = x.base(); + const char *xb = &*x.begin(); + const char *xe = &*x.end(); + const char *fb = f ? &*f->begin() : nullptr; + const char *fe = f ? &*f->end() : nullptr; + if (f && xe == fe) + *this = TString(*f, xb - fb); + else + *this = FString(x); + } + + TString::TString(XPair p) + : _s(p), _o(0) + {} + + TString::iterator TString::begin() const + { + return &_s.begin()[_o]; + } + TString::iterator TString::end() const + { + return &*_s.end(); + } + const FString *TString::base() const + { + return &_s; + } + const char *TString::c_str() const + { + return &*begin(); + } + + TS TS::oslice_t(size_t o) const + { return TS(_s, _o + o); } + SS TS::oslice_h(size_t o) const + { return SS(_s, _o, _o + o); } + TS TS::orslice_t(size_t no) const + { return TS(_s, _s.size() - no); } + SS TS::orslice_h(size_t no) const + { return SS(_s, _o, _s.size() - no); } + TS TS::oislice_t(iterator it) const + { return TS(_s, _o + it - begin()); } + SS TS::oislice_h(iterator it) const + { return SS(_s, _o, _o + it - begin()); } + SS TS::olslice(size_t o, size_t l) const + { return SS(_s, _o + o, _o + o + l); } + SS TS::opslice(size_t b, size_t e) const + { return SS(_s, _o + b, _o + e); } + SS TS::oislice(iterator b, iterator e) const + { return SS(_s, _o + b - begin(), _o + e - begin()); } + + const char *decay_for_printf(const TString& ts) + { + return ts.c_str(); + } +} // namespace strings diff --git a/src/strings/tstring.hpp b/src/strings/tstring.hpp new file mode 100644 index 0000000..63f3b7a --- /dev/null +++ b/src/strings/tstring.hpp @@ -0,0 +1,76 @@ +#ifndef TMWA_STRINGS_TSTRING_HPP +#define TMWA_STRINGS_TSTRING_HPP +// strings/tstring.hpp - A tail slice of a string. +// +// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> +// +// This file is part of The Mana World (Athena server) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + +#include "base.hpp" +#include "fstring.hpp" + +namespace strings +{ + /// An owning string that represents a tail slice of an FString. + /// Guaranteed to be NUL-terminated. + class TString : public _crtp_string<TString, TString, ZPair> + { + friend class SString; + FString _s; + size_t _o; + public: + TString(); + TString(FString b, size_t i=0); + //TString(const TString&) + TString(const SString&); + TString(const ZString&); + TString(const XString&); + template<uint8_t n> + TString(const VString<n>& v); + template<size_t n> + TString(char (&s)[n]) = delete; + template<size_t n> + TString(const char (&s)[n]); + //template<class It> + //TString(It b, It e) : _s(b, e), _o(0) {} + TString(XPair p); + + iterator begin() const; + iterator end() const; + const FString *base() const; + const char *c_str() const; + + TString oslice_t(size_t o) const; + SString oslice_h(size_t o) const; + TString orslice_t(size_t no) const; + SString orslice_h(size_t no) const; + TString oislice_t(iterator it) const; + SString oislice_h(iterator it) const; + SString olslice(size_t o, size_t l) const; + SString opslice(size_t b, size_t e) const; + SString oislice(iterator b, iterator e) const; + }; + + // cxxstdio helpers + // I think the conversion will happen automatically. TODO test this. + // Nope, it doesn't, since there's a template + // Actually, it might now. + const char *decay_for_printf(const TString& ts); +} // namespace strings + +#include "tstring.tcc" + +#endif // TMWA_STRINGS_TSTRING_HPP diff --git a/src/strings/tstring.tcc b/src/strings/tstring.tcc new file mode 100644 index 0000000..4eba13f --- /dev/null +++ b/src/strings/tstring.tcc @@ -0,0 +1,32 @@ +// strings/tstring.tcc - Inline functions for tstring.hpp +// +// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> +// +// This file is part of The Mana World (Athena server) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + +#include "vstring.hpp" + +namespace strings +{ + template<uint8_t n> + TString::TString(const VString<n>& v) + : _s(v), _o(0) + {} + template<size_t n> + TString::TString(const char (&s)[n]) + : _s(s), _o(0) + {} +} // namespace strings diff --git a/src/strings/vstring.cpp b/src/strings/vstring.cpp new file mode 100644 index 0000000..6a0416a --- /dev/null +++ b/src/strings/vstring.cpp @@ -0,0 +1,23 @@ +#include "vstring.hpp" +// strings/vstring.cpp - Functions for vstring.hpp +// +// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> +// +// This file is part of The Mana World (Athena server) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + +namespace strings +{ +} // namespace strings diff --git a/src/strings/vstring.hpp b/src/strings/vstring.hpp new file mode 100644 index 0000000..527c2b4 --- /dev/null +++ b/src/strings/vstring.hpp @@ -0,0 +1,79 @@ +#ifndef TMWA_STRINGS_VSTRING_HPP +#define TMWA_STRINGS_VSTRING_HPP +// strings/vstring.hpp - A small string that stores its own value. +// +// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> +// +// This file is part of The Mana World (Athena server) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + +#include "base.hpp" + +namespace strings +{ + template<uint8_t n> + class VString : public _crtp_string<VString<n>, VString<n>, ZPair> + { + char _data[n]; + unsigned char _special; + public: + typedef typename _crtp_string<VString<n>, VString<n>, ZPair>::iterator iterator; + VString(XString x); + VString(FString f); + VString(TString t); + VString(SString s); + VString(ZString z); + template<uint8_t m> + VString(VString<m> v); + template<size_t m> + VString(char (&s)[m]) = delete; + template<size_t m> + VString(const char (&s)[m]); + VString(decltype(really_construct_from_a_pointer) e, const char *s); + VString(char c); + VString(); + VString(XPair p); + + iterator begin() const; + iterator end() const; + const FString *base() const; + const char *c_str() const; + + VString oslice_t(size_t o) const { return this->xslice_t(o); } + VString oslice_h(size_t o) const { return this->xslice_h(o); } + VString orslice_t(size_t no) const { return this->xrslice_t(no); } + VString orslice_h(size_t no) const { return this->xrslice_h(no); } + VString oislice_t(iterator it) const { return this->xislice_t(it); } + VString oislice_h(iterator it) const { return this->xislice_h(it); } + VString olslice(size_t o, size_t l) const { return this->xlslice(o, l); } + VString opslice(size_t b, size_t e) const { return this->xpslice(b, e); } + VString oislice(iterator b, iterator e) const { return this->xislice(b, e); } + }; + + // cxxstdio helpers + // I think the conversion will happen automatically. TODO test this. + // Nope, it doesn't, since there's a template + // Actually, it might now. + template<uint8_t n> + const char *decay_for_printf(const VString<n>& vs); + + template<uint8_t len> + __attribute__((format(printf, 2, 0))) + int do_vprint(VString<len>& out, const char *fmt, va_list ap); +} // namespace strings + +#include "vstring.tcc" + +#endif // TMWA_STRINGS_VSTRING_HPP diff --git a/src/strings/vstring.tcc b/src/strings/vstring.tcc new file mode 100644 index 0000000..674b21d --- /dev/null +++ b/src/strings/vstring.tcc @@ -0,0 +1,143 @@ +// strings/vstring.tcc - Inline functions for vstring.hpp +// +// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> +// +// This file is part of The Mana World (Athena server) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + +#include <cassert> + +#include "../common/utils2.hpp" + +#include "fstring.hpp" +#include "tstring.hpp" +#include "sstring.hpp" +#include "zstring.hpp" +#include "xstring.hpp" + +namespace strings +{ + template<uint8_t n> + VString<n>::VString(XString x) : _data(), _special() + { + if (x.size() > n) + // we're hoping this doesn't happen + // hopefully there will be few enough users of this class + x = x.xslice_h(n); + char *e = std::copy(x.begin(), x.end(), std::begin(_data)); + _special = std::end(_data) - e; + assert (_special == n - x.size()); // 0 when it needs to be + } + // poor man's delegated constructors + // needed for gcc 4.6 compatibility + template<uint8_t n> + VString<n>::VString(FString f) + { + *this = XString(f); + } + template<uint8_t n> + VString<n>::VString(TString t) + { + *this = XString(t); + } + template<uint8_t n> + VString<n>::VString(SString s) + { + *this = XString(s); + } + template<uint8_t n> + VString<n>::VString(ZString z) + { + *this = XString(z); + } + template<uint8_t n> + template<uint8_t m> + VString<n>::VString(VString<m> v) + { + static_assert(m < n, "can only grow"); + *this = XString(v); + } + template<uint8_t n> + template<size_t m> + VString<n>::VString(const char (&s)[m]) + { + static_assert(m <= n + 1, "string would truncate"); + *this = XString(s); + } + template<uint8_t n> + VString<n>::VString(decltype(really_construct_from_a_pointer) e, const char *s) + { + *this = XString(e, s, nullptr); + } + template<uint8_t n> + VString<n>::VString(char c) + { + *this = XString(&c, &c + 1, nullptr); + } + template<uint8_t n> + VString<n>::VString() + { + *this = XString(); + } + template<uint8_t n> + VString<n>::VString(XPair p) + { + *this = XString(p); + } + + // hopefully this is obvious + template<uint8_t n> + typename VString<n>::iterator VString<n>::begin() const + { + return std::begin(_data); + } + template<uint8_t n> + typename VString<n>::iterator VString<n>::end() const + { + return std::end(_data) - _special; + } + template<uint8_t n> + const FString *VString<n>::base() const + { + return nullptr; + } + template<uint8_t n> + const char *VString<n>::c_str() const + { + return &*begin(); + } + + // cxxstdio helpers + // I think the conversion will happen automatically. TODO test this. + // Nope, it doesn't, since there's a template + // Actually, it might now. + template<uint8_t n> + inline + const char *decay_for_printf(const VString<n>& vs) + { + return vs.c_str(); + } + + template<uint8_t len> + inline + int do_vprint(VString<len>& out, const char *fmt, va_list ap) + { + char buffer[len + 1]; + vsnprintf(buffer, len + 1, fmt, ap); + + out = const_(buffer); + return len; + } +} // namespace strings diff --git a/src/strings/xstring.cpp b/src/strings/xstring.cpp new file mode 100644 index 0000000..107217b --- /dev/null +++ b/src/strings/xstring.cpp @@ -0,0 +1,62 @@ +#include "xstring.hpp" +// strings/xstring.cpp - Functions for xstring.hpp +// +// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> +// +// This file is part of The Mana World (Athena server) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + +namespace strings +{ + XString::XString() + : _b(""), _e(_b), _base() + {} + XString::XString(const FString& s) + : _b(&*s.begin()), _e(&*s.end()), _base(s.base()) + {} + XString::XString(const TString& s) + : _b(&*s.begin()), _e(&*s.end()), _base(s.base()) + {} + XString::XString(const SString& s) + : _b(&*s.begin()), _e(&*s.end()), _base(s.base()) + {} + XString::XString(const ZString& s) + : _b(&*s.begin()), _e(&*s.end()), _base(s.base()) + {} + + XString::XString(const char *b, const char *e, const FString *base_) + : _b(b), _e(e), _base(base_) + {} + XString::XString(decltype(really_construct_from_a_pointer) e, const char *s, const FString *base_) + { + *this = ZString(e, s, base_); + } + XString::XString(XPair p) + : _b(p.begin()), _e(p.end()), _base(nullptr) + {} + + XString::iterator XString::begin() const + { + return _b; + } + XString::iterator XString::end() const + { + return _e; + } + const FString *XString::base() const + { + return _base; + } +} // namespace strings diff --git a/src/strings/xstring.hpp b/src/strings/xstring.hpp new file mode 100644 index 0000000..448d0ba --- /dev/null +++ b/src/strings/xstring.hpp @@ -0,0 +1,71 @@ +#ifndef TMWA_STRINGS_XSTRING_HPP +#define TMWA_STRINGS_XSTRING_HPP +// strings/xstring.hpp - A full borrowed slice. +// +// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> +// +// This file is part of The Mana World (Athena server) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + +#include "base.hpp" + +namespace strings +{ + /// A non-owning string that is not guaranteed to be NUL-terminated. + /// This should be only used as a parameter. + class XString : public _crtp_string<XString, FString, XPair> + { + iterator _b, _e; + // optional + const FString *_base; + public: + // do I really want this? + XString(); + XString(std::nullptr_t) = delete; + // no MString + XString(const FString& s); + XString(const TString& s); + XString(const SString& s); + XString(const ZString& s); + template<uint8_t n> + XString(const VString<n>& s); + template<size_t n> + XString(char (&s)[n]) = delete; + template<size_t n> + XString(const char (&s)[n]); + // mostly internal + XString(const char *b, const char *e, const FString *base_); + XString(decltype(really_construct_from_a_pointer) e, const char *s, const FString *base_); + XString(XPair p); + + iterator begin() const; + iterator end() const; + const FString *base() const; + + XString oslice_t(size_t o) const { return xslice_t(o); } + XString oslice_h(size_t o) const { return xslice_h(o); } + XString orslice_t(size_t no) const { return xrslice_t(no); } + XString orslice_h(size_t no) const { return xrslice_h(no); } + XString oislice_t(iterator it) const { return xislice_t(it); } + XString oislice_h(iterator it) const { return xislice_h(it); } + XString olslice(size_t o, size_t l) const { return xlslice(o, l); } + XString opslice(size_t b, size_t e) const { return xpslice(b, e); } + XString oislice(iterator b, iterator e) const { return xislice(b, e); } + }; +} // namespace strings + +#include "xstring.tcc" + +#endif // TMWA_STRINGS_XSTRING_HPP diff --git a/src/strings/xstring.tcc b/src/strings/xstring.tcc new file mode 100644 index 0000000..aee87f8 --- /dev/null +++ b/src/strings/xstring.tcc @@ -0,0 +1,32 @@ +// strings/xstring.tcc - Inline functions for xstring.hpp +// +// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> +// +// This file is part of The Mana World (Athena server) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + +#include "vstring.hpp" + +namespace strings +{ + template<uint8_t n> + XString::XString(const VString<n>& s) + : _b(&*s.begin()), _e(&*s.end()), _base(nullptr) + {} + template<size_t n> + XString::XString(const char (&s)[n]) + : _b(s), _e(s + strlen(s)), _base(nullptr) + {} +} // namespace strings diff --git a/src/strings/zstring.cpp b/src/strings/zstring.cpp new file mode 100644 index 0000000..3b86b0e --- /dev/null +++ b/src/strings/zstring.cpp @@ -0,0 +1,88 @@ +#include "zstring.hpp" +// strings/zstring.cpp - Functions for zstring.hpp +// +// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> +// +// This file is part of The Mana World (Athena server) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + +#include "xstring.hpp" + +namespace strings +{ + ZString::ZString() + { + *this = ZString(""); + } + ZString::ZString(const FString& s) + : _b(&*s.begin()), _e(&*s.end()), _base(s.base()) + {} + ZString::ZString(const TString& s) + : _b(&*s.begin()), _e(&*s.end()), _base(s.base()) + {} + ZString::ZString(const char *b, const char *e, const FString *base_) + : _b(b), _e(e), _base(base_) + {} + ZString::ZString(decltype(really_construct_from_a_pointer), const char *s, const FString *base_) + : _b(s), _e(s + strlen(s)), _base(base_) + {} + + ZString::iterator ZString::begin() const + { + return _b; + } + ZString::iterator ZString::end() const + { + return _e; + } + const FString *ZString::base() const + { + return _base; + } + const char *ZString::c_str() const + { + return &*begin(); + } + + ZS ZS::oslice_t(size_t o) const + { return ZS(really_construct_from_a_pointer, &begin()[o], base()); } + XS ZS::oslice_h(size_t o) const + { return XS(&*begin(), &begin()[o], base()); } + ZS ZS::orslice_t(size_t no) const + { return ZS(really_construct_from_a_pointer, &end()[-no], base()); } + XS ZS::orslice_h(size_t no) const + { return XS(&*begin(), &end()[-no], base()); } + ZS ZS::oislice_t(iterator it) const + { return ZS(really_construct_from_a_pointer, &*it, base()); } + XS ZS::oislice_h(iterator it) const + { return XS(&*begin(), &*it, base()); } + XS ZS::olslice(size_t o, size_t l) const + { return XS(&begin()[o], &begin()[o + l], base()); } + XS ZS::opslice(size_t b, size_t e) const + { return XS(&begin()[b], &begin()[e], base()); } + XS ZS::oislice(iterator b, iterator e) const + { return XS(&*b, &*e, base()); } + + const char *decay_for_printf(const ZString& zs) + { + return zs.c_str(); + } + + __attribute__((format(scanf, 2, 0))) + int do_vscan(ZString in, const char *fmt, va_list ap) + { + return vsscanf(in.c_str(), fmt, ap); + } +} // namespace strings diff --git a/src/strings/zstring.hpp b/src/strings/zstring.hpp new file mode 100644 index 0000000..1b7e7fc --- /dev/null +++ b/src/strings/zstring.hpp @@ -0,0 +1,81 @@ +#ifndef TMWA_STRINGS_ZSTRING_HPP +#define TMWA_STRINGS_ZSTRING_HPP +// strings/zstring.hpp - A borrowed tail slice of a string. +// +// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> +// +// This file is part of The Mana World (Athena server) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + +#include <cstring> + +#include "base.hpp" + +namespace strings +{ + /// A non-owning string that is guaranteed to be NUL-terminated. + /// This should be only used as a parameter. + class ZString : public _crtp_string<ZString, FString, ZPair> + { + iterator _b, _e; + // optional + const FString *_base; + public: + ZString(); + // no MString + ZString(const FString& s); + ZString(const TString& s); + ZString(const SString&) = delete; + //ZString(ZString); + ZString(const XString&) = delete; + template<uint8_t n> + ZString(const VString<n>& s); + // dangerous + ZString(const char *b, const char *e, const FString *base_); + ZString(decltype(really_construct_from_a_pointer), const char *s, const FString *base_); + template<size_t n> + ZString(char (&s)[n]) = delete; + template<size_t n> + ZString(const char (&s)[n], const FString *base_=nullptr); + + iterator begin() const; + iterator end() const; + const FString *base() const; + const char *c_str() const; + + ZString oslice_t(size_t o) const; + XString oslice_h(size_t o) const; + ZString orslice_t(size_t no) const; + XString orslice_h(size_t no) const; + ZString oislice_t(iterator it) const; + XString oislice_h(iterator it) const; + XString olslice(size_t o, size_t l) const; + XString opslice(size_t b, size_t e) const; + XString oislice(iterator b, iterator e) const; + }; + + // cxxstdio helpers + // I think the conversion will happen automatically. TODO test this. + // Nope, it doesn't, since there's a template + // Actually, it might now. + const char *decay_for_printf(const ZString& zs); + + __attribute__((format(scanf, 2, 0))) + int do_vscan(ZString in, const char *fmt, va_list ap); +} // namespace strings + +#include "zstring.tcc" + +#endif // TMWA_STRINGS_ZSTRING_HPP diff --git a/src/strings/zstring.tcc b/src/strings/zstring.tcc new file mode 100644 index 0000000..1065b7c --- /dev/null +++ b/src/strings/zstring.tcc @@ -0,0 +1,35 @@ +// strings/zstring.tcc - Inline functions for zstring.hpp +// +// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> +// +// This file is part of The Mana World (Athena server) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + +#include <cstring> + +#include "vstring.hpp" + +namespace strings +{ + template<uint8_t n> + ZString::ZString(const VString<n>& s) + : _b(&*s.begin()), _e(&*s.end()), _base(nullptr) + {} + + template<size_t n> + ZString::ZString(const char (&s)[n], const FString *base_) + : _b(s), _e(s + strlen(s)), _base(base_) + {} +} // namespace strings |