| 213 | } |
| 214 | |
| 215 | FeatureView |
| 216 | Context::extract_view(const Expr &expr, std::initializer_list<ViewOption> opts) |
| 217 | { |
| 218 | FeatureView zret; |
| 219 | |
| 220 | bool commit_p = false; |
| 221 | bool cstr_p = false; |
| 222 | for (auto opt : opts) { |
| 223 | switch (opt) { |
| 224 | case EX_COMMIT: |
| 225 | commit_p = true; |
| 226 | break; |
| 227 | case EX_C_STR: |
| 228 | cstr_p = true; |
| 229 | break; |
| 230 | } |
| 231 | } |
| 232 | |
| 233 | auto f = this->extract(expr); |
| 234 | if (IndexFor(STRING) == f.index()) { |
| 235 | auto view = std::get<IndexFor(STRING)>(f); |
| 236 | if (cstr_p && !view._cstr_p) { |
| 237 | if (!view._literal_p && !view._direct_p) { // in temporary memory |
| 238 | // If there's room, just add the null terminator. |
| 239 | if (auto span = _arena->remnant().rebind<char>(); span.data() == view.data_end()) { |
| 240 | _arena->alloc(1); |
| 241 | span[0] = '\0'; |
| 242 | view._cstr_p = true; |
| 243 | } else { |
| 244 | _arena->alloc(view.size()); // commit the view data and copy. |
| 245 | view._literal_p = true; |
| 246 | } |
| 247 | } |
| 248 | // if it's still in fixed memory, need to copy and terminate. |
| 249 | if (view._literal_p) { |
| 250 | auto span = _arena->require(view.size() + 1).remnant().rebind<char>(); |
| 251 | memcpy(span, view); |
| 252 | span[view.size()] = '\0'; |
| 253 | view = TextView(span); |
| 254 | view.remove_suffix(1); // drop null from view. |
| 255 | view._cstr_p = true; |
| 256 | view._literal_p = false; |
| 257 | } |
| 258 | } |
| 259 | zret = view; |
| 260 | } else { |
| 261 | ArenaWriter w{*_arena}; |
| 262 | if (cstr_p) { |
| 263 | w.print("{}\0", f); |
| 264 | zret = TextView{w.view()}.remove_suffix(1); |
| 265 | zret._cstr_p = true; |
| 266 | } else { |
| 267 | w.print("{}", f); |
| 268 | zret = w.view(); |
| 269 | } |
| 270 | } |
| 271 | if (commit_p && !zret._literal_p && !zret._direct_p) { |
| 272 | _arena->alloc(zret.size() + (zret._cstr_p ? 1 : 0)); |