1 /*
2  * Copyright 2023 The Android Open Source Project
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 
17 #pragma once
18 
19 #include <cstddef>
20 
21 namespace bluetooth::log_internal {
22 
23 /// Truncating write buffer.
24 ///
25 /// This buffer can be used with `std::back_insert_iterator` to create
26 /// an output iterator. All write actions beyond the maximum length of
27 /// the buffer are silently ignored.
28 template <int buffer_size>
29 struct truncating_buffer {
30   using value_type = char;
31 
push_backtruncating_buffer32   void push_back(char c) {
33     if (len < buffer_size - 1) {
34       buffer[len++] = c;
35     }
36   }
37 
c_strtruncating_buffer38   char const* c_str() {
39     if (len == buffer_size - 1) {
40       // Inspect the last 4 bytes of the buffer to check if
41       // the last character was truncated. Remove the character
42       // entirely if that's the case.
43       for (size_t n = 0; n < 4; n++) {
44         char c = buffer[len - n - 1];
45         if ((c & 0b11000000) == 0b10000000) {
46           continue;
47         }
48         size_t char_len = (c & 0b10000000) == 0b00000000   ? 1
49                           : (c & 0b11100000) == 0b11000000 ? 2
50                           : (c & 0b11110000) == 0b11100000 ? 3
51                           : (c & 0b11111000) == 0b11110000 ? 4
52                                                            : 0;
53         if ((n + 1) < char_len) {
54           len -= n + 1;
55         }
56         break;
57       }
58     }
59 
60     buffer[len] = '\0';
61     return buffer;
62   }
63 
64  private:
65   char buffer[buffer_size];
66   size_t len{0};
67 };
68 
69 }  // namespace bluetooth::log_internal
70