Spec-Zone.ru › Haskell 7

Data.ByteString.Builder

Авторские права (c) 2010 Jasper Van der Jeugt (c) 2010 - 2011 Simon Meier
Лицензия BSD3-стиль (см. LICENSE)
Поддержка Simon Meier <iridcode@gmail.com>
Переносимость GHC
Безопасный Haskell Надёжный
Язык Haskell98

Содержание

  • Тип Builder
  • Выполнение Builder
  • Создание Builder
    • Бинарные кодировки
      • Большой порядок следования байтов
      • Малый порядок следования байтов
    • Кодировки символов
      • ASCII (Char7)
      • ISO/IEC 8859-1 (Char8)
      • UTF-8
    • Форматирование чисел как текста
      • Десятичные числа
      • Шестнадцатеричные числа
      • Шестнадцатеричные числа фиксированной ширины

Описание

Builder используются для эффективного построения последовательностей байтов из более мелких частей. Обычно такое построение является частью реализации кодирования, т. е. функции для преобразования значений Haskell в последовательности байтов. Примерами кодировок являются генерация последовательности байтов, представляющей HTML-документ, который отправляется в HTTP-ответе веб-приложением, или сериализация значения Haskell с использованием фиксированного бинарного формата.

Для эффективной реализации кодирования важно, чтобы (а) затрачивалось мало времени на преобразование значений Haskell в результирующую последовательность байтов и (б) представление результирующей последовательности было таким, чтобы ее можно было эффективно использовать. Builder поддерживают (а), предоставляя операцию конкатенации O(1) и эффективные реализации основных кодировок для Char, Int и других стандартных значений Haskell. Они поддерживают (б), представляя свой результат как ленивую ByteString, которая внутри себя представляет собой просто связанный список указателей на блоки последовательных блоков памяти. Ленивые ByteString могут эффективно использоваться функциями, которые записывают их в файл или отправляют их по сетевому сокету. Обратите внимание, что каждый предел блока влечёт дорогостоящие дополнительные затраты (например, системный вызов), которые необходимо амортизировать за счёт затрат на обработку тела блока. Builder поэтому уделяют особое внимание, чтобы средний размер блока был достаточно большим. Точное значение «достаточно большого» зависит от приложения. Текущая реализация настроена на средний размер блока между 4 КБ и 32 КБ, что должно подойти для большинства приложений.

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

data Cell = StringC String
          | IntC Int
          deriving( Eq, Ord, Show )

type Row   = [Cell]
type Table = [Row]

Мы используем следующие импорты и сокращаем mappend для упрощения чтения.

import qualified Data.ByteString.Lazy               as L
import           Data.ByteString.Builder
import           Data.Monoid
import           Data.Foldable                        (foldMap)
import           Data.List                            (intersperse)

infixr 4 <>
(<>) :: Monoid m => m -> m -> m
(<>) = mappend

CSV — это представление таблиц на основе символов. Для максимальной модульности мы могли бы сначала преобразовать Table в String и затем закодировать это String с помощью какой-либо кодировки символов Юникода. Однако это приведёт к потере производительности из-за того, что промежуточное представление String будет построено и сразу же удалено. Мы избавляемся от этого промежуточного представления String, задав кодировку символов UTF-8 и используя Builder для преобразования Table напрямую в UTF-8 закодированные CSV таблицы, представленные в виде ленивых ByteString.

encodeUtf8CSV :: Table -> L.ByteString
encodeUtf8CSV = toLazyByteString . renderTable

renderTable :: Table -> Builder
renderTable rs = mconcat [renderRow r <> charUtf8 '\n' | r <- rs]

renderRow :: Row -> Builder
renderRow []     = mempty
renderRow (c:cs) =
    renderCell c <> mconcat [ charUtf8 ',' <> renderCell c' | c' <- cs ]

renderCell :: Cell -> Builder
renderCell (StringC cs) = renderString cs
renderCell (IntC i)     = intDec i

renderString :: String -> Builder
renderString cs = charUtf8 '"' <> foldMap escape cs <> charUtf8 '"'
  where
    escape '\\' = charUtf8 '\\' <> charUtf8 '\\'
    escape '\"' = charUtf8 '\\' <> charUtf8 '\"'
    escape c    = charUtf8 c

