Здравствуйте, Sinclair, Вы писали:
S>Варианта "скорректировать размер буфера" у нас нету, т.к. TryFormat не даёт нам информации о том, сколько места надо.
Это логично, оно там внутре гоняет Dragon4/Grisu3, и не доделывает вхолостую при нехватке места только чтобы посчитать размер.
S>Спасибо, я как-то так и предполагал, но хотел убедиться. То есть предполагается ровно один паттерн: пробуем втиснуться в буфер, какой бы он ни был; если не сработало — фоллбэкаемся на обычный метод с выделением.
Это в принципе единственный способ форматировать в буфер, а не в аллоцированную строку. Вместо фоллбэка с аллокацией можешь брать всё большие буферы из ArrayPool<char>.Shared, неважно.
Здравствуйте, Qbit86, Вы писали:
S>>Варианта "скорректировать размер буфера" у нас нету, т.к. TryFormat не даёт нам информации о том, сколько места надо.
Q>Это логично, оно там внутре гоняет Dragon4/Grisu3, и не доделывает вхолостую при нехватке места только чтобы посчитать размер.
А где можно посмотреть на ?
Там, где я смотрел, перед форматированием всегда вычисляется вычисляется необходимый размер буфера.
Например здесь — Utf8Formatter.TimeSpan в начале три экрана вычисления размера буфера и только потом один экран непосредственно форматирования.
Здравствуйте, AlexRK, Вы писали:
A>>Есть большая надежда что это будет реально .NET 5. Обьединить лучшие аспекты существующих реализаций
...никто не обещал. Просто название .net core 4 будет путаться с .net fw 4, а потому перешли сразу к версии 5. И убрали слово core чтобы показать, что .net fw особо развиваться уже не будет.
Здравствуйте, Kolesiki, Вы писали:
K>Зачем вам сегодня переносимость? Кому, что и куда переносить? ЧТО переносить и чего нет в других платформах?
Самый наибанальнейший пример — хостить asp.net сервер под линуксом (дешевле и доступнее хостинг), а разрабатывать под виндами и спокойно его и там и там запускать.
Весьма удобно, кстати.
Здравствуйте, sergeya, Вы писали:
Q>>Это логично, оно там внутре гоняет Dragon4/Grisu3, и не доделывает вхолостую при нехватке места только чтобы посчитать размер.
S>Там, где я смотрел, перед форматированием всегда вычисляется вычисляется необходимый размер буфера. S>Например здесь — Utf8Formatter.TimeSpan в начале три экрана вычисления размера буфера и только потом один экран непосредственно форматирования.
Вряд ли это можно найти в TimeSpan, потому что Dragon4 и Grisu3 — это алгоритмы для печати чисел с плавающей точкой в формате IEEE 754.
Здравствуйте, fmiracle, Вы писали:
F>Просто название .net core 4 будет путаться с .net fw 4, а потому перешли сразу к версии 5. И убрали слово core чтобы показать, что .net fw особо развиваться уже не будет.
We are also taking the opportunity to simplify naming. We thought that if there is only one .NET going forward, we don’t need a clarifying term like “Core”. The shorter name is a simplification and also communicates that .NET 5 has uniform capabilities and behaviors. Feel free to continue to use the “.NET Core” name if you prefer it.
— .NET 5 = .NET Core vNext
Здравствуйте, AlexRK, Вы писали:
ARK>Отчего ж один, можно еще в бесконечном цикле долбиться, увеличивая на единицу размер буфера, пока не влезет. Производительность!
И чем это отличалось бы от просто вызова выделяющего метода?
Или предлагается увеличивать буфер через stackalloc?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Qbit86, Вы писали:
S>>>Варианта "скорректировать размер буфера" у нас нету, т.к. TryFormat не даёт нам информации о том, сколько места надо.
Q>>Это логично, оно там внутре гоняет Dragon4/Grisu3, и не доделывает вхолостую при нехватке места только чтобы посчитать размер.
Если бы это было так, и Dragon4/Grisu3 сразу печатали бы в буфер назначения, то в случае неуспешного завершения буфер был бы испорчен.
Поэтому похоже что сначала печать выполняется в промежуточный буфер гарантированно достаточного размера,
и только после этого выполняется попытка скопировать результат в буфер-приемник.
А тут уже есть вся информация о том, сколько места не хватило.
Q>src\Common\src\CoreLib\System\Number.Formatting.cs
Код из приведенного тобой исходника:
private const int CharStackBufferSize = 32;
public static bool TryFormatDouble(double value, ReadOnlySpan<char> format, NumberFormatInfo info, Span<char> destination, out int charsWritten)
{
Span<char> stackBuffer = stackalloc char[CharStackBufferSize];
var sb = new ValueStringBuilder(stackBuffer);
string? s = FormatDouble(ref sb, value, format, info);
return s != null ?
TryCopyTo(s, destination, out charsWritten) :
sb.TryCopyTo(destination, out charsWritten);
}
Здравствуйте, sergeya, Вы писали:
S>Если бы это было так, и Dragon4/Grisu3 сразу печатали бы в буфер назначения, то в случае неуспешного завершения буфер был бы испорчен.
Я не говорил, что он сразу печатает в выходной буфер.
S>Поэтому похоже что сначала печать выполняется в промежуточный буфер гарантированно достаточного размера,
Ок, возможно в данной имплементации так.
S>А тут уже есть вся информация о том, сколько места не хватило.
Но в общем случае какая-нибудь другая реализация TryFormat для этого или какого-то другого типа может не знать сколько места не хватило. Скажем, нет смысла продолжать рендерить какой-нибудь список после того, как стало известно, что места в целевом буфере не хватит (даже если потенциально хватит во внутреннем буфере). Такая сигнатура TryFormat достаточна в большинстве случаев.
Здравствуйте, Qbit86, Вы писали:
S>>Поэтому похоже что сначала печать выполняется в промежуточный буфер гарантированно достаточного размера, Q>Ок, возможно в данной имплементации так.
Ну т.е. у тебя нет практического примера, иллюстрируюего причину того, что "TryFormat не даёт нам информации о том, сколько места надо"?
Здравствуйте, Sinclair, Вы писали:
ARK>>Отчего ж один, можно еще в бесконечном цикле долбиться, увеличивая на единицу размер буфера, пока не влезет. Производительность! S>И чем это отличалось бы от просто вызова выделяющего метода? S>Или предлагается увеличивать буфер через stackalloc?
Здравствуйте, sergeya, Вы писали:
S>Ну т.е. у тебя нет практического примера, иллюстрируюего причину того, что "TryFormat не даёт нам информации о том, сколько места надо"?
Ты какие-то окольные наводящие вопросы задаёшь, экзаменуешь меня что ли, лол. Вообще не очевидно, с чего ты решил, что такая твоя позиция по отношению ко мне имеет хоть какие-то основания :)
Здравствуйте, sergeya, Вы писали:
S>Может быть не в тему, но для меня было открытием узнать, что stackalloc умеет выделять память динамического размера.
Тогда, возможно, также будет новостью узнать, что в C# 7 для stackallock уже больше не требуется unsafe-контекст. Правда, для этого требуется Span<T>, который есть в .NET Core, и которого нет и не будет в .NET Legacy. (Хотя его туда бэкпортировали в NuGet-пакете.)
Здравствуйте, Qbit86, Вы писали:
Q>Здравствуйте, sergeya, Вы писали:
S>>Ну т.е. у тебя нет практического примера, иллюстрируюего причину того, что "TryFormat не даёт нам информации о том, сколько места надо"?
Q>Ты какие-то окольные наводящие вопросы задаёшь, экзаменуешь меня что ли, лол.
Обычная дискуссия. Ты привел аргумент в защиту проектировщиков TryFormat, я его опроверг.
>>> Варианта "скорректировать размер буфера" у нас нету, т.к. TryFormat не даёт нам информации о том, сколько места надо. >> Это логично, оно там внутре гоняет Dragon4/Grisu3, и не доделывает вхолостую при нехватке места только чтобы посчитать размер. > сначала печать выполняется в промежуточный буфер гарантированно достаточного размера, а тут уже есть вся информация о том, сколько места не хватило.
Поскольку ты все еще считашь дизайн TryFormat удачным, я поинтересовался, нет ли у тебя других практических примеров.
Q>Вообще не очевидно, с чего ты решил, что такая твоя позиция по отношению ко мне имеет хоть какие-то основания
А вот этого пассажа я не понял.
Здравствуйте, sergeya, Вы писали:
S>нет ли у тебя других практических примеров.
Других примеров я не знаю, но мне кажется, и пример с плавающими числами вполне подходит. Текущая сигнатура API позволяет при необходимости изменить реализацию так, чтоб она останавливала работу, если превысит переданную длину — как я ранее предполагал, что оно должно быть так реализовано. Если бы API обязывал реализацию считать требуемый размер, то так было сделать бы нельзя.
S>Поскольку ты все еще считашь дизайн TryFormat удачным, я поинтересовался, нет ли у тебя других практических примеров.
Поскольку ты все еще считашь дизайн TryFormat неудачным, давай теперь ты поищи примеры другого дизайна API форматирования в буфер, который возвращал бы рассчитанный формат. В Rust, в C++, где-нибудь. Кто там не «индусы» и не «делитанты».
Я TryFormat использую, и это точно было бы неудобно, если бы он как-то возвращал (пятым параметром) ещё и ненужный мне рассчётный размер (для тех типов, для которых его можно рассчитать, а для тех, для которых нельзя — не возвращал).
var t = 1;
Span<char> s;
unsafe
{
do
{
s = new Span<char>(stackalloc char[t],t);
t++;
}
while(!number.TryFormat(s, out int written))
}
Console.WriteLine(s);
представляется не самой хорошей идеей.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, okon, Вы писали: O>а Winform и WPF остаются Windows specific, их исключат из .NET5 и будут отдельные сборки через nuget подключаться ?
With the .NET Core 3.0 release in September 2019 we think that all *new* .NET applications should be based on .NET Core. The primary application types from .NET Framework are supported, and where we did not port something over there is a recommended modern replacement. All future investment in .NET will be in .NET Core. This includes: Runtime, JIT, AOT, GC, BCL (Base Class Library), C#, VB.NET, F#, ASP.NET, Entity Framework, ML.NET, WinForms, WPF and Xamarin.
Здравствуйте, Qbit86, Вы писали:
Q>Других примеров я не знаю, но мне кажется, и пример с плавающими числами вполне подходит. Текущая сигнатура API позволяет при необходимости изменить реализацию так, чтоб она останавливала работу, если превысит переданную длину — как я ранее предполагал, что оно должно быть так реализовано. Если бы API обязывал реализацию считать требуемый размер, то так было сделать бы нельзя.
S>>Поскольку ты все еще считашь дизайн TryFormat удачным, я поинтересовался, нет ли у тебя других практических примеров. Q>Поскольку ты все еще считашь дизайн TryFormat неудачным, давай теперь ты поищи примеры другого дизайна API форматирования в буфер, который возвращал бы рассчитанный формат. В Rust, в C++, где-нибудь. Кто там не «индусы» и не «делитанты».
int size = snprintf(NULL, 0, "%d", 132);
char * a = malloc(size + 1);
sprintf(a, "%d", 132);
Но меня смущает не отсутсвие расчитанного размера, а двойная работа — если размера буфера не хватит, придется выполнять форматирование повторно с самого начала.
Я в своем первом сообщении так и написал — http://rsdn.org/forum/dotnet/7441915.1
Поэтому рассчитанный размер мне тоже не очень нужен. Мне больше нравится дизайн System.Text.Decoder.Convert(), который позволяет продолжить конвертацию с предыдущей точки остановки.
Правда, для этого надо хранить состояние между вызовами, а сделать это для stackalloc буфера будет нетривиально (но варианты придумать можно).
Отдать остатки stackalloc буфера наружу без перевыделения памяти тоже не вариант.
Тут надо думать и рассматривать варианты использования.
Конкретно тот сценарий, который ты привел — AppendSpanFormattable
я бы реализовал с помощью метода FormatTo(stringBulder). Чтобы Decimal.Format() внутри себя печатал в stackalloc буфер, а затем вызвал stringBulder.Append(Span<char> span), внутри которого была бы вся та оптимизация — быстрое копирование во внутрненний буфер, а если его размер недостаточен, то динамическое расширение.
По аллокациям и процессорным тактам получилось бы оптимальнее, чем существущее решение — логика то и типы данных те же самые, но нет необходимости в повторных вызовов.
Здравствуйте, Qbit86, Вы писали:
S>>Может быть не в тему, но для меня было открытием узнать, что stackalloc умеет выделять память динамического размера. Q>Тогда, возможно, также будет новостью узнать, что в C# 7 для stackallock уже больше не требуется unsafe-контекст. Правда, для этого требуется Span<T>...