Информация об изменениях

Сообщение Re[6]: JSON vs BSON: очередное торжество больного воображени от 03.12.2022 17:20

Изменено 05.12.2022 12:34 vdimas

Re[6]: JSON vs BSON: очередное торжество больного воображени
Здравствуйте, swame, Вы писали:

S>Я работаю в Dekphi, в разных реализациях JSON, и, да, там каждая нода представляется объектом и делается копия строки.

S>А что — я не в курсе — в System.Text.Json под капотом не так? Точно?

Не так. Там просто разметка по смещению, информация хранится с сжатом виде, каждый элемент описывается тройкой int, где сами эти int тоже разбиты на битовые поля:
        // The database for the parsed structure of a JSON document.
        //
        // Every token from the document gets a row, which has one of the following forms:
        //
        // Number
        // * First int
        //   * Top bit is unassigned / always clear
        //   * 31 bits for token offset
        // * Second int
        //   * Top bit is set if the number uses scientific notation
        //   * 31 bits for the token length
        // * Third int
        //   * 4 bits JsonTokenType
        //   * 28 bits unassigned / always clear
        //
        // String, PropertyName
        // * First int
        //   * Top bit is unassigned / always clear
        //   * 31 bits for token offset
        // * Second int
        //   * Top bit is set if the string requires unescaping
        //   * 31 bits for the token length
        // * Third int
        //   * 4 bits JsonTokenType
        //   * 28 bits unassigned / always clear
        //
        // Other value types (True, False, Null)
        // * First int
        //   * Top bit is unassigned / always clear
        //   * 31 bits for token offset
        // * Second int
        //   * Top bit is unassigned / always clear
        //   * 31 bits for the token length
        // * Third int
        //   * 4 bits JsonTokenType
        //   * 28 bits unassigned / always clear
        //
        // EndObject / EndArray
        // * First int
        //   * Top bit is unassigned / always clear
        //   * 31 bits for token offset
        // * Second int
        //   * Top bit is unassigned / always clear
        //   * 31 bits for the token length (always 1, effectively unassigned)
        // * Third int
        //   * 4 bits JsonTokenType
        //   * 28 bits for the number of rows until the previous value (never 0)
        //
        // StartObject
        // * First int
        //   * Top bit is unassigned / always clear
        //   * 31 bits for token offset
        // * Second int
        //   * Top bit is unassigned / always clear
        //   * 31 bits for the token length (always 1, effectively unassigned)
        // * Third int
        //   * 4 bits JsonTokenType
        //   * 28 bits for the number of rows until the next value (never 0)
        //
        // StartArray
        // * First int
        //   * Top bit is unassigned / always clear
        //   * 31 bits for token offset
        // * Second int
        //   * Top bit is set if the array contains other arrays or objects ("complex" types)
        //   * 31 bits for the number of elements in this array
        // * Third int
        //   * 4 bits JsonTokenType
        //   * 28 bits for the number of rows until the next value (never 0)


В публичном АПИ эта информация предоставляется через легковесный value-type:
public readonly struct JsonElement

Причём, JsonElement создаётся на лету как view к массиву индексов распарсенного док-та, в реальности объекты этого типа не хранятся.
То бишь, JsonDocument хранит только два массива — исходные даные и массив разметки над данными.

Через элемент можно пройтись по его детям тоже через легковесный енумератор:
public struct JsonElement.ObjectEnumerator

Тоже будет создание на лету этого представления, без потребления памяти из кучи.

Основная фишка System.Text.Json в том, что он позволяет маппить объекты как в рантайм через рефлексию, там и в design-time через кодогенерацию.
Во втором случае можно задействовать технологию .Net Native AOT, где в скомпилённом бинарнике уже никакой лишней метаинформации нет, как и нет байт-кода.

Делается это так:
[JsonSourceGenerationOptions(
        GenerationMode = JsonSourceGenerationMode.Metadata,
        IncludeFields = true,
        PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase
    )]
[JsonSerializable(typeof(Capabilities))]
internal partial class CMakeJson : JsonSerializerContext {
    public static ValueTask<Capabilities> ParseCapabilitiesAsync(Stream s, CancellationToken ct)
        => JsonSerializer.DeserializeAsync(s, Default.Capabilities, ct);
}

internal class Capabilities {
    public Generator[] Generators;
    public CMakeVersion Version = new CMakeVersion();
}

public struct Generator {
    public string Name;
    public bool PlatformSupport;
    public bool ToolsetSupport;
    public string[]? SupportedPlatforms;
}

internal struct CMakeVersion {
    public string String { get; set; }
}


При компиляции этого файла генерируется код сериализации/десериализации результата вызова "cmake -E capabilities".
В общем, хоть какая-то польза от Roslyn. ))

(в MSVS 2022 генерируется так же при сохранении файла, если ошибок компиляции нет)


S>Если там хранятся смещения, как ты пишешь, значит нельзя поменять ноду распарсенного JSON по сценарию прочитал — поменял — записал обратно.

S>Тогда это не DOM, а что-то другое.

