Return if we handle any error messages to avoid unnecessarily calling recv/send
[folly.git] / folly / io / Cursor-inl.h
1 /*
2  * Copyright 2017 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 extractString() {
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     std::__throw_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