blob: bfe362becad1e0eff2d0ad290ffe87244d75c41a [file] [log] [blame]
//===-- Core Structures for printf ------------------------------*- 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_STDIO_PRINTF_CORE_CORE_STRUCTS_H
#define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_CORE_STRUCTS_H
#include "src/__support/macros/config.h"
#include "src/__support/CPP/string_view.h"
#include "src/__support/CPP/type_traits.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/stdio/printf_core/printf_config.h"
#include <inttypes.h>
#include <stddef.h>
namespace LIBC_NAMESPACE {
namespace printf_core {
// These length modifiers match the length modifiers in the format string, which
// is why they are formatted differently from the rest of the file.
enum class LengthModifier { hh, h, l, ll, j, z, t, L, w, wf, none };
struct LengthSpec {
LengthModifier lm;
size_t bit_width;
};
enum FormatFlags : uint8_t {
LEFT_JUSTIFIED = 0x01, // -
FORCE_SIGN = 0x02, // +
SPACE_PREFIX = 0x04, // space
ALTERNATE_FORM = 0x08, // #
LEADING_ZEROES = 0x10, // 0
// These flags come from the GNU extensions which aren't yet implemented.
// group_decimals = 0x20, // '
// locale_digits = 0x40, // I
};
struct FormatSection {
bool has_conv;
cpp::string_view raw_string;
// Format Specifier Values
FormatFlags flags = FormatFlags(0);
LengthModifier length_modifier = LengthModifier::none;
size_t bit_width = 0;
int min_width = 0;
int precision = -1;
// Needs to be large enough to hold a long double.
fputil::FPBits<long double>::StorageType conv_val_raw;
void *conv_val_ptr;
char conv_name;
// This operator is only used for testing and should be automatically
// optimized out for release builds.
LIBC_INLINE bool operator==(const FormatSection &other) const {
if (has_conv != other.has_conv)
return false;
if (raw_string != other.raw_string)
return false;
if (has_conv) {
if (!((static_cast<uint8_t>(flags) ==
static_cast<uint8_t>(other.flags)) &&
(min_width == other.min_width) && (precision == other.precision) &&
(bit_width == other.bit_width) &&
(length_modifier == other.length_modifier) &&
(conv_name == other.conv_name)))
return false;
if (conv_name == 'p' || conv_name == 'n' || conv_name == 's')
return (conv_val_ptr == other.conv_val_ptr);
else if (conv_name != '%')
return (conv_val_raw == other.conv_val_raw);
}
return true;
}
};
enum PrimaryType : uint8_t {
Unknown = 0,
Float = 1,
Pointer = 2,
Integer = 3,
FixedPoint = 4,
};
// TypeDesc stores the information about a type that is relevant to printf in
// a relatively compact manner.
struct TypeDesc {
uint8_t size;
PrimaryType primary_type;
LIBC_INLINE constexpr bool operator==(const TypeDesc &other) const {
return (size == other.size) && (primary_type == other.primary_type);
}
};
template <typename T> LIBC_INLINE constexpr TypeDesc type_desc_from_type() {
if constexpr (cpp::is_same_v<T, void>) {
return TypeDesc{0, PrimaryType::Unknown};
} else {
constexpr bool IS_POINTER = cpp::is_pointer_v<T>;
constexpr bool IS_FLOAT = cpp::is_floating_point_v<T>;
#ifdef LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT
constexpr bool IS_FIXED_POINT = cpp::is_fixed_point_v<T>;
#else
constexpr bool IS_FIXED_POINT = false;
#endif // LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT
return TypeDesc{sizeof(T), IS_POINTER ? PrimaryType::Pointer
: IS_FLOAT ? PrimaryType::Float
: IS_FIXED_POINT ? PrimaryType::FixedPoint
: PrimaryType::Integer};
}
}
// This is the value to be returned by conversions when no error has occurred.
constexpr int WRITE_OK = 0;
// These are the printf return values for when an error has occurred. They are
// all negative, and should be distinct.
constexpr int FILE_WRITE_ERROR = -1;
constexpr int FILE_STATUS_ERROR = -2;
constexpr int NULLPTR_WRITE_ERROR = -3;
constexpr int INT_CONVERSION_ERROR = -4;
constexpr int FIXED_POINT_CONVERSION_ERROR = -5;
} // namespace printf_core
} // namespace LIBC_NAMESPACE
#endif // LLVM_LIBC_SRC_STDIO_PRINTF_CORE_CORE_STRUCTS_H