1 | /* |
2 | * Copyright 2016-present Facebook, Inc. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | // Copyright 2004-present Facebook. All Rights Reserved. |
17 | #pragma once |
18 | |
19 | namespace folly { |
20 | namespace io { |
21 | namespace detail { |
22 | |
23 | /* |
24 | * Helper classes for use with CursorBase::readWhile() |
25 | */ |
26 | class CursorStringAppender { |
27 | public: |
28 | void append(ByteRange bytes) { |
29 | str_.append(reinterpret_cast<char const*>(bytes.data()), bytes.size()); |
30 | } |
31 | std::string () { |
32 | return std::move(str_); |
33 | } |
34 | |
35 | private: |
36 | std::string str_; |
37 | }; |
38 | |
39 | class CursorNoopAppender { |
40 | public: |
41 | void append(ByteRange) {} |
42 | }; |
43 | |
44 | template <class Derived, class BufType> |
45 | std::string CursorBase<Derived, BufType>::readTerminatedString( |
46 | char termChar, |
47 | size_t maxLength) { |
48 | size_t bytesRead{0}; |
49 | auto keepReading = [&bytesRead, termChar, maxLength](uint8_t byte) { |
50 | if (byte == termChar) { |
51 | return false; |
52 | } |
53 | ++bytesRead; |
54 | if (bytesRead >= maxLength) { |
55 | throw std::length_error("string overflow" ); |
56 | } |
57 | return true; |
58 | }; |
59 | |
60 | auto result = readWhile(keepReading); |
61 | // skip over the terminator character |
62 | if (isAtEnd()) { |
63 | throw_exception<std::out_of_range>("terminator not found" ); |
64 | } |
65 | skip(1); |
66 | |
67 | return result; |
68 | } |
69 | |
70 | template <class Derived, class BufType> |
71 | template <typename Predicate> |
72 | std::string CursorBase<Derived, BufType>::readWhile( |
73 | const Predicate& predicate) { |
74 | CursorStringAppender s; |
75 | readWhile(predicate, s); |
76 | return s.extractString(); |
77 | } |
78 | |
79 | template <class Derived, class BufType> |
80 | template <typename Predicate, typename Output> |
81 | void CursorBase<Derived, BufType>::readWhile( |
82 | const Predicate& predicate, |
83 | Output& out) { |
84 | while (true) { |
85 | auto peeked = peekBytes(); |
86 | if (peeked.empty()) { |
87 | return; |
88 | } |
89 | for (size_t idx = 0; idx < peeked.size(); ++idx) { |
90 | if (!predicate(peeked[idx])) { |
91 | peeked.reset(peeked.data(), idx); |
92 | out.append(peeked); |
93 | skip(idx); |
94 | return; |
95 | } |
96 | } |
97 | out.append(peeked); |
98 | skip(peeked.size()); |
99 | } |
100 | } |
101 | |
102 | template <class Derived, class BufType> |
103 | template <typename Predicate> |
104 | void CursorBase<Derived, BufType>::skipWhile(const Predicate& predicate) { |
105 | CursorNoopAppender appender; |
106 | readWhile(predicate, appender); |
107 | } |
108 | } // namespace detail |
109 | } // namespace io |
110 | } // namespace folly |
111 | |