استبدل بكفاءة جزء من كائن ثنائي

هدفي هو الكتابة بالكتابة فوق عدة أقسام من blob ، مع ترك المحتوى العام الخاص به وهيكل البكر. تحقيقا لهذه الغاية ، لقد كتبت الوظائف التالية:

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

وهذه طريقة عملهم:

λ 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?

سأكون ممتعًا بشكل خاص إذا حدث أننا يمكن أن نستبدل الأقسام المتعددة في وقت أقل من خطي عدد البدائل.

0
إذا كنت تقوم بالكثير من الاستبدالات ، ففكر في التحويل إلى مرحلة البسل البطيئة (التي يكون فيها concat وقتًا ثابتًا). للحصول على أفضل أداء ممكن ، فإن أفضل رهان هو أن تقوم بنسخ عملية الاختبار عن بُعد ، ثم القيام بتبديل بديل على ExternalPtr التابع للنسخة.
وأضاف المؤلف user2407038, مصدر
SimonShine كنت أشير إلى عدد البدائل. سأقوم بتحرير المنشور للإشارة إلى ذلك.
وأضاف المؤلف Ignat Insarov, مصدر
SimonShine سيكون من الرائع إذا كنت تستطيع كتابة إجابة توضح كيفية تنفيذ ذلك مع ST monad. كما أفهم ، سيكون علينا أن ننظر إلى ByteString كمصفوفة ، وأنا غير متأكد إذا كانت صحيحة من الناحية الأخلاقية لأن التمثيل الأساسي قد يتغير ، وما إذا كان من المعقول استخدام صفيف عادي هنا.
وأضاف المؤلف Ignat Insarov, مصدر
SimonShine شكرا لك ، سيمون. سوف أبحث في هذه الروابط الآن. أظن أن التماثل المستمر لنوع الترابط بين سلسلة البايت الصارمة ومجموعة ST سيحل المشكلة ، لكني لست متأكداً من كيفية الحصول على واحدة.
وأضاف المؤلف Ignat Insarov, مصدر
@ user2407038 وكيف يفعل ذلك؟ ولماذا النسخ لا يمكن تجنبه؟ (إذا وعدت بعدم وجود أي جزء آخر من المنطق يهتم بسلسلة بايت معينة ، فهل يمكنني تغييره في مكانه؟) هل من الممكن أن تزعج نفسك لتلخيص كل هذا في إجابة صحيحة؟
وأضاف المؤلف Ignat Insarov, مصدر
@ hegel5000 أنا أقرأه من ملف يحتوي على ByteString.readFile ، لذلك ، لا توجد مشكلة على الإطلاق في إنشاء نسخة. أنا فقط أكون منشد الكمال من أجل قضية فهم القضية بشكل أفضل.
وأضاف المؤلف Ignat Insarov, مصدر
عن طريق خطي يعني خطي يتناسب مع كومة القش بدلا من الإبرة ، أليس كذلك؟ حسنا ، طالما كنت تنتج نسخة مع بعض وحدات البايت المعدلة ، لا يمكنك تجنب ذلك. إذا كنت تريد استبدال مدمر ، في المكان ، قد ترغب في ST monad.
وأضاف المؤلف Simon Shine, مصدر
في وقت لاحق اليوم من خلال إجراء بعض الأبحاث السريعة ، يمكنني إما محاولة الجمع بين ST و STArray من Data.Array.ST ، ولكن الذهاب بين ByteString و STArray له تكلفة. بدلاً من ذلك ، يبدو أن باستخدام Data.Conduit.Binary يتيح لك
وأضاف المؤلف Simon Shine, مصدر
Ignat Insarov كيف تأتي بياناتك في برنامجك؟ لدي شعور قوي بأن صنع نسخة واحدة فقط من المصفوفة من أجل جعل سلسلة من الطفرات هي لا ستكون خطوة تحديد المعدل ، خاصة إذا كانت بياناتك تأتي من القرص ، الشبكة ، أو قضى أي وقت كنوع [Word8] .
وأضاف المؤلف hegel5000, مصدر
لقد ذهبت من كتابة نوع قاعدة البيانات في هاسكل للقيام بالحوسبة العلمية في C ++. لا يحتوي C ++ على GC مما يعني أنه لا يمكنه عمل هياكل بيانات ثابتة (على سبيل المثال [] أو Data.Map ) بدون الكثير من الإعداد. والنتيجة هي أن هناك الكثير من النسخ ، حتى لو كنت لا تسعى للبرمجة الوظيفية البحتة (التي أفعلها). لكنني الآن أضع برامجي كثيرًا ووجدت أن معظم هذه النسخ لا تظهر ، وإذا كان الأمر كذلك ، فهي ليست خطوة النسخ (O) O في المقام الأول ، ولكن المشكلة هي O (1) خطوات التخصيص/إلغاء التخصيص.
وأضاف المؤلف hegel5000, مصدر

1 إجابة

عندما يكون concat خطيًا في حجم القائمة وكل من و إسقاط هي O (1) ، فقد يكون هذا جيدًا كما يحصل :

replace source offset replacement = 
  concat [ take offset source
         , replacement
         , drop n source
         ] 
  where n = offset + length replacement

للحصول على عدد عشوائي من البدائل:

replacemany :: [(Int, ByteString)] -> ByteString -> ByteString
replacemany wss bs = foldr f bs wss where
  f (l, ws) bs = replace bs l ws
0
وأضاف
حسنا ، هذا بالتأكيد مقروء وجميل جدا. لكن ما زلت آمل أن يكون هناك حل أفضل للحل.
وأضاف المؤلف Ignat Insarov, مصدر
أيضا ، أتساءل كيف يمكنك تمديد هذا للعمل مع أزواج استبدال الأوفست متعددة.
وأضاف المؤلف Ignat Insarov, مصدر
لست متأكداً من أنني أرى كيف يجب أن تذهب. هل تمانع في تحرير أفكارك على هذا في الجواب؟ خاصة في الجزء المطفأ O (1).
وأضاف المؤلف Ignat Insarov, مصدر
مع طيات بالطبع :-) حسنا إذا كنت صحيحة ، إذا كنت تأخذ عدم التزاما في الاعتبار يتم إطفاء هذا O (1).
وأضاف المؤلف Regis Kuckaertz, مصدر
اعتقدت أن نوع ByteString عمل بطريقة ما كقائمة ، حيث أنك لن تدفع سوى تكلفة concat فقط عندما تستهلك القائمة فعليًا ، ولكن بعد ذلك بحثت في شفرة المصدر وهي تستخدم memcpy حتى الآن لست متأكدًا. على أي حال ، فقط أضفت بعض الشفرات ، آمل أن تكون مفيدة.
وأضاف المؤلف Regis Kuckaertz, مصدر
لا أرى كيف ستفعل عمليات n دفعة واحدة ، بخلاف استخدام تعليمات SIMD
وأضاف المؤلف Regis Kuckaertz, مصدر