brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.9 KiB · efec402 Raw
205 lines · c
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef TEST_SUPPORT_CONCAT_MACROS_H10#define TEST_SUPPORT_CONCAT_MACROS_H11 12#include <algorithm>13#include <cstdio>14#include <string>15#include <source_location>16 17#include "assert_macros.h"18#include "test_macros.h"19 20#ifndef TEST_HAS_NO_LOCALIZATION21#  include <concepts>22#  include <iterator>23#  include <sstream>24#endif25 26#if TEST_STD_VER > 1727 28#  ifndef TEST_HAS_NO_LOCALIZATION29 30[[nodiscard]] constexpr bool test_is_high_surrogate(char32_t value) { return value >= 0xd800 && value <= 0xdbff; }31 32[[nodiscard]] constexpr bool test_is_low_surrogate(char32_t value) { return value >= 0xdc00 && value <= 0xdfff; }33 34[[nodiscard]] constexpr bool test_is_surrogate(char32_t value) { return value >= 0xd800 && value <= 0xdfff; }35 36[[nodiscard]] constexpr bool test_is_code_point(char32_t value) { return value <= 0x10ffff; }37 38[[nodiscard]] constexpr bool test_is_scalar_value(char32_t value) {39  return test_is_code_point(value) && !test_is_surrogate(value);40}41 42inline constexpr char32_t test_replacement_character = U'\ufffd';43 44template <class InIt, class OutIt>45OutIt test_transcode() = delete;46 47template <class InIt, class OutIt>48  requires(std::output_iterator<OutIt, const char&> && std::same_as<std::iter_value_t<InIt>, char8_t>)49OutIt test_transcode(InIt first, InIt last, OutIt out_it) {50  return std::copy(first, last, out_it);51}52 53template <class OutIt>54  requires std::output_iterator<OutIt, const char&>55void test_encode(OutIt& out_it, char16_t value) {56  if (value < 0x80)57    *out_it++ = static_cast<char>(value);58  else if (value < 0x800) {59    *out_it++ = static_cast<char>(0b11000000 | (value >> 6));60    *out_it++ = static_cast<char>(0b10000000 | (value & 0b00111111));61  } else {62    *out_it++ = static_cast<char>(0b11100000 | (value >> 12));63    *out_it++ = static_cast<char>(0b10000000 | ((value) >> 6 & 0b00111111));64    *out_it++ = static_cast<char>(0b10000000 | (value & 0b00111111));65  }66}67 68template <class OutIt>69  requires std::output_iterator<OutIt, const char&>70void test_encode(OutIt& out_it, char32_t value) {71  if ((value & 0xffff0000) == 0)72    test_encode(out_it, static_cast<char16_t>(value));73  else {74    *out_it++ = static_cast<char>(0b11100000 | (value >> 18));75    *out_it++ = static_cast<char>(0b10000000 | ((value) >> 12 & 0b00111111));76    *out_it++ = static_cast<char>(0b10000000 | ((value) >> 6 & 0b00111111));77    *out_it++ = static_cast<char>(0b10000000 | (value & 0b00111111));78  }79}80 81template <class InIt, class OutIt>82  requires(std::output_iterator<OutIt, const char&> &&83           (std::same_as<std::iter_value_t<InIt>, char16_t>84#    ifndef TEST_HAS_NO_WIDE_CHARACTERS85            || (std::same_as<std::iter_value_t<InIt>, wchar_t> && sizeof(wchar_t) == 2)86#    endif87                ))88OutIt test_transcode(InIt first, InIt last, OutIt out_it) {89  while (first != last) {90    char32_t value = *first++;91 92    if (test_is_low_surrogate(value)) [[unlikely]] {93      test_encode(out_it, static_cast<char16_t>(test_replacement_character));94      continue;95    }96 97    if (!test_is_high_surrogate(value)) {98      test_encode(out_it, static_cast<char16_t>(value));99      continue;100    }101 102    if (first == last || !test_is_low_surrogate(static_cast<char32_t>(*first))) [[unlikely]] {103      test_encode(out_it, static_cast<char16_t>(test_replacement_character));104      continue;105    }106 107    value -= 0xd800;108    value <<= 10;109    value += static_cast<char32_t>(*first++) - 0xdc00;110    value += 0x10000;111 112    if (test_is_code_point(value)) [[likely]]113      test_encode(out_it, value);114    else115      test_encode(out_it, static_cast<char16_t>(test_replacement_character));116  }117 118  return out_it;119}120 121template <class InIt, class OutIt>122  requires(std::output_iterator<OutIt, const char&> &&123           (std::same_as<std::iter_value_t<InIt>, char32_t>124#    ifndef TEST_HAS_NO_WIDE_CHARACTERS125            || (std::same_as<std::iter_value_t<InIt>, wchar_t> && sizeof(wchar_t) == 4)126#    endif127                ))128OutIt test_transcode(InIt first, InIt last, OutIt out_it) {129  while (first != last) {130    char32_t value = *first++;131    if (test_is_code_point(value)) [[likely]]132      test_encode(out_it, value);133    else134      test_encode(out_it, static_cast<char16_t>(test_replacement_character));135  }136  return out_it;137}138 139std::ostream& operator<<(std::ostream& os, const std::source_location& loc) {140  return os << loc.file_name() << ':' << loc.line() << ':' << loc.column();141}142 143template <class T>144concept test_streamable = requires(std::stringstream& stream, T&& value) { stream << value; };145 146template <class R>147concept test_convertable_range = (!test_streamable<R> && requires(R&& value) {148  std::basic_string_view{std::begin(value), std::end(value)};149});150 151template <class T>152concept test_can_concat = test_streamable<T> || test_convertable_range<T>;153 154template <test_streamable T>155std::ostream& test_concat(std::ostream& stream, T&& value) {156  return stream << value;157}158 159template <test_convertable_range T>160std::ostream& test_concat(std::ostream& stream, T&& value) {161  auto b = std::begin(value);162  auto e = std::end(value);163  if (b != e) {164    // When T is an array it's string-literal, remove the NUL terminator.165    if constexpr (std::is_array_v<std::remove_cvref_t<T>>) {166      --e;167    }168    test_transcode(b, e, std::ostream_iterator<char>{stream});169  }170  return stream;171}172#  endif // TEST_HAS_NO_LOCALIZATION173 174// If possible concatenates message for the assertion function, else returns a175// default message. Not being able to stream is not considered an error. For176// example, streaming to std::wcerr doesn't work properly in the CI. Therefore177// the formatting tests should only stream to std::string.178//179// The macro TEST_WRITE_CONCATENATED can be used to evaluate the arguments180// lazily. This useful when using this function in combination with181// assert_macros.h.182template <class... Args>183std::string test_concat_message([[maybe_unused]] Args&&... args) {184#  ifndef TEST_HAS_NO_LOCALIZATION185  if constexpr ((test_can_concat<Args> && ...)) {186    std::stringstream sstr;187    ((test_concat(sstr, std::forward<Args>(args))), ...);188    return sstr.str();189  } else190#  endif // TEST_HAS_NO_LOCALIZATION191    return "Message discarded since it can't be streamed to std::cerr.\n";192}193 194// Writes its arguments to stderr, using the test_concat_message helper.195#  define TEST_WRITE_CONCATENATED(...) [&] { ::test_eprintf("%s", ::test_concat_message(__VA_ARGS__).c_str()); }196 197#else198 199// Fallback definition before C++20 that allows using the macro but doesn't provide a very good message.200#  define TEST_WRITE_CONCATENATED(...) [&] { ::test_eprintf("%s", TEST_STRINGIZE(__VA_ARGS__)); }201 202#endif // TEST_STD_VER > 17203 204#endif //  TEST_SUPPORT_CONCAT_MACROS_H205