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