Reputation: 4832
My goal is to efficiently overwrite several sections of a blob, while leaving its overall content and structure pristine. To this end, I have written the following functions:
replace :: ByteString -> Int -> ByteString -> ByteString
replace source offset replacement = prefix <> replacement <> suffix
where
prefix = ByteString.take offset source
suffix = ByteString.drop (offset + ByteString.length replacement) source
fix :: Int -> ByteString -> ByteString -> ByteString
fix offset replacement source = replace source offset replacement
And this is how they work:
λ replace "I have a cat." 0x09 "dog"
"I have a dog."
λ fix 0x0A "fat" . fix 0x03 "dog" $ "My cat is red."
"My dog is fat."
Unfortunately, <>
= append
is linear time, and therefore these functions too. Having the
knowledge that the replacement is just as long as the section being replaced, surely we can do
better?
I would be especially joyful if it happens that we can replace multiple sections in time less than linear over the number of replacements.
Upvotes: 2
Views: 115
Reputation: 991
Given concat
is linear in the size of the list and both take
and drop
are O(1), this may be as good as it gets:
replace source offset replacement =
concat [ take offset source
, replacement
, drop n source
]
where n = offset + length replacement
For an arbitrary number of replacements:
replacemany :: [(Int, ByteString)] -> ByteString -> ByteString
replacemany wss bs = foldr f bs wss where
f (l, ws) bs = replace bs l ws
Upvotes: 2