Как стать автором
Обновить
-17
@twinklederead⁠-⁠only

Пользователь

Отправить сообщение
Но я не могу согласиться с тем, что этого не должно быть в каком-то виде в качестве оптимизации. Так как мы живём в мире С++ и у нас мегатонны легаси кода, который уже переписывать никто не будет.

Я согласен с ораторами выше. Лучше туда не лезть. Кто там знает чего туда напихано. Но в какой-то мере это имеет место быть, с этим я так же согласен.

Просто на данный момент компиляторы и так делают очень много «грязной» работы по оптимизации, и реализовано это всё очень и очень ужасно (стоит хотя бы взглянуть на InstCombine в LLVM и его аналог у GCC — не знаю как для Вас, а для меня это вырвиглазно).

Я знаком с clang на достаточно базовом уровне и мой опыт заканчивается на портировании пары наработок на новую версию шланга и написания примитивного кодогена на libtooling. С llvm ещё меньше.

Но в целом я согласен да, существует множество вещей которые проще реализовать на уровне хайлевел оптимизаций. А ещё лучше мочь ими управлять.

Касательно движения С++… Мне сложно сказать, двигается ли С++ сейчас в правильном направлении. Я лично больше всего жду нормальной compile-time рефлексии с поддержкой атрибутов (на данный момент атрибуты не поддерживаются — можно это подсмотреть в докладе David Sankel c CppNow 2019).

А я хочу смерти атрибутам. Это рудимент gcc и что-то «снизу». Нужно заменить их на нормальные аннотации aka java.

Ну и С++ нужно взять пример со всяких модных языков. Необходима некая экспериментальная ветка, которая существует вне стандарта и на которой будут обкатываться новшества, которая будет популяризировать С++ и быстро реагировать на запросы комьюнити/обратную связь.

Сейчас мы имеем то, что почти никто не знает о тысячах наработках. Обычные люди не будут читать патчи на стандарт и строгие формулировки. И искать форки компиляторов в интернете.

А Вы случаем не знаете, где эта оптимизация реализована в GCC или LLVM? Я сходу не смог найти, в какой момент они занимаются схлопыванием аллокаций.

Нет, не интересовался. Но предположить можно. В С++ семантически определены аллокаторы, в си они есть на уровне libc и их можно определять по именам. В так же есть [[gnu::malloc/alloc_size]]. Т.е. компилятор знает где malloc, а где free. И даже знает какая длинна у аллоцируемой памяти.

Далее работают базовые оптимизации. Т.е. если компилятор не найдёт побочных эффектов вызова функции, то он спокойно может её убирать. Функции у нас внешние и узнать что в них происходит мы не можем. Для решения этих проблем уже давно существуют всякие [[gnu::pure/const]].

Получается, что компилятор точно знает значение переменной на всём протяжении программы(скоупа). Даже если он его не знает, то он знает изменяется он или нет.

Соответственно, инвариант тут простой. Если выход из маллока приходит во free в первоначальном виде, то free не имеет эффекта. На malloc можно просто повесить [[gnu::pure]], а free реализовать как: godbolt.org/z/BBpOVP

В данном случае компилятор знает, что функция не может вернуть null и проверка не срабатывает. Скорее всего подобные(допустим там хранить оригинальное значение или что-то типа того) хинты есть для внутреннего представления компилятора.

gcc умеет дампить ir. Я сейчас не могу посмотреть(как это сделать на godbolt я не нашел). Если успею посмотреть — поищу как там сделано.

На самом деле мне не нравится текущий подход к оптимизации в Clang/LLVM в плане того, что все (подавляющее большинство согласно ответу в clang-dev mailing list) оптимизации проводятся на уровне LLVM IR (я не знаю, как оно сделано в GCC — мне не нравится читать их исходники). Потому что при переходе на LLVM IR по моему мнению мы теряем достаточно много информации, которую могли бы использовать для оптимизации — LLVM IR слишком низкоуровневый. Можно выкручиваться путём прокидывания (аннотирования) IR с фронтенда, чтобы мидленд уже обладал бОльшим кол-вом информации. Но это выглядит ужасно. На мой взгляд это не совсем эффективно.

Полностью согласен. Да и компиляторы уже давно выносят на уровень языка ручки. Но этого мало. Программисты и языки(С++) уже дозрели до управления оптимизациями, компиляцией.

