summaryrefslogtreecommitdiff
path: root/lib/libc/include/string-file.h
blob: 16329334be59de268887aaf56715aa62af058bd8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
// Copyright 2021 The Fuchsia Authors
// Copyright (c) 2008 Travis Geiselbrecht
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT

#ifndef ZIRCON_KERNEL_LIB_LIBC_INCLUDE_STRING_FILE_H_
#define ZIRCON_KERNEL_LIB_LIBC_INCLUDE_STRING_FILE_H_

#ifdef __cplusplus
#include <stdio.h>

#include <ktl/algorithm.h>
#include <ktl/span.h>
#include <ktl/string_view.h>

// FILE* wrapper over a string.
class StringFile : public FILE {
 public:
  StringFile() = delete;
  StringFile(const StringFile &) = delete;
  StringFile operator=(const StringFile &) = delete;

  explicit StringFile(ktl::span<char> s) : FILE(this), buffer_(s) {}

  ~StringFile() = default;

  // Adds a null character at the end of the current buffer and returns a view
  // into the written section.
  ktl::span<char> take() &&;

  // Returns |str.size()| and writes as much of |str| as it would fit in the
  // buffer [offest_, size - 1) while reserving the last byte for null
  // character.
  int Write(ktl::string_view str);

  // Returns a region representing the currently used portion of the buffer.
  ktl::span<char> used_region() const {
    return (offset_ > 0) ? ktl::span<char>{buffer_.data(), offset_} : ktl::span<char>{};
  }

  // Returns a region representing the remaining unused space in the buffer,
  // _not_ including the space reserved for the final null character.
  ktl::span<char> available_region() const {
    const size_t available = ktl::max<size_t>(buffer_.size() - offset_, 1) - 1;
    return (available > 0) ? ktl::span<char>{buffer_.data() + offset_, available}
                            : ktl::span<char>{};
  }

  // Skip up to |amt| bytes in the buffer, advancing the write pointer as if we
  // had written data, but without actually changing the buffer.
  void Skip(size_t amt) {
    amt = ktl::min(amt, available_region().size());
    offset_ += amt;
  }

  // Provide two ways for users to convert the currently used buffer into a
  // string_view.  Given a string file |S|, users may say either:
  //
  // 1) S.as_string_view();   // or
  // 2) static_cast<ktl::string_view>(S);
  //
  // to perform the conversion.
  //
  ktl::string_view as_string_view() const {
    return (offset_ > 0) ? ktl::string_view{buffer_.data(), offset_} : ktl::string_view{};
  }

  explicit operator ktl::string_view() const { return this->as_string_view(); }

 private:
  ktl::span<char> buffer_;
  size_t offset_ = 0;
};

#endif  // __cplusplus

#endif  // ZIRCON_KERNEL_LIB_LIBC_INCLUDE_STRING_FILE_H_