blob: ce43dbbcb3913c02216448af69a7f1c93311aeef [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ZIRCON_SYSTEM_DEV_LIB_UART_INCLUDE_LIB_UART_CHARS_FROM_H_
#define ZIRCON_SYSTEM_DEV_LIB_UART_INCLUDE_LIB_UART_CHARS_FROM_H_
#include <zircon/assert.h>
#include <cstdint>
#include <iterator>
#include <string_view>
namespace uart {
// Container/view wrapper, turns a container or view of Char-like into a view
// (forward-iterable only) of Char. Container::value_type is converted to
// OutChar. If NewlineToCrLf is true, then '\n' elements read as '\r'
// followed by '\n'.
template <typename Container, typename OutChar = uint8_t, bool NewlineToCrLf = true>
class CharsFrom {
public:
using value_type = OutChar;
class iterator {
public:
using difference_type = ptrdiff_t;
using value_type = OutChar;
using pointer = value_type*;
using reference = value_type&;
using iterator_category = std::input_iterator_tag;
iterator() = default;
iterator(const iterator&) = default;
iterator(iterator&&) = default;
iterator& operator=(const iterator&) = default;
iterator& operator=(iterator&&) = default;
template <typename T>
explicit iterator(T&& it) : it_(std::forward<T>(it)) {}
bool operator==(const iterator& other) const {
return other.it_ == it_ && other.pending_lf_ == pending_lf_;
}
bool operator!=(const iterator& other) const { return !(*this == other); }
iterator operator++(int) { // postfix
iterator old = *this;
++*this;
return old;
}
iterator& operator++() { // prefix
if (NewlineToCrLf && !pending_lf_ && *it_ == '\n') {
// Advance past the synthesized '\r' but not past the real '\n'.
pending_lf_ = true;
} else {
if constexpr (NewlineToCrLf) {
ZX_DEBUG_ASSERT(!pending_lf_ || *it_ == '\n');
pending_lf_ = false;
}
++it_;
}
return *this;
}
value_type operator*() const {
value_type c = static_cast<value_type>(*it_);
return (NewlineToCrLf && !pending_lf_ && c == '\n') ? value_type{'\r'} : c;
}
private:
using Iterator = decltype(std::begin(std::declval<const Container&>()));
using InChar = std::decay_t<decltype(*std::declval<Iterator>())>;
static_assert(
std::is_convertible_v<InChar, value_type>,
"uart::CharsFrom applied to container with value_type not convertible to uint8_t");
Iterator it_{};
bool pending_lf_ = false;
};
using const_iterator = iterator;
explicit CharsFrom(const Container& container) : container_(container) {}
iterator begin() const { return iterator(std::begin(container_)); }
iterator end() const { return iterator(std::end(container_)); }
private:
const Container& container_;
};
} // namespace uart
#endif // ZIRCON_SYSTEM_DEV_LIB_UART_INCLUDE_LIB_UART_CHARS_FROM_H_