Да нет, это именно DOM, просто он не является редактируемым, заточен на парсинг.
Но это именно объектная модель док-та, кто сказал, что модель документа не может быть read only? ))

Если нужно редактирование — опиши свои типизированные структуры, как показал выше, или используй более общий Dictionary<string, object>.
Прочитал в такие структуры, поредактировал, записал обратно.


V>>Если твой парсер тоже обходится подстроками, — то будет примерно так же, с точностью до вылизывания (системная реализация нехило вылизана).

V>>Просто ты часть работы переносишь из Json парсера в свой, непонятно откуда надеясь, что твой парсер будет эффективнее. ))
S>Я использую этот парсинг строки и в других местах, более быстродействующих чех парсинг файла, никаких тормозов там не наблюдается.

Тут только тесты покажут.
Де-факто системные реализации вылизываются, а наколенные вылизываются намного реже, особенно в таких вот непринципиальных задачах.
Потому что в конкретном проекте подобная фунциональность побочная, а не целевая.


V>>JSON сам по себе малость убог и избыточен, увы.

V>>Сравни похожий на него QML:
V>>
V>>Item {
V>>     Rectangle {
V>>         id: myRect
V>>         width: 120
V>>         height: 100
V>>     }
V>>     Rectangle {
V>>         width: myRect.width
V>>         height: 200
V>>     }
V>>}
V>>

S>по сравнению с повторяющимисч иенами атрибутов разделитель — мелочь.

Это не имена атрибутов, ведь там нет ':'.
Это описание лейаута, вызов конструкторов объектов.
Обрати внимание, что когда я предлагал убрать избыточность синтаксиса, я оставил ':' для атрибутов:
http://www.rsdn.org/forum/flame.comp/8418302.1

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

Не сомневаюсь, что рано или поздно JSON будет допиливаться, пойдут другие версии стандарта, ну или от него будут форкаться другие стандарты с другими именами собственными, что не суть важно, как это будет обыграно. ))

Но оно будет обязательно.

Похожий синтаксис получается не только в QML, вот тебе Flutter:
    MaterialApp(
      title: 'Ice Creams FTW',
      home: const HomePage(title: 'Ice Cream Stores in SF'),
      theme: ThemeData(
        primarySwatch: Colors.pink,
        scaffoldBackgroundColor: Colors.pink[50],
      ),
    )

Язык Dart умеет быть скриптовым, т.е. эти описания тоже можно передавать удалённо.

Просто JSON — это наследие конкретно JS со всеми вытекающими. ))
И да, в самом начале своей жизни в JSON не было обязательным заключать имена атрибутов в кавычки, это требование появилось позже.
Re[6]: JSON vs BSON: очередное торжество больного воображени
Здравствуйте, swame, Вы писали:

S>Я работаю в Dekphi, в разных реализациях JSON, и, да, там каждая нода представляется объектом и делается копия строки.

S>А что — я не в курсе — в System.Text.Json под капотом не так? Точно?

Не так. Там просто разметка по смещению, информация хранится с сжатом виде, каждый элемент описывается тройкой int, где сами эти int тоже разбиты на битовые поля:
        // The database for the parsed structure of a JSON document.
        //
        // Every token from the document gets a row, which has one of the following forms:
        //
        // Number
        // * First int
        //   * Top bit is unassigned / always clear
        //   * 31 bits for token offset
        // * Second int
        //   * Top bit is set if the number uses scientific notation
        //   * 31 bits for the token length
        // * Third int
        //   * 4 bits JsonTokenType
        //   * 28 bits unassigned / always clear
        //
        // String, PropertyName
        // * First int
        //   * Top bit is unassigned / always clear
        //   * 31 bits for token offset
        // * Second int
        //   * Top bit is set if the string requires unescaping
        //   * 31 bits for the token length
        // * Third int
        //   * 4 bits JsonTokenType
        //   * 28 bits unassigned / always clear
        //
        // Other value types (True, False, Null)
        // * First int
        //   * Top bit is unassigned / always clear
        //   * 31 bits for token offset
        // * Second int
        //   * Top bit is unassigned / always clear
        //   * 31 bits for the token length
        // * Third int
        //   * 4 bits JsonTokenType
        //   * 28 bits unassigned / always clear
        //
        // EndObject / EndArray
        // * First int
        //   * Top bit is unassigned / always clear
        //   * 31 bits for token offset
        // * Second int
        //   * Top bit is unassigned / always clear
        //   * 31 bits for the token length (always 1, effectively unassigned)
        // * Third int
        //   * 4 bits JsonTokenType
        //   * 28 bits for the number of rows until the previous value (never 0)
        //
        // StartObject
        // * First int
        //   * Top bit is unassigned / always clear
        //   * 31 bits for token offset
        // * Second int
        //   * Top bit is unassigned / always clear
        //   * 31 bits for the token length (always 1, effectively unassigned)
        // * Third int
        //   * 4 bits JsonTokenType
        //   * 28 bits for the number of rows until the next value (never 0)
        //
        // StartArray
        // * First int
        //   * Top bit is unassigned / always clear
        //   * 31 bits for token offset
        // * Second int
        //   * Top bit is set if the array contains other arrays or objects ("complex" types)
        //   * 31 bits for the number of elements in this array
        // * Third int
        //   * 4 bits JsonTokenType
        //   * 28 bits for the number of rows until the next value (never 0)