К тому же, тут есть и другая проблема. Если мы уберём ir, то куда пойдут всякие свифты/расты?

По поводу сравнения оптимизаторов LLVM vs GCC. Согласно тестам того же Phoronix, оптимизатор LLVM не так уж и плох, так что я не могу согласиться, что там так уж всё плохо и что это всё «пыль в глаза».

Там тесты говно. У llvm очень плохой кодоген и всякие фундаментальные оптимизации. За примерами далеко ходить ненужно — в соседнем посте парсер json«а на llvm работает почти в 2раза медленнее.

В llvm есть свои преимущества — там больше всякие хайлевел реплейс-оптимизаций и более агрессивная дефолтная настройка. Там глубина анализа циклов больше. Больше анроллинга.

gcc более универсальный код генерирует. Ну и в контексте С++ у него намного выше скорость компиляции. Хотя clang начинал хайпиться как „собирает быстрее“. Сейчас в gcc завезли модное раздельное lto и собранный с ним гцц стал ещё быстрее.

Первая проблема заключается в том, что для анализатора на данный момент все ветки кода равновероятностные. Точнее, он даже не знает о такой вещи как разные ветки выполнения кода.
Это выливается в проблемы с анализом для примерно вот такого кода:

Уже есть поддержка likely/unlikely. На это и прочее есть только один адекватный ответ — язык.

Осталось только научить язык в constexpr/eval-контексте получать мета-информацию. Какие методы используются в контексте функции и прочее, на базовом уровне. Нужна поддержка получения окружения для объекта. Нужны MUTexptr/eval. Нужно локализовать компилтайм-контекст:

godbolt.org/z/EQnbPF

Всё это уже работает сейчас, и компилятор знает, что там >= 42. Нужно просто это принести на уровень языка. Случае, если кол-во вызовов неизвестно — можно ввести флаг аналогичный std::is_constant_evaluated()

Будет сборка статистики, будут рефлексия, будут метаклассы, будут интерфейсы. Всё это позволит использовать один интерфейс. А далее оптимальный контейнер будет генерироваться автоматически исходя из контекста. Далее мы заменим мусорные функции и убогий inline чем-то на вроде «parametric expressions» и получим расширение анализа на халяву.

Подобные механизмы универсальны и позволят делать множество всего. Это очень большая проблема С++, да и не только. Заниматься параллельно тысячей разных костылей и решать под капотом сложные задачи. И с т.з. каждого участника это кажется выгодным «сделаю нужную мне фишку без лишней сложности», но суммарно трудозатраты получаются куда большие.

Вместо добавления рефлексии и расширения шаблонов — костыль на костыле. parameter pack у нас не объект, а какой-то неведомый треш. Вместо pack.size() у нас очередной костыль sizeof...(), костыли вида std::get<0>(std::tie(...args)). А какие приключения с откусыванием начала/конца. Постоянно переизобретаются очередные for… и прочая невиданная хрень. if constexpr, потом будет for/switch и прочее.

Приоритеты в комьюнити просто неадекватные. Мы делаем модули и боремся с макросами, но условной компиляции нет, вообще. На __LINE__ всё остановилось и то засунули «в ящик».

Сейчас какой-то тренд намечается на решение фундаментальных проблем. Контракты, концепты, улучшение шаблонных параметров. Я не считаю правильным отходить от этого тренда.

В связи с этим я считаю, что реализация как анализ и советы уровня «вы неправильно используете std::list замените на vector» и прочее — это вполне себе годно и имеет смысл. Реализовывать же именно как оптимизации — смысла имеет мало, ведь адекватная реализация требует наличия тех фишек, которых в С++ нет.

Поэтому ключевым, как я считаю, в решении этой проблемы является добавление этих фишек в С++, а уже потом оптимизации. Это будет либо очень слабо, либо будут переизобретаться в кишках очередные подобия тех фишек, что должны существовать в С++.
Не понимаю, что значит оптимизация «для галочки».

Всё очень просто. Добавлять бесполезные оптимизации для использования их в последующей конкурентной борьбе. Уровень этой борьбы может быть разный. На уровне авторов реализовавших оптимизацию, либо на уровне оптимизаций.

По поводу самой оптимизации. Я посмотрел — и тот и тот компилятор умеет убирать malloc/free, шланг умеет убирать и из вектора(нужен libc++). Почему не убирает из libstdc++ — напишу ниже.

