summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.in2
-rw-r--r--real.make9
-rw-r--r--src/admin/ladmin.cpp8
-rw-r--r--src/char/char.cpp7
-rw-r--r--src/char/char.hpp2
-rw-r--r--src/char/int_party.cpp4
-rw-r--r--src/char/int_party.hpp2
-rw-r--r--src/char/int_storage.cpp4
-rw-r--r--src/char/int_storage.hpp2
-rw-r--r--src/char/inter.cpp7
-rw-r--r--src/char/inter.hpp2
-rw-r--r--src/common/core.cpp4
-rw-r--r--src/common/core.hpp2
-rw-r--r--src/common/dumb_ptr.hpp7
-rw-r--r--src/common/extract.cpp4
-rw-r--r--src/common/extract.hpp2
-rw-r--r--src/common/extract_test.cpp2
-rw-r--r--src/common/human_time_diff.hpp3
-rw-r--r--src/common/intern-pool.hpp4
-rw-r--r--src/common/intern-pool_test.cpp2
-rw-r--r--src/common/io.hpp2
-rw-r--r--src/common/ip.cpp3
-rw-r--r--src/common/ip.hpp3
-rw-r--r--src/common/lock.cpp3
-rw-r--r--src/common/lock.hpp2
-rw-r--r--src/common/md5calc.cpp3
-rw-r--r--src/common/md5calc.hpp4
-rw-r--r--src/common/md5calc_test.cpp3
-rw-r--r--src/common/mmo.hpp5
-rw-r--r--src/common/socket.hpp4
-rw-r--r--src/common/strings.hpp1092
-rw-r--r--src/common/timer.cpp2
-rw-r--r--src/common/timer.hpp2
-rw-r--r--src/common/utils.cpp8
-rw-r--r--src/common/utils.hpp4
-rw-r--r--src/login/login.cpp8
-rw-r--r--src/map/atcommand.cpp8
-rw-r--r--src/map/atcommand.hpp2
-rw-r--r--src/map/battle.cpp5
-rw-r--r--src/map/battle.hpp2
-rw-r--r--src/map/chrif.cpp3
-rw-r--r--src/map/chrif.hpp2
-rw-r--r--src/map/clif.cpp4
-rw-r--r--src/map/clif.hpp3
-rw-r--r--src/map/grfio.cpp3
-rw-r--r--src/map/grfio.hpp1
-rw-r--r--src/map/intif.cpp4
-rw-r--r--src/map/intif.hpp2
-rw-r--r--src/map/itemdb.cpp4
-rw-r--r--src/map/magic-expr-eval.hpp2
-rw-r--r--src/map/magic-expr.cpp5
-rw-r--r--src/map/magic-expr.hpp3
-rw-r--r--src/map/magic-interpreter-base.cpp3
-rw-r--r--src/map/magic-interpreter-parser.ypp3
-rw-r--r--src/map/magic-interpreter.hpp3
-rw-r--r--src/map/magic-stmt.cpp2
-rw-r--r--src/map/magic.cpp2
-rw-r--r--src/map/magic.hpp2
-rw-r--r--src/map/map.cpp7
-rw-r--r--src/map/map.hpp5
-rw-r--r--src/map/map.t.hpp2
-rw-r--r--src/map/mob.cpp3
-rw-r--r--src/map/npc.cpp11
-rw-r--r--src/map/npc.hpp2
-rw-r--r--src/map/party.cpp2
-rw-r--r--src/map/party.hpp2
-rw-r--r--src/map/pc.cpp3
-rw-r--r--src/map/pc.hpp2
-rw-r--r--src/map/script.cpp5
-rw-r--r--src/map/script.hpp15
-rw-r--r--src/map/skill.cpp4
-rw-r--r--src/map/skill.hpp3
-rw-r--r--src/map/tmw.cpp4
-rw-r--r--src/map/tmw.hpp2
-rw-r--r--src/monitor/main.cpp11
-rw-r--r--src/strings/all.hpp31
-rw-r--r--src/strings/base.hpp205
-rw-r--r--src/strings/base.tcc442
-rw-r--r--src/strings/base_test.cpp18
-rw-r--r--src/strings/fstring.cpp150
-rw-r--r--src/strings/fstring.hpp104
-rw-r--r--src/strings/fstring.tcc62
-rw-r--r--src/strings/fwd.hpp58
-rw-r--r--src/strings/mstring.cpp100
-rw-r--r--src/strings/mstring.hpp66
-rw-r--r--src/strings/pair.hpp73
-rw-r--r--src/strings/sstring.cpp91
-rw-r--r--src/strings/sstring.hpp69
-rw-r--r--src/strings/sstring.tcc33
-rw-r--r--src/strings/strings2_test.cpp (renamed from src/common/strings2_test.cpp)2
-rw-r--r--src/strings/strings_test.cpp (renamed from src/common/strings_test.cpp)22
-rw-r--r--src/strings/tstring.cpp98
-rw-r--r--src/strings/tstring.hpp76
-rw-r--r--src/strings/tstring.tcc32
-rw-r--r--src/strings/vstring.cpp23
-rw-r--r--src/strings/vstring.hpp79
-rw-r--r--src/strings/vstring.tcc143
-rw-r--r--src/strings/xstring.cpp62
-rw-r--r--src/strings/xstring.hpp71
-rw-r--r--src/strings/xstring.tcc32
-rw-r--r--src/strings/zstring.cpp88
-rw-r--r--src/strings/zstring.hpp81
-rw-r--r--src/strings/zstring.tcc35
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
diff --git a/real.make b/real.make
index f93640d..e04d98e 100644
--- a/real.make
+++ b/real.make
@@ -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 &mid;
- }
- };
-
- 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 &mid;
+ }
+
+ 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