В публичном АПИ эта информация предоставляется через легковесный value-type:
public readonly struct JsonElement

Причём, JsonElement создаётся на лету как view к массиву индексов распарсенного док-та, в реальности объекты этого типа не хранятся.
То бишь, JsonDocument хранит только два массива — исходные данные и массив разметки над данными.

Через элемент можно пройтись по его детям тоже через легковесный енумератор:
public struct JsonElement.ObjectEnumerator

Тоже будет создание на лету этого представления, без потребления памяти из кучи.

Основная фишка System.Text.Json в том, что он позволяет маппить объекты как в рантайм через рефлексию, там и в design-time через кодогенерацию.
Во втором случае можно задействовать технологию .Net Native AOT, где в скомпилённом бинарнике уже никакой лишней метаинформации нет, как и нет байт-кода.

Делается это так:
[JsonSourceGenerationOptions(
        GenerationMode = JsonSourceGenerationMode.Metadata,
        IncludeFields = true,
        PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase
    )]
[JsonSerializable(typeof(Capabilities))]
internal partial class CMakeJson : JsonSerializerContext {
    public static ValueTask<Capabilities> ParseCapabilitiesAsync(Stream s, CancellationToken ct)
        => JsonSerializer.DeserializeAsync(s, Default.Capabilities, ct);
}

internal class Capabilities {
    public Generator[] Generators;
    public CMakeVersion Version = new CMakeVersion();
}

public struct Generator {
    public string Name;
    public bool PlatformSupport;
    public bool ToolsetSupport;
    public string[]? SupportedPlatforms;
}

internal struct CMakeVersion {
    public string String { get; set; }
}


При компиляции этого файла генерируется код сериализации/десериализации результата вызова "cmake -E capabilities".
В общем, хоть какая-то польза от Roslyn. ))

(в MSVS 2022 генерируется так же при сохранении файла, если ошибок компиляции нет)


S>Если там хранятся смещения, как ты пишешь, значит нельзя поменять ноду распарсенного JSON по сценарию прочитал — поменял — записал обратно.

S>Тогда это не DOM, а что-то другое.

Да нет, это именно DOM, просто он не является редактируемым, заточен на парсинг.
Но это именно объектная модель док-та, кто сказал, что модель документа не может быть read only? ))

Если нужно редактирование — опиши свои типизированные структуры, как показал выше, или используй более общий Dictionary<string, object>.
Прочитал в такие структуры, поредактировал, записал обратно.


V>>Если твой парсер тоже обходится подстроками, — то будет примерно так же, с точностью до вылизывания (системная реализация нехило вылизана).

V>>Просто ты часть работы переносишь из Json парсера в свой, непонятно откуда надеясь, что твой парсер будет эффективнее. ))
S>Я использую этот парсинг строки и в других местах, более быстродействующих чех парсинг файла, никаких тормозов там не наблюдается.

Тут только тесты покажут.
Де-факто системные реализации вылизываются, а наколенные вылизываются намного реже, особенно в таких вот непринципиальных задачах.
Потому что в конкретном проекте подобная фунциональность побочная, а не целевая.


V>>JSON сам по себе малость убог и избыточен, увы.

V>>Сравни похожий на него QML:
V>>
V>>Item {
V>>     Rectangle {
V>>         id: myRect
V>>         width: 120
V>>         height: 100
V>>     }
V>>     Rectangle {
V>>         width: myRect.width
V>>         height: 200
V>>     }
V>>}
V>>

S>по сравнению с повторяющимисч иенами атрибутов разделитель — мелочь.

Это не имена атрибутов, ведь там нет ':'.
Это описание лейаута, вызов конструкторов объектов.
Обрати внимание, что когда я предлагал убрать избыточность синтаксиса, я оставил ':' для атрибутов:
http://www.rsdn.org/forum/flame.comp/8418302.1

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

Не сомневаюсь, что рано или поздно JSON будет допиливаться, пойдут другие версии стандарта, ну или от него будут форкаться другие стандарты с другими именами собственными, что не суть важно, как это будет обыграно. ))

Но оно будет обязательно.

Похожий синтаксис получается не только в QML, вот тебе Flutter:
    MaterialApp(
      title: 'Ice Creams FTW',
      home: const HomePage(title: 'Ice Cream Stores in SF'),
      theme: ThemeData(
        primarySwatch: Colors.pink,
        scaffoldBackgroundColor: Colors.pink[50],
      ),
    )

Язык Dart умеет быть скриптовым, т.е. эти описания тоже можно передавать удалённо.

Просто JSON — это наследие конкретно JS со всеми вытекающими. ))
И да, в самом начале своей жизни в JSON не было обязательным заключать имена атрибутов в кавычки, это требование появилось позже.