Преобразование Lazy ByteString в строгую ByteString

У меня есть функция, которая принимает ленивый ByteString, что я хочу иметь возвращаемые списки strict ByteStrings (лень переводить на списочный тип вывода).

import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as L
csVals :: L.ByteString -> [B.ByteString]

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

Как мне "строгать" ByteString без разделить их?

Обновление0

Я хочу взять Lazy ByteString и сделать один строгий ByteString, содержащий все его данные.


person Matt Joiner    schedule 19.10.2011    source источник
comment
В чем проблема с toChunks? На первый взгляд кажется, что он консервирует лень.   -  person Mikhail Glushenkov    schedule 19.10.2011
comment
@Matt Joiner: Может быть, вам следует написать лексику самостоятельно или принудительно оценить результаты с помощью DeepSeq.   -  person wuxb    schedule 19.10.2011
comment
@Matt Joiner: в том же пакете есть ленивая версия: «Data.ByteString.Lex.Lazy.Double».   -  person wuxb    schedule 19.10.2011
comment
@Matt Joiner: так тебе нужны куски указанного размера? Возможно повторные вызовы splitAt? Обратите внимание, что toChunks генерирует строгие байтовые строки максимального размера (за исключением, возможно, последнего).   -  person ivanm    schedule 19.10.2011
comment
@MikhailGlushenkov: toChunks возвращает список строгих байтовых строк. Я хочу их всех в одном.   -  person Matt Joiner    schedule 19.10.2011
comment
@WuXingbo: Сейчас я переключился на Lazy readDouble, спасибо. Однако мой вопрос остается в силе.   -  person Matt Joiner    schedule 19.10.2011
comment
Здесь есть недоразумение - ленивая строка байтов является просто списком фрагментов (т.е. строгих строк байтов), по сути. toChunks раскрывает эту структуру. Чтобы поместить весь список в одну строгую байтовую строку, нет другого способа, кроме concat . toChunks (или эквивалента). Во многих типичных случаях список будет состоять из одного элемента — в этих случаях concat . toChunks также будет относительно эффективным.   -  person sclv    schedule 19.10.2011
comment
@sclv: То, что вы описываете, - это то, что мне нужно.   -  person Matt Joiner    schedule 20.10.2011


Ответы (5)


Как сказал @sclv в комментариях выше, ленивая строка байтов — это просто список строгих строк байтов. Существует два подхода к преобразованию ленивой ByteString в строгую (источник: обсуждение списка рассылки haskell о добавлении функции toStrict) — соответствующий код из ветки электронной почты ниже:

Во-первых, соответствующие библиотеки:

import qualified Data.ByteString               as B
import qualified Data.ByteString.Internal      as BI
import qualified Data.ByteString.Lazy          as BL
import qualified Data.ByteString.Lazy.Internal as BLI
import           Foreign.ForeignPtr
import           Foreign.Ptr

Подход 1 (такой же, как @sclv):

toStrict1 :: BL.ByteString -> B.ByteString
toStrict1 = B.concat . BL.toChunks

Подход 2:

toStrict2 :: BL.ByteString -> B.ByteString
toStrict2 BLI.Empty = B.empty
toStrict2 (BLI.Chunk c BLI.Empty) = c
toStrict2 lb = BI.unsafeCreate len $ go lb
  where
    len = BLI.foldlChunks (\l sb -> l + B.length sb) 0 lb

    go  BLI.Empty                   _   = return ()
    go (BLI.Chunk (BI.PS fp s l) r) ptr =
        withForeignPtr fp $ \p -> do
            BI.memcpy ptr (p `plusPtr` s) (fromIntegral l)
            go r (ptr `plusPtr` l)

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

person Sal    schedule 18.12.2011

Пакет bytestring теперь экспортирует функцию toStrict:

http://hackage.haskell.org/packages/archive/bytestring/0.10.2.0/doc/html/Data-ByteString-Lazy.html#v:toStrict

Это может быть не совсем то, что вы хотите, но это, безусловно, отвечает на вопрос в заголовке этого поста :)

person ocharles    schedule 29.11.2012
comment
какая-нибудь подсказка, в какой версии это было добавлено? Кажется, его нет в платформе Haskell 2012.4 (включая ghc 7.4)? - person Emmanuel Touzery; 17.12.2012

Если рассматриваемая ленивая ByteString равна ‹= максимальному размеру строгой ByteString:

toStrict = fromMaybe SB.empty . listToMaybe . toChunks

toChunks делает каждый фрагмент максимально возможным (за исключением, возможно, последнего).

Если размер вашей ленивой ByteString больше, чем может быть строгая ByteString, то это невозможно: именно для этого и нужны ленивые ByteString.

person ivanm    schedule 19.10.2011

Data.ByteString.Lazy.Char8 теперь имеет функции toStrict и fromStrict.

person Jeffrey Benjamin Brown    schedule 09.10.2017
comment
По сути, это дубликат ответа Очарльза. - person dfeuer; 10.10.2017

Вы также можете использовать blaze-builder для создания строгой ByteString из ленивых

toStrict :: BL.ByteString -> BS.ByteString
toStrict = toByteString . fromLazyByteString

Он должен быть эффективным.

person s9gf4ult    schedule 06.04.2013