blob: ba628bd34cdc0c48565dbf3195b0ed34e7a44397 [file] [log] [blame]
//===-- Definition of a class for mbstate_t and conversion -----*-- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC___SUPPORT_STRING_CONVERTER_H
#define LLVM_LIBC_SRC___SUPPORT_STRING_CONVERTER_H
#include "hdr/types/char32_t.h"
#include "hdr/types/char8_t.h"
#include "hdr/types/size_t.h"
#include "src/__support/CPP/type_traits.h"
#include "src/__support/common.h"
#include "src/__support/error_or.h"
#include "src/__support/wchar/character_converter.h"
#include "src/__support/wchar/mbstate.h"
namespace LIBC_NAMESPACE_DECL {
namespace internal {
template <typename T> class StringConverter {
private:
CharacterConverter cr;
const T *src;
size_t src_len;
size_t src_idx;
// # of pops we are allowed to perform (essentially size of the dest buffer)
size_t num_to_write;
ErrorOr<size_t> pushFullCharacter() {
size_t num_pushed;
for (num_pushed = 0; !cr.isFull() && src_idx + num_pushed < src_len;
++num_pushed) {
int err = cr.push(src[src_idx + num_pushed]);
if (err != 0)
return Error(err);
}
// if we aren't able to read a full character from the source string
if (src_idx + num_pushed == src_len && !cr.isFull()) {
src_idx += num_pushed;
return Error(-1);
}
return num_pushed;
}
public:
StringConverter(const T *s, mbstate *ps, size_t dstlen,
size_t srclen = SIZE_MAX)
: cr(ps), src(s), src_len(srclen), src_idx(0), num_to_write(dstlen) {}
template <typename CharType> ErrorOr<CharType> pop() {
if (num_to_write == 0)
return Error(-1);
if (cr.isEmpty() || src_idx == 0) {
auto src_elements_read = pushFullCharacter();
if (!src_elements_read.has_value())
return Error(src_elements_read.error());
if (cr.sizeAs<CharType>() > num_to_write) {
cr.clear();
return Error(-1);
}
src_idx += src_elements_read.value();
}
ErrorOr<CharType> out = cr.pop<CharType>();
// if out isn't null terminator or an error
if (out.has_value() && out.value() == 0)
src_len = src_idx;
num_to_write--;
return out;
}
size_t getSourceIndex() { return src_idx; }
};
} // namespace internal
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC___SUPPORT_STRING_CONVERTER_H