По поводу гцц — он так же умеет всё удалять. Но он не игнорирует исключения из op new. Это починить несложно, но этого почему-то никто не сделал и предположить причину так же несложно.

В векторе из stdlibc++ есть проверка на null. Из-за это проверки оптимизатор не может связать выход malloc co входом free.

Аналогично, тут видна фундаментальная разница между gcc(действительно сильным оптимизатором) и clang(больше пыли в глаза). Я написал код, который обходит проверку и clang видит её — он убрал if, но он не смог связать выход malloc co входом free. О таких мелочах как замена malloc + memset(0) на calloc я и не говорю.

Т.е. на самом деле оптимизации давно есть и в gcc и они лучше. Если стандарт разрешил игнорировать исключение из new, то гцц просто его не игнорирует. Это не значит что оптимизации нет.

godbolt.org/z/6G5uVj
Ну это просто оптимизация «для галочки» и упоминать её не имеет смысла. И там и там op new, правда всё это сворачивает llvm и в этом проблема. Нужна некая обратная связь, в противном случае все эти оптимизации имеют мало смысла.
Всему виной то, что на данный момент только один С++ компилятор реализует оптимизацию по удалению динамических аллокаций — Clang.

Что-то у меня не получается добиться этого даже для самого примитивного случая: godbolt.org/z/iozO7C
А смысл иметь тысячу нитей

Я не говорил о каких-то «нитях». Про нити там:

рассылать по потокам

Всё что дальше — к потокам отношения не имеет, а имеет отношение к «их».

Отвечу сразу на:
В чем заключался оверхед?

Это уже обсуждалось. Там ниже есть бенчмарки С++-версии и раст-версии и оверхед там очевиден(там же обсуждался оверхед с red75prim). Многопоточная раст-версия работает на одном потоке намного медленнее однопоточной — это и есть оверхед.