Обратите внимание, что кодировка ASCII является подмножеством кодировки UTF-8, поэтому мы можем использовать оптимизированную функцию intDec для кодирования Int как десятичного числа с UTF-8 закодированными цифрами. Использование intDec более эффективно, чем stringUtf8 . show, так как это позволяет избежать создания промежуточного String. Избежание этой промежуточной структуры данных значительно улучшает производительность, поскольку кодирование Cell является основной операцией для отображения таблиц CSV. См. Data.ByteString.Builder.Prim для получения дополнительной информации о том, как улучшить производительность renderString.

Мы демонстрируем нашу функцию кодирования UTF-8 CSV на следующей таблице.

strings :: [String]
strings =  ["hello", "\"1\"", "λ-wörld"]

table :: Table
table = [map StringC strings, map IntC [-3..3]]

Выражение encodeUtf8CSV table приводит к следующей ленивой ByteString.

Chunk "\"hello\",\"\\\"1\\\"\",\"\206\187-w\195\182rld\"\n-3,-2,-1,0,1,2,3\n" Empty

Мы можем ясно видеть, что мы преобразуем в бинарный формат. Символы «λ» и «ö», имеющие код Юникода выше 127, расширяются до их соответствующего многобайтового представления UTF-8.

Мы используем библиотеку criterion (http://hackage.haskell.org/package/criterion) для оценки производительности нашей функции кодирования на следующей таблице.

import Criterion.Main     -- add this import to the ones above

maxiTable :: Table
maxiTable = take 1000 $ cycle table

main :: IO ()
main = defaultMain
  [ bench "encodeUtf8CSV maxiTable (original)" $
      whnf (L.length . encodeUtf8CSV) maxiTable
  ]

На процессоре Core2 Duo 2.20 ГГц на 32-битной Linux вышеприведенный код тратит 1 мс на генерацию ленивой ByteString длиной 22 500 байт. Вновь взглянув на определения выше, мы видим, что мы позаботились об избегании промежуточных структур данных, так как в противном случае мы бы потеряли производительность. Например, следующее (вероятно, более простое) определение renderRow примерно на 20% медленнее.

renderRow :: Row -> Builder
renderRow  = mconcat . intersperse (charUtf8 ',') . map renderCell

Аналогично, следует избегать использования конкатенаций O(n), таких как ++ или эквивалентных операций concat над строгими и ленивыми ByteString. Следующее определение renderString также примерно на 20% медленнее.

renderString :: String -> Builder
renderString cs = charUtf8 $ "\"" ++ concatMap escape cs ++ "\""
  where
    escape '\\' = "\\"
    escape '\"' = "\\\""
    escape c    = return c

Помимо удаления промежуточных структур данных, кодировки можно дополнительно оптимизировать, настроив их параметры выполнения с помощью функций в Data.ByteString.Builder.Extra и их «внутренних циклов» с помощью функций в Data.ByteString.Builder.Prim.

Тип Builder

data Builder Источник

Builder обозначают последовательности байтов. Они являются Monoid, где mempty — это последовательность нулевой длины, а mappend — это конкатенация, которая выполняется за O(1).

Примеры реализации

Monoid Builder

Выполнение Builder

Внутри Builder — это функции заполнения буфера. Они выполняются драйвером, который предоставляет им фактический буфер для заполнения. После вызова с буфером, Builder заполняет его и возвращает сигнал драйверу, сообщая, что он либо закончил, заполнил текущий буфер, или хочет напрямую вставить ссылку на блок памяти. В последних двух случаях Builder также возвращает продолжение Builder, которое драйвер может вызвать для заполнения следующего буфера. Здесь мы предоставляем два драйвера, которые удовлетворяют почти всем случаям использования. См. Data.ByteString.Builder.Extra для получения информации о настройке их параметров.

toLazyByteString :: Builder -> ByteString Источник

Выполнить Builder и вернуть сгенерированные блоки как ленивую ByteString. Работа выполняется лениво, т. е. только при принудительном вычислении блока ленивой ByteString.

hPutBuilder :: Handle -> Builder -> IO () Источник

Вывести Builder в Handle. Builder выполняется непосредственно в буфере Handle.

Рекомендуется установить Handle в двоичный и BlockBuffering режим. См. hSetBinaryMode и hSetBuffering.

Эта функция более эффективна, чем hPut . toLazyByteString, так как во многих случаях не требуется выделение буфера. Кроме того, результаты нескольких выполнений коротких Builder объединяются в буфере Handle , тем самым избегая ненужных сбросов буфера.

Создание Builder

Бинарные кодировки

byteString :: ByteString -> Builder Источник

Создать Builder, обозначающую ту же последовательность байтов, что и строгий ByteString. Builder вставляет большие ByteString напрямую, но копирует маленькие, чтобы обеспечить, что сгенерированные блоки в среднем будут большими.

lazyByteString :: ByteString -> Builder Источник

Создать Builder, обозначающую ту же последовательность байтов, что и ленивая ByteString. Builder вставляет большие блоки ленивой ByteString напрямую, но копирует маленькие, чтобы обеспечить, что сгенерированные блоки в среднем будут большими.

shortByteString :: ShortByteString -> Builder Источник

Построить Builder, копирующий ShortByteString.

int8 :: Int8 -> Builder Source

Закодировать один подписанный байт как есть.

word8 :: Word8 -> Builder Source

Закодировать один беззнаковый байт как есть.

Big-endian

int16BE :: Int16 -> Builder Source

Закодировать Int16 в формате big endian.

int32BE :: Int32 -> Builder Source

Закодировать Int32 в формате big endian.

int64BE :: Int64 -> Builder Source

Закодировать Int64 в формате big endian.

word16BE :: Word16 -> Builder Source

Закодировать Word16 в формате big endian.

word32BE :: Word32 -> Builder Source

Закодировать Word32 в формате big endian.

word64BE :: Word64 -> Builder Source

Закодировать Word64 в формате big endian.

floatBE :: Float -> Builder Source

Закодировать Float в формате big endian.

doubleBE :: Double -> Builder Source

Закодировать Double в формате big endian.

Little-endian

int16LE :: Int16 -> Builder Source

Закодировать Int16 в формате little endian.

int32LE :: Int32 -> Builder Source

Закодировать Int32 в формате little endian.

int64LE :: Int64 -> Builder Source

Закодировать Int64 в формате little endian.

word16LE :: Word16 -> Builder Source

Закодировать Word16 в формате little endian.

word32LE :: Word32 -> Builder Source

Закодировать Word32 в формате little endian.

word64LE :: Word64 -> Builder Source

Закодировать Word64 в формате little endian.

floatLE :: Float -> Builder Source

Закодировать Float в формате little endian.

doubleLE :: Double -> Builder Source

Закодировать Double в формате little endian.

Кодировки символов

Преобразование из Char и String в Builder в различных кодировках.

ASCII (Char7)

Кодировка ASCII является 7-битной кодировкой. Реализованная здесь кодировка Char7 работает путем усечения кодовой точки Unicode до 7 бит, добавления перед ней ведущего 0 и кодирования полученных 8 бит в один байт. Для кодовых точек 0-127 это соответствует кодировке ASCII.

char7 :: Char -> Builder Source

Char7 кодирует Char.

string7 :: String -> Builder Source

Char7 кодирует String.

ISO/IEC 8859-1 (Char8)

Кодировка ISO/IEC 8859-1 является 8-битной кодировкой, часто известной как Latin-1. Реализованная здесь кодировка Char8 работает путем усечения кодовой точки Unicode до 8 бит и кодирования их в один байт. Для кодовых точек 0-255 это соответствует кодировке ISO/IEC 8859-1.

char8 :: Char -> Builder Source

Char8 кодирует Char.

string8 :: String -> Builder Source

Char8 кодирует String.

UTF-8

Кодировка UTF-8 может кодировать все кодовые точки Unicode. Мы рекомендуем всегда использовать её для кодирования Char и String, если приложение действительно не требует другой кодировки.

charUtf8 :: Char -> Builder Source

UTF-8 кодирует Char.

stringUtf8 :: String -> Builder Source

UTF-8 кодирует String.

Форматирование чисел как текст

Форматирование чисел как ASCII-текст.

Обратите внимание, что вы также можете использовать эти функции для кодировок ISO/IEC 8859-1 и UTF-8, поскольку кодировка ASCII эквивалентна для кодовых точек 0-127.

Десятичные числа

Десятичное кодирование чисел с использованием ASCII-кодированных символов.

int8Dec :: Int8 -> Builder Source

Десятичное кодирование Int8 с использованием десятичных цифр ASCII.

Например:

toLazyByteString (int8Dec 42)   = "42"
toLazyByteString (int8Dec (-1)) = "-1"

int16Dec :: Int16 -> Builder Source

Десятичное кодирование Int16 с использованием десятичных цифр ASCII.

int32Dec :: Int32 -> Builder Source

Десятичное кодирование Int32 с использованием ASCII-цифр.

int64Dec :: Int64 -> Builder Source

Десятичное кодирование Int64 с использованием ASCII-цифр.

intDec :: Int -> Builder Source

Десятичное кодирование Int с использованием ASCII-цифр.

integerDec :: Integer -> Builder Source

Десятичное кодирование Integer с использованием ASCII-цифр.

word8Dec :: Word8 -> Builder Source

Десятичное кодирование Word8 с использованием ASCII-цифр.

word16Dec :: Word16 -> Builder Source

Десятичное кодирование Word16 с использованием ASCII-цифр.

word32Dec :: Word32 -> Builder Source

Десятичное кодирование Word32 с использованием ASCII-цифр.

word64Dec :: Word64 -> Builder Source

Десятичное кодирование Word64 с использованием ASCII-цифр.

wordDec :: Word -> Builder Source

Десятичное кодирование Word с использованием ASCII-цифр.

floatDec :: Float -> Builder Source

Сейчас медленно. Десятичное кодирование IEEE Float.

doubleDec :: Double -> Builder Source

Сейчас медленно. Десятичное кодирование IEEE Double.

Шестнадцатеричные числа

Кодирование целых положительных чисел в шестнадцатеричном формате с использованием строчных ASCII-символов. Используется кратчайшее возможное представление. Например,

>>> toLazyByteString (word16Hex 0x0a10)
Chunk "a10" Empty

Обратите внимание, что поддержка использования прописных символов отсутствует. Пожалуйста, обратитесь к разработчику, если ваше приложение не может работать без шестнадцатеричных кодировок, использующих прописные символы.

word8Hex :: Word8 -> Builder Source

Кратчайшее шестнадцатеричное кодирование Word8 с использованием строчных символов.

word16Hex :: Word16 -> Builder Source

Кратчайшее шестнадцатеричное кодирование Word16 с использованием строчных символов.

word32Hex :: Word32 -> Builder Source

Кратчайшее шестнадцатеричное кодирование Word32 с использованием строчных символов.

word64Hex :: Word64 -> Builder Source

Кратчайшее шестнадцатеричное кодирование Word64 с использованием строчных символов.

wordHex :: Word -> Builder Source

Кратчайшее шестнадцатеричное кодирование Word с использованием строчных символов.

Шестнадцатеричные числа фиксированной ширины

int8HexFixed :: Int8 -> Builder Source

Кодирование Int8 с использованием 2 тетрад (шестнадцатеричных цифр).

int16HexFixed :: Int16 -> Builder Source

Кодирование Int16 с использованием 4 тетрад.

int32HexFixed :: Int32 -> Builder Source

Кодирование Int32 с использованием 8 тетрад.

int64HexFixed :: Int64 -> Builder Source

Кодирование Int64 с использованием 16 тетрад.

word8HexFixed :: Word8 -> Builder Source

Кодирование Word8 с использованием 2 тетрад (шестнадцатеричных цифр).

word16HexFixed :: Word16 -> Builder Source

Кодирование Word16 с использованием 4 тетрад.

word32HexFixed :: Word32 -> Builder Source

Кодирование Word32 с использованием 8 тетрад.

word64HexFixed :: Word64 -> Builder Source

Кодирование Word64 с использованием 16 тетрад.

floatHexFixed :: Float -> Builder Source

Кодирование IEEE Float с использованием 8 тетрад.

doubleHexFixed :: Double -> Builder Source

Кодирование IEEE Double с использованием 16 тетрад.

byteStringHex :: ByteString -> Builder Source

Кодирует каждый байт ByteString с использованием его фиксированной ширины шестнадцатеричного кодирования.

lazyByteStringHex :: ByteString -> Builder Source

Кодирует каждый байт ленивого ByteString с использованием его фиксированной ширины шестнадцатеричного кодирования.

© The University of Glasgow and others
Licensed under a BSD-style license (see top of the page).
https://downloads.haskell.org/~ghc/7.10.3/docs/html/libraries/bytestring-0.10.6.0/Data-ByteString-Builder.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API