annotate osx/include/kj/string-tree.h @ 83:ae30d91d2ffe

Replace these with versions built using an older toolset (so as to avoid ABI compatibilities when linking on Ubuntu 14.04 for packaging purposes)
author Chris Cannam
date Fri, 07 Feb 2020 11:51:13 +0000
parents 0994c39f1e94
children
rev   line source
cannam@62 1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
cannam@62 2 // Licensed under the MIT License:
cannam@62 3 //
cannam@62 4 // Permission is hereby granted, free of charge, to any person obtaining a copy
cannam@62 5 // of this software and associated documentation files (the "Software"), to deal
cannam@62 6 // in the Software without restriction, including without limitation the rights
cannam@62 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
cannam@62 8 // copies of the Software, and to permit persons to whom the Software is
cannam@62 9 // furnished to do so, subject to the following conditions:
cannam@62 10 //
cannam@62 11 // The above copyright notice and this permission notice shall be included in
cannam@62 12 // all copies or substantial portions of the Software.
cannam@62 13 //
cannam@62 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
cannam@62 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
cannam@62 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
cannam@62 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
cannam@62 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
cannam@62 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
cannam@62 20 // THE SOFTWARE.
cannam@62 21
cannam@62 22 #ifndef KJ_STRING_TREE_H_
cannam@62 23 #define KJ_STRING_TREE_H_
cannam@62 24
cannam@62 25 #if defined(__GNUC__) && !KJ_HEADER_WARNINGS
cannam@62 26 #pragma GCC system_header
cannam@62 27 #endif
cannam@62 28
cannam@62 29 #include "string.h"
cannam@62 30
cannam@62 31 namespace kj {
cannam@62 32
cannam@62 33 class StringTree {
cannam@62 34 // A long string, represented internally as a tree of strings. This data structure is like a
cannam@62 35 // String, but optimized for concatenation and iteration at the expense of seek time. The
cannam@62 36 // structure is intended to be used for building large text blobs from many small pieces, where
cannam@62 37 // repeatedly concatenating smaller strings into larger ones would waste copies. This structure
cannam@62 38 // is NOT intended for use cases requiring random access or computing substrings. For those,
cannam@62 39 // you should use a Rope, which is a much more complicated data structure.
cannam@62 40 //
cannam@62 41 // The proper way to construct a StringTree is via kj::strTree(...), which works just like
cannam@62 42 // kj::str(...) but returns a StringTree rather than a String.
cannam@62 43 //
cannam@62 44 // KJ_STRINGIFY() functions that construct large strings from many smaller strings are encouraged
cannam@62 45 // to return StringTree rather than a flat char container.
cannam@62 46
cannam@62 47 public:
cannam@62 48 inline StringTree(): size_(0) {}
cannam@62 49 inline StringTree(String&& text): size_(text.size()), text(kj::mv(text)) {}
cannam@62 50
cannam@62 51 StringTree(Array<StringTree>&& pieces, StringPtr delim);
cannam@62 52 // Build a StringTree by concatenating the given pieces, delimited by the given delimiter
cannam@62 53 // (e.g. ", ").
cannam@62 54
cannam@62 55 inline size_t size() const { return size_; }
cannam@62 56
cannam@62 57 template <typename Func>
cannam@62 58 void visit(Func&& func) const;
cannam@62 59
cannam@62 60 String flatten() const;
cannam@62 61 // Return the contents as a string.
cannam@62 62
cannam@62 63 // TODO(someday): flatten() when *this is an rvalue and when branches.size() == 0 could simply
cannam@62 64 // return `kj::mv(text)`. Requires reference qualifiers (Clang 3.3 / GCC 4.8).
cannam@62 65
cannam@62 66 void flattenTo(char* __restrict__ target) const;
cannam@62 67 // Copy the contents to the given character array. Does not add a NUL terminator.
cannam@62 68
cannam@62 69 private:
cannam@62 70 size_t size_;
cannam@62 71 String text;
cannam@62 72
cannam@62 73 struct Branch;
cannam@62 74 Array<Branch> branches; // In order.
cannam@62 75
cannam@62 76 inline void fill(char* pos, size_t branchIndex);
cannam@62 77 template <typename First, typename... Rest>
cannam@62 78 void fill(char* pos, size_t branchIndex, First&& first, Rest&&... rest);
cannam@62 79 template <typename... Rest>
cannam@62 80 void fill(char* pos, size_t branchIndex, StringTree&& first, Rest&&... rest);
cannam@62 81 template <typename... Rest>
cannam@62 82 void fill(char* pos, size_t branchIndex, Array<char>&& first, Rest&&... rest);
cannam@62 83 template <typename... Rest>
cannam@62 84 void fill(char* pos, size_t branchIndex, String&& first, Rest&&... rest);
cannam@62 85
cannam@62 86 template <typename... Params>
cannam@62 87 static StringTree concat(Params&&... params);
cannam@62 88 static StringTree&& concat(StringTree&& param) { return kj::mv(param); }
cannam@62 89
cannam@62 90 template <typename T>
cannam@62 91 static inline size_t flatSize(const T& t) { return t.size(); }
cannam@62 92 static inline size_t flatSize(String&& s) { return 0; }
cannam@62 93 static inline size_t flatSize(StringTree&& s) { return 0; }
cannam@62 94
cannam@62 95 template <typename T>
cannam@62 96 static inline size_t branchCount(const T& t) { return 0; }
cannam@62 97 static inline size_t branchCount(String&& s) { return 1; }
cannam@62 98 static inline size_t branchCount(StringTree&& s) { return 1; }
cannam@62 99
cannam@62 100 template <typename... Params>
cannam@62 101 friend StringTree strTree(Params&&... params);
cannam@62 102 };
cannam@62 103
cannam@62 104 inline StringTree&& KJ_STRINGIFY(StringTree&& tree) { return kj::mv(tree); }
cannam@62 105 inline const StringTree& KJ_STRINGIFY(const StringTree& tree) { return tree; }
cannam@62 106
cannam@62 107 inline StringTree KJ_STRINGIFY(Array<StringTree>&& trees) { return StringTree(kj::mv(trees), ""); }
cannam@62 108
cannam@62 109 template <typename... Params>
cannam@62 110 StringTree strTree(Params&&... params);
cannam@62 111 // Build a StringTree by stringifying the given parameters and concatenating the results.
cannam@62 112 // If any of the parameters stringify to StringTree rvalues, they will be incorporated as
cannam@62 113 // branches to avoid a copy.
cannam@62 114
cannam@62 115 // =======================================================================================
cannam@62 116 // Inline implementation details
cannam@62 117
cannam@62 118 namespace _ { // private
cannam@62 119
cannam@62 120 template <typename... Rest>
cannam@62 121 char* fill(char* __restrict__ target, const StringTree& first, Rest&&... rest) {
cannam@62 122 // Make str() work with stringifiers that return StringTree by patching fill().
cannam@62 123
cannam@62 124 first.flattenTo(target);
cannam@62 125 return fill(target + first.size(), kj::fwd<Rest>(rest)...);
cannam@62 126 }
cannam@62 127
cannam@62 128 template <typename T> constexpr bool isStringTree() { return false; }
cannam@62 129 template <> constexpr bool isStringTree<StringTree>() { return true; }
cannam@62 130
cannam@62 131 inline StringTree&& toStringTreeOrCharSequence(StringTree&& tree) { return kj::mv(tree); }
cannam@62 132 inline StringTree toStringTreeOrCharSequence(String&& str) { return StringTree(kj::mv(str)); }
cannam@62 133
cannam@62 134 template <typename T>
cannam@62 135 inline auto toStringTreeOrCharSequence(T&& value)
cannam@62 136 -> decltype(toCharSequence(kj::fwd<T>(value))) {
cannam@62 137 static_assert(!isStringTree<Decay<T>>(),
cannam@62 138 "When passing a StringTree into kj::strTree(), either pass it by rvalue "
cannam@62 139 "(use kj::mv(value)) or explicitly call value.flatten() to make a copy.");
cannam@62 140
cannam@62 141 return toCharSequence(kj::fwd<T>(value));
cannam@62 142 }
cannam@62 143
cannam@62 144 } // namespace _ (private)
cannam@62 145
cannam@62 146 struct StringTree::Branch {
cannam@62 147 size_t index;
cannam@62 148 // Index in `text` where this branch should be inserted.
cannam@62 149
cannam@62 150 StringTree content;
cannam@62 151 };
cannam@62 152
cannam@62 153 template <typename Func>
cannam@62 154 void StringTree::visit(Func&& func) const {
cannam@62 155 size_t pos = 0;
cannam@62 156 for (auto& branch: branches) {
cannam@62 157 if (branch.index > pos) {
cannam@62 158 func(text.slice(pos, branch.index));
cannam@62 159 pos = branch.index;
cannam@62 160 }
cannam@62 161 branch.content.visit(func);
cannam@62 162 }
cannam@62 163 if (text.size() > pos) {
cannam@62 164 func(text.slice(pos, text.size()));
cannam@62 165 }
cannam@62 166 }
cannam@62 167
cannam@62 168 inline void StringTree::fill(char* pos, size_t branchIndex) {
cannam@62 169 KJ_IREQUIRE(pos == text.end() && branchIndex == branches.size(),
cannam@62 170 kj::str(text.end() - pos, ' ', branches.size() - branchIndex).cStr());
cannam@62 171 }
cannam@62 172
cannam@62 173 template <typename First, typename... Rest>
cannam@62 174 void StringTree::fill(char* pos, size_t branchIndex, First&& first, Rest&&... rest) {
cannam@62 175 pos = _::fill(pos, kj::fwd<First>(first));
cannam@62 176 fill(pos, branchIndex, kj::fwd<Rest>(rest)...);
cannam@62 177 }
cannam@62 178
cannam@62 179 template <typename... Rest>
cannam@62 180 void StringTree::fill(char* pos, size_t branchIndex, StringTree&& first, Rest&&... rest) {
cannam@62 181 branches[branchIndex].index = pos - text.begin();
cannam@62 182 branches[branchIndex].content = kj::mv(first);
cannam@62 183 fill(pos, branchIndex + 1, kj::fwd<Rest>(rest)...);
cannam@62 184 }
cannam@62 185
cannam@62 186 template <typename... Rest>
cannam@62 187 void StringTree::fill(char* pos, size_t branchIndex, String&& first, Rest&&... rest) {
cannam@62 188 branches[branchIndex].index = pos - text.begin();
cannam@62 189 branches[branchIndex].content = StringTree(kj::mv(first));
cannam@62 190 fill(pos, branchIndex + 1, kj::fwd<Rest>(rest)...);
cannam@62 191 }
cannam@62 192
cannam@62 193 template <typename... Params>
cannam@62 194 StringTree StringTree::concat(Params&&... params) {
cannam@62 195 StringTree result;
cannam@62 196 result.size_ = _::sum({params.size()...});
cannam@62 197 result.text = heapString(
cannam@62 198 _::sum({StringTree::flatSize(kj::fwd<Params>(params))...}));
cannam@62 199 result.branches = heapArray<StringTree::Branch>(
cannam@62 200 _::sum({StringTree::branchCount(kj::fwd<Params>(params))...}));
cannam@62 201 result.fill(result.text.begin(), 0, kj::fwd<Params>(params)...);
cannam@62 202 return result;
cannam@62 203 }
cannam@62 204
cannam@62 205 template <typename... Params>
cannam@62 206 StringTree strTree(Params&&... params) {
cannam@62 207 return StringTree::concat(_::toStringTreeOrCharSequence(kj::fwd<Params>(params))...);
cannam@62 208 }
cannam@62 209
cannam@62 210 } // namespace kj
cannam@62 211
cannam@62 212 #endif // KJ_STRING_TREE_H_