Для понимания темы я советую взять и написать аналог моего бенчмарка и сравнить результаты. Он читает файл, берёт ваш алгоритм по выделению из строки объектов и делит строку на подстроки(вот они тут: github.com/epishman/habr_samples/blob/master/jsonparse/main.rs#L187). Далее он посылает эти подстроки в воркеры(которые потоки).

В рамках бенчмарка воркер не просто считает длину этой подстроки и складывает внутри себя. Далее бенчмарк выводит суммарной кол-во байт «переданное» в каждый воркер(это показанные мною 1/4 цифры).

github.com/epishman/habr_samples/blob/master/jsonparse/main.rs#L284 — вот то место, у вас там o является подстрокой. Нужно взять и сложить все длинны входящих слайсов для каждого элемента массива: github.com/epishman/habr_samples/blob/master/jsonparse/main.rs#L141

Я потом попробовал наивно распараллелить — получилось медленнее (~770ms), оверхед на рантайм высокий (в основном это блокировки и шедулинг горутин), ну и сложность решения выше даже при наивном подходе.

Сложно как-то у вас всё.

Я на базе С++-версии написал такой бенчмарк
//https://github.com/jarro2783/cxxopts.git
//https://github.com/cameron314/concurrentqueue.git
#include <filesystem>
#include <sys/mman.h>
#include <fcntl.h>
#include <string>
#include <vector>
#include <boost/algorithm/string/join.hpp>
#include <algorithm>
#include <cxxopts.hpp>
#include <concurrentqueue/concurrentqueue.h>
#include <future>


moodycamel::ConcurrentQueue<std::string_view> q;

struct config {
  static inline size_t bulk = 128;
  static inline size_t concurrency = std::min(4u, std::thread::hardware_concurrency());
};

auto work() {
  std::vector<std::string_view> pool(config::bulk);
  size_t size = 0;
  
  for(bool end_flag = false; !end_flag;) {
    auto n = q.try_dequeue_bulk(begin(pool), config::bulk);
    for(size_t it = 0; it < n; ++it) {
      auto & str = pool[it];
      if((end_flag = str.empty())) continue;
      size += str.size();
    }
    
    if(end_flag) q.enqueue({});
  }
  return size;
}


auto parse(int argc, char* argv[]) {
  cxxopts::Options options{*argv};
  options.add_options()
    ("b", "", cxxopts::value(config::bulk))
    ("c", "threads", cxxopts::value(config::concurrency))
    ("f", "file path", cxxopts::value<std::string>());
  auto pr = options.parse(argc, argv);
  if(pr.count("f") == 1) return pr["f"].as<std::string>();
  printf("%s\n", options.help().c_str());
  exit(0);
}


int main(int argc, char * argv[]) {
  std::filesystem::path path = parse(argc, argv);
  auto file_size = std::filesystem::file_size(path);
  auto file_data = (const char *)mmap(nullptr, file_size + 4096, PROT_READ, MAP_POPULATE|MAP_PRIVATE|MAP_FILE, open(path.c_str(), O_RDONLY), 0);
  std::string_view file{file_data, file_size};
    
  auto next = [it = file]() mutable {
    auto p = it.data();
    const char * begin = nullptr;
    size_t braces = 0;
    while(true) {
      switch(p = strpbrk(p, "{}"); p ? *p : 0) {
        case '{': if(!braces++) begin = p; ++p; break;
        case '}': ++p; if(!--braces) {
          it = it.substr(size_t(p - it.begin()));
          return std::string_view{begin, size_t(p - begin)};
        } break;
        default: it = it.substr(it.size()); return std::string_view{};
      }
    };
  };
  
  std::vector<std::future<size_t>> tp(config::concurrency);
  for(auto & f: tp) f = std::async(std::launch::async, work);
  
  std::vector<std::string_view> pool;
  auto max = config::bulk * config::concurrency;
  pool.reserve(max);
  while(true) {
    auto str = next();
    if(pool.size() == max || str.empty()) {
      q.enqueue_bulk(begin(pool), pool.size());
      pool.clear();
    }
    if(str.empty()) {
      q.enqueue({});
      break;
    }
    pool.emplace_back(str);    
  }
  std::vector<std::string> all;
  std::transform(begin(tp), end(tp), std::back_inserter(all), [](auto & f) {
    return std::to_string(f.get());
  });
  assert(all.size() == config::concurrency);
  fprintf(stderr, "{%s}\n", boost::algorithm::join(all, ", ").c_str());
  
}



Оно парсит(при помощи алгоритма автора) на подстроки и раскидывает подстроки по потокам.

//1 поток(на самом деле 2)
{93000000}
real 0m0,041s
user 0m0,054s
sys 0m0,012s
//4 потока(на самом деле 5)
{23247900, 23247942, 23256193, 23247965}
real 0m0,042s
user 0m0,140s
sys 0m0,010s


Там лям объектов объектов. Их без проблем можно рассылать по потокам по тысячи штук, а это всего тысяча операций. Это ничто даже для системных механизмов синхронизации, не говоря уже о юзерспейсных.

Я распараллеливал на расте вполне успешно, выигрыш как ожидалось в разы, только накосячил немного при слиянии результата.

Распараллеливание на расте было крайне неуспешным в связи с неадекватным оверхедом на само распараллеливание.
real 0m0,533s
user 0m0,519s
sys 0m0,014s

//C++
real 0m0,536s
user 0m0,496s
sys 0m0,040s

//C++ + pgo
real 0m0,462s
user 0m0,423s
sys 0m0,039s

Т.е. оно эквивалентно С++-версии.

если парсить потоково и сразу агрегировать, то получается быстро.

А если ещё и json(текст) убогий выпилить.
Ну-ну, т. е. паскалёвых и подобных строк не существует. И понятие строки из различных представлений ASN.1.

Попытка подменять понятия. Я говорил именно про данные, к паскаль/си-строке это не имеет никакого отношения.

Я уж не стал цепляться к ваши примерам с hb. Но я вам подскажу. Именно то, что openssl следовал вашей логике и получился hb. Именно потому, что openssl пытался не отделял транспорт от транспортируемого и вышла подобная ситуация. Как и ваш другой пример был глуп.

Никогда адекватный транспорт не должен вообще смотреть на транспортируемое и никак с ним взаимодействовать. Именно тогда, и только тогда, никаких проблем не будет. Задача интерпретации/валидации данных — это задача той логики, которая как-то работает с этими данными.

Строка, как транспорт, с ними не работает и её абсолютно не должно волновать какие в ней лежат данные. Если вы хотите валидировать данные — их нужно валидировать на входе. Строка этим входом не является.

У меня сложилось впечатление, что Вы не осознаёте, что в различных контекстах понятие строки может быть различное.

Вы это не мне пишите, а тем, кто утверждал «строки — это наши строки с utf8, а всё остальное мусор». Для меня строка — некий транспорт для данных. Транспорту абсолютно без разницы что там внутри него.

Где-то это просто byte array + lenght

Это описание транспорта.

где-то с требованием валидного UTF-16 в native endianness, где-то null terminated byte array, где-то byte array с указателем на объект encoder'а и decoder'а. И всё это строки.

Вы должны спорить не со мною. С чем именно вы спорите? С моим тезисом «транспорт не должно интересовать транспортируемое»? Я не считаю обратное осмысленным. Вы можете с этим поспорить.

Ссылки на «я считаю, что можно и валидировать» не являются аргументом. Вы должны объяснить «зачем». Зачем делать что-то, что предлагаете делать.

Сравнивать стоит всё-таки сопоставимые вещи, о чём Вам здесь не раз сказали.

Я что-то не вижу вашей критики под «я сравниваю многопоточное/однопоточное», «я сравниваю sax/dom»? Зачем вы это пишите мне?

Кто вам не даёт убрать ненужную здесь валидацию? Это не моя проблема, что вы её не убрали. И это не было темой обсуждения. Вы опять врёте.

Темой обсуждение было «мы не убрали потому что убирать неправильно» — ваша задача обосновать почему. Зачем вы пытаетесь подменить контекст?

Сравнивать реализацию с валидацией входного потока и без,

Во-первых вы опять врёте, т.к. валидация в моём коде есть. Во-вторых, как я уже говорил, наличие валидации у вас — ваша проблемы. Она не ставилась как требование автора, а значит она ненужна. Вы должны обосновать её наличие. Если вы пытаетесь утверждать, что моя реализация неверня или что-то тому подобное.

К тому же, вас никак это не спасёт. Даже если я буду строку хоть 10 раз валидировать.

да потом заявлять что реализация без валидации выше/лучше/быстрее выглядит как какой-то маразм.

Опять враньё про отсутствие валидации. Опять враньё про причину проигрыша. Причина не в валидации. Повторюсь, кто вам мешал её убрать? Она была в требованиях автора? Нет. У вас она есть? Да. У вас с нею проблемы? Уберите её.

И цепляться после этого к тому что в другом языке и/или стандартной библиотеке под строкой могут понимать что-то другое — тоже.

Опять враньё. Почему каждый ваш тезис — враньё? Цеплялись вы. Вы начали оправдываться, вы начали утверждать, что строки только utf8 и всё остальное мусор.

С чего вдруг я должен идти на поводу у ограничения какого-либо пхп и заниматься какой-то ненужностью? Это ваша проблема, а не моя.

К тому же, где критика моих оппонентов которые действительно сравнивали несравнимой? Какая-то у вас однобокая справедливость получается. Почему та происходит?

После того, каким «сравнением несравнимого» поклонники очередного пхп пытались выиграть мой код — я могу говорить что угодно. Я не собираюсь играть по правилам, которые нарушаете вы. Вы их нарушили множество раз. После этого все обвинения меня не имеют смысла.

К тому же даже ваши обвинения ложны.

Спасибо за ваше квалифицированное мнение.

Ну кому-то же надо его иметь.

Некоторые писатели парсеров ASN.1 тоже заявляли подобное, потом можно было спокойно выпускать сертификат на "*.google.com\0.my-evil-domain.ru" и браузеры его прекрасно интерпретировали как google.com.

Какая-то чушь. Оно так интерпретируется именно потому, что интерпретируется «правильно». А вот если бы это был «массив байт», то никогда такого бы не произошло. Это очевидно.

куча других не менее прелестных CVE где причиной стало то, что разработчики не обращают внимания на то что в разных контекстах строка может быть не просто char * или uint8_t * с null-termination, но и чем-то другим.

Больше базвордов, больше отсылок на фентейзиные cve.

Ваши рассуждений сломались так и не начавшись. Изначально речь шла о «всё что не utf8 — мусор». Теперь вдруг риторика поменялась и началось какое-то char, null и прочие не относящиеся к теме рассуждения.

Другой хороший пример, что «транспорт валидировать не надо» назывался heartbleed. Помните такой?

Такая же глупость. heartbleed вообще никак не связан с темой. Это глупая попытка выдернуть фразу, интерпретировать как угодно. Очевидно, что под транспортом имелось ввиду «транспортируемые данные».
Если так хочется сравнивать использовать в rust'е, например, «строки» не с utf8

И опять враньё. Строк не с utf8 нету. Это всё мусор. Зачем мне использовать мусор?

К тому же, вы сейчас умножили на ноль все предыдущие рассуждений. Если это делать можно, то зачем все эти рассуждения про cve/hb? Пустить пыль в глаза?

Все эти рассуждения имеют единственную предпосылку «у вас можно сделать неправильно». Если неправильно можно сделать везде, то смысла в этих рассуждениях нет.

никто не мешает использовать срезы байт (&[u8]), которые эффективно являются указателем + длинной как и плюсовый string_view или какую-нибудь OsString, который имеет более слабые инварианты на содержимое нижележащего массива байт.

К эффективности rust не имеет никакого отношения. По поводу «можно» — это такая же глупость.

Меня не должно волновать слово «можно», меня должно волновать слово «как». Можно и черепом гвозди забивать, но я так делать не буду.

Определяющим является не то, что там можно через какое-то одно место(и то, можно только номинально). А то, насколько всё это прозрачно и удобно происходит.

Всё ещё не требует валидации?

Я уже отвечал на это и на тысячи подобных вопросов. Я до сих пор не понял зачем вы говорите о какой-то валидации. Зачем она нужна? Какой в ней смысл? Делать два раза одну и туже работу?

Есть ли в utf16 «неправильные» последовательности, либо нет — так же неважно. utf16 лишь пример, которую я перепутал с ucs-2, а даже если бы не перепутал — это так же ничего не меняет.

Факт остаётся фактом — строка является транспортом для данных. Никакой транспорт валидировать ненужно и это не имеет смысла.

Аналогично и с utf8. Строка не с utf8 не становится мусором, как утверждалось выше. И даже если мы примем какую-то необходимость валидации строки, то не все форматы кодирования избыточны.
Нет, это так не работает. Вас поможет не это, а основания(верифицируемые) для признания байта «222» невалидным.

Хотя даже этого ненужно. Кто вас вообще сказал, что какой-то там байт вообще какой-то символ? Это, как я уже говорил, так не работает. Семибитную «кодировку» вообще не должно волновать то, что там лежит слева, сбоку и в каких-то левых битах.

Причина тому проста. Если у нас там 0, то чем это отличается от 1? Где именно ascii предписывает(даже в древнем rfc 0 там только рекомендация. К тому же это именно битовый формат, а не таблица. И тут, опять же, ненужно путать), что в каких-то других битах должен быть ноль? Почему не 1?

Именно поэтому подобные рассуждения опять сводятся к непониманию темы. Какая-то кодировка является лишь интерпретацией каких-то битов. Никаких интерпретаций других битов — она не даёт. Поэтому она могут быть какими угодно. В этом её свойство.

utf8(и тот же 16) — это не таблица, а формат кодирования. Именно в нём формализовано то, что является ошибкой, а что не является. Прям на уровне битов и прям всех байтов.

Таблица же определяет лишь соответствия уровня число->символ. Она нигде не определяет форматы чисел, какие и где там могут быть записаны числа. Сколько их должно быть и какой они должны быть ширины.

И самое главное, и об этом я уже говорил. Никто и нигде не накладывает ограничений на канальный уровень. Никто и нигде не накладывает ограничений на вход в декодер. Именно поэтому такого понятия как «валидация» вообще существовать не может — это глупость. Валидация является лишь частью декодера и не более того.

С т.з. всего остального — никакой валидации в принципе существовать не может, да и она не имеет смысла.

В UCS-2/UCS-4, опять-таки, существуют невалидные коды.

Там не может подобного существовать в принципе. Это просто таблица.

Из-за тех самых суррогатных пар. Собственно, суррогаты как раз и невалидны, поскольку соответствующих им символов в Юникоде не существует.

Не существует — не значит невалидно.

В целом я ваши рассуждения вообще не понимаю. Вы откуда-то взяли какое-то «валидно», но ссылаетесь на декодирование(которое вы, очевидно, не делаете). Вы каким-то образом накладываете критерий валидности на передающий канал, хотя никакого подобного упоминания нет. И это попросту бред. «Валидация» — это задача декодера.

В конечном итоге была придумана какая-то глупость и путём подмены понятий с кого-то начинается требование. Я вообще могу сослаться на декодер и то, что декодер является валидатором, а значит МОЖЕТ принимать невалидную последовательность.

Из этого напрямую следует то, что на входящую последовательность НИКАКИХ ограничений нет. А значит никакого смысла валидации нет и вообще её нет. Это ваша локальная придумка.
If there is no W2 (that is, the sequence ends with W1), or if W2
is not between 0xDC00 and 0xDFFF, the sequence is in error.
Terminate.

Т.е. там попросту есть ограничения на значения во второй части пары.

При этом последующее слово обязательно должно содержать 110111 в старших разрядах. Если это не так, то последовательность невалидна.

Этого я там не нашел.

W1 is between 0xD800 and 0xDBFF
W2 is between 0xDC00 and 0xDFFF

Это все ограничения, которые я там увидел.

Но в любом случае — ограничения на значения в utf16 есть. Значит она может быть невалидной.

Also note that a string
decoding algorithm, as opposed to the single-character decoding
described above, need not terminate upon detection of an error, if
proper error reporting and/or recovery is provided.

Хотя тут допускается игнорирование ошибок. Зарепортить можно когда и как угодно. Аналогично с восстановлением. После, по-факту использования я могу попросту игнорировать «битые» пары. Насколько я понимаю под восстановлением тут понимается «восстановление владиности последовательности».

Неверно. Там нет такого понятия как «невалидный». Опять глупости вызванные полным непониманием темы. ascii — это таблица, а как там они хранятся и в каком виде — абсолютно неважно. Тут идёт попросту путаница с utf8, где utf8 — это именно формат кодирования, а не таблица кодов.
Насколько я знаю utf-16 поддерживает суррогатные пары

Действительно, судя по: www.unicode.org/faq/utf_bom.html#utf16-11 сейчас под utf16 понимается именно формат кодирования. Т.е. я был не совсем точен — пусть будет UCS-2/UCS-4/да пусть та же ascii.

При этом последующее слово обязательно должно содержать 110111 в старших разрядах. Если это не так, то последовательность невалидна.

Я не нашел подобных ограничений. Можете предоставить ссылку на то, что стандарт utf16 как-то ограничивает значение второго числа из пары.
При чем тут валиадатор UTF8?


Что я писал:

Как строка связана с utf8? Как минимум существуют строки без юникода, а даже если с юникодом — существуют разные форматы юникода.

Ещё раз. Это локальные проблемы отдельной библиотеки. Реальная жизнь на строки никакого подобного инварианта не накладывает. Строки это не только utf-8.


Вы пытались со мною спорить? Пытались. Что вы опровергали? Опровергали эти утверждения. Значит, вы утверждаете, что строки бывают только utf8 и что все строки должны его валидировтаь.

Конечно, в строках должны быть символы, а не рандомный мусор. Если вы не валидируете строки «и так сойдет», то тут исключительно ваши проблемы.

Вот тот набор слов, который я услышал на процитированные выше тезисы(мои). Я говорил о не-utf8 строках. Мне в ответ, среди этого набора слов, поступило заявление:

Конечно, в строках должны быть символы, а не рандомный мусор.

Т.е. под символами тут имеется ввиду utf8(хотя какое отношение utf8 и его валидация имеет к символам, но ладно), а «рандомным мусором» называется всё, что не является валидированным utf8.

В расте дефолтная строка это utf8. Значит и в плюсовом коде должен быть utf8, иначе сравнение не до конца корректное.

С чего вдруг? Эта проблема вашего «языка сливающего луа», а не мои. По этой «логике» у вас должен быть ГЦ, когда вы сравниваете что-то с луа(хотя это не помогло). Ведь тогда сравнение нечестное? Но это глупость.

Код должен выполнять поставленную задачу. Если мне нужна валидация utf8 и сам utf8 — она будет и должна быть. Если не нужна, то не будет.

А то, что вы пытаетесь фанатично защищать(вы бы лучше делом защищали, а не разговорами) свой предмет обожания не значит, что «как у меня» — должно быть у всех.

Это вари проблемы, что ваш «язык» сливает и не даёт вам выбора. И это не значит, что этот выбор ненужен. Это значит, что выбора нет у вас. И на меня это никак распространятся не должно.
Есть что ответить? Или опять, типичная для хабра, клоунада? Доказывать необходимость/нужность — это ваша задача, а не моя. Вы это утверждаете, а не я. Доказывать ненужность чего угодно я не обязан — это состояние всего по умолчанию и это не требует доказательств по причине невозможности доказательства ненужности.

Информация

В рейтинге
Не участвует
Зарегистрирован
Активность