]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | /* |
2 | * This file is open source software, licensed to you under the terms | |
3 | * of the Apache License, Version 2.0 (the "License"). See the NOTICE file | |
4 | * distributed with this work for additional information regarding copyright | |
5 | * ownership. You may not use this file except in compliance with the License. | |
6 | * | |
7 | * You may obtain a copy of the License at | |
8 | * | |
9 | * http://www.apache.org/licenses/LICENSE-2.0 | |
10 | * | |
11 | * Unless required by applicable law or agreed to in writing, | |
12 | * software distributed under the License is distributed on an | |
13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
14 | * KIND, either express or implied. See the License for the | |
15 | * specific language governing permissions and limitations | |
16 | * under the License. | |
17 | */ | |
18 | /* | |
19 | * Copyright (C) 2014 Cloudius Systems, Ltd. | |
20 | */ | |
21 | ||
22 | #pragma once | |
23 | ||
24 | #include <seastar/core/sstring.hh> | |
25 | #include <seastar/core/temporary_buffer.hh> | |
26 | #include <seastar/util/eclipse.hh> | |
27 | #include <algorithm> | |
28 | #include <memory> | |
29 | #include <cassert> | |
30 | #include <seastar/util/std-compat.hh> | |
31 | #include <seastar/core/future.hh> | |
32 | ||
33 | namespace seastar { | |
34 | ||
35 | // Support classes for Ragel parsers | |
36 | ||
37 | // Builds an sstring that can be scattered across multiple packets. | |
38 | // | |
39 | // Use a sstring_build::guard variable to designate each scattered | |
40 | // char array, and call mark_start() and mark_end() at the start | |
41 | // and end points, respectively. sstring_builder will collect data | |
42 | // from intervening segments, if needed. | |
43 | // | |
44 | // After mark_end() has been called, use the get() method to obtain | |
45 | // the built string. | |
46 | // | |
47 | // FIXME: switch to string_view. | |
48 | // | |
49 | class sstring_builder { | |
50 | sstring _value; | |
51 | const char* _start = nullptr; | |
52 | public: | |
53 | class guard; | |
54 | public: | |
55 | sstring get() && { | |
56 | return std::move(_value); | |
57 | } | |
58 | void reset() { | |
f67539c2 | 59 | _value = {}; |
11fdf7f2 TL |
60 | _start = nullptr; |
61 | } | |
62 | friend class guard; | |
63 | }; | |
64 | ||
65 | class sstring_builder::guard { | |
66 | sstring_builder& _builder; | |
67 | const char* _block_end; | |
68 | public: | |
69 | guard(sstring_builder& builder, const char* block_start, const char* block_end) | |
70 | : _builder(builder), _block_end(block_end) { | |
71 | if (!_builder._value.empty()) { | |
72 | mark_start(block_start); | |
73 | } | |
74 | } | |
75 | ~guard() { | |
76 | if (_builder._start) { | |
77 | mark_end(_block_end); | |
78 | } | |
79 | } | |
80 | void mark_start(const char* p) { | |
81 | _builder._start = p; | |
82 | } | |
83 | void mark_end(const char* p) { | |
84 | if (_builder._value.empty()) { | |
85 | // avoid an allocation in the common case | |
86 | _builder._value = sstring(_builder._start, p); | |
87 | } else { | |
88 | _builder._value += sstring(_builder._start, p); | |
89 | } | |
90 | _builder._start = nullptr; | |
91 | } | |
92 | }; | |
93 | ||
94 | ||
95 | // CRTP | |
96 | template <typename ConcreteParser> | |
97 | class ragel_parser_base { | |
98 | protected: | |
99 | int _fsm_cs; | |
100 | std::unique_ptr<int[]> _fsm_stack = nullptr; | |
101 | int _fsm_stack_size = 0; | |
102 | int _fsm_top; | |
103 | int _fsm_act; | |
104 | char* _fsm_ts; | |
105 | char* _fsm_te; | |
106 | sstring_builder _builder; | |
107 | protected: | |
108 | void init_base() { | |
109 | _builder.reset(); | |
110 | } | |
111 | void prepush() { | |
112 | if (_fsm_top == _fsm_stack_size) { | |
113 | auto old = _fsm_stack_size; | |
114 | _fsm_stack_size = std::max(_fsm_stack_size * 2, 16); | |
115 | assert(_fsm_stack_size > old); | |
116 | std::unique_ptr<int[]> new_stack{new int[_fsm_stack_size]}; | |
117 | std::copy(_fsm_stack.get(), _fsm_stack.get() + _fsm_top, new_stack.get()); | |
118 | std::swap(_fsm_stack, new_stack); | |
119 | } | |
120 | } | |
121 | void postpop() {} | |
122 | sstring get_str() { | |
9f95a23c | 123 | return std::move(_builder).get(); |
11fdf7f2 TL |
124 | } |
125 | public: | |
f67539c2 | 126 | using unconsumed_remainder = std::optional<temporary_buffer<char>>; |
11fdf7f2 TL |
127 | future<unconsumed_remainder> operator()(temporary_buffer<char> buf) { |
128 | char* p = buf.get_write(); | |
129 | char* pe = p + buf.size(); | |
130 | char* eof = buf.empty() ? pe : nullptr; | |
131 | char* parsed = static_cast<ConcreteParser*>(this)->parse(p, pe, eof); | |
132 | if (parsed) { | |
133 | buf.trim_front(parsed - p); | |
134 | return make_ready_future<unconsumed_remainder>(std::move(buf)); | |
135 | } | |
136 | return make_ready_future<unconsumed_remainder>(); | |
137 | } | |
138 | }; | |
139 | ||
140 | } |