packages feed

treap (empty) → 0.0.0.0

raw patch · 16 files changed

+1744/−0 lines, 16 filesdep +Globdep +basedep +deepseq

Dependencies added: Glob, base, deepseq, doctest, hspec, hspec-core, mersenne-random-pure64, treap

Files

+ CHANGELOG.md view
@@ -0,0 +1,11 @@+# Changelog++`treap` uses [PVP Versioning][1].+The changelog is available [on GitHub][2].++## 0.0.0.0 — Apr 29, 2019++* Initially created.++[1]: https://pvp.haskell.org+[2]: https://github.com/chshersh/treap/releases
+ LICENSE view
@@ -0,0 +1,373 @@+Mozilla Public License Version 2.0+==================================++1. Definitions+--------------++1.1. "Contributor"+    means each individual or legal entity that creates, contributes to+    the creation of, or owns Covered Software.++1.2. "Contributor Version"+    means the combination of the Contributions of others (if any) used+    by a Contributor and that particular Contributor's Contribution.++1.3. "Contribution"+    means Covered Software of a particular Contributor.++1.4. "Covered Software"+    means Source Code Form to which the initial Contributor has attached+    the notice in Exhibit A, the Executable Form of such Source Code+    Form, and Modifications of such Source Code Form, in each case+    including portions thereof.++1.5. "Incompatible With Secondary Licenses"+    means++    (a) that the initial Contributor has attached the notice described+        in Exhibit B to the Covered Software; or++    (b) that the Covered Software was made available under the terms of+        version 1.1 or earlier of the License, but not also under the+        terms of a Secondary License.++1.6. "Executable Form"+    means any form of the work other than Source Code Form.++1.7. "Larger Work"+    means a work that combines Covered Software with other material, in+    a separate file or files, that is not Covered Software.++1.8. "License"+    means this document.++1.9. "Licensable"+    means having the right to grant, to the maximum extent possible,+    whether at the time of the initial grant or subsequently, any and+    all of the rights conveyed by this License.++1.10. "Modifications"+    means any of the following:++    (a) any file in Source Code Form that results from an addition to,+        deletion from, or modification of the contents of Covered+        Software; or++    (b) any new file in Source Code Form that contains any Covered+        Software.++1.11. "Patent Claims" of a Contributor+    means any patent claim(s), including without limitation, method,+    process, and apparatus claims, in any patent Licensable by such+    Contributor that would be infringed, but for the grant of the+    License, by the making, using, selling, offering for sale, having+    made, import, or transfer of either its Contributions or its+    Contributor Version.++1.12. "Secondary License"+    means either the GNU General Public License, Version 2.0, the GNU+    Lesser General Public License, Version 2.1, the GNU Affero General+    Public License, Version 3.0, or any later versions of those+    licenses.++1.13. "Source Code Form"+    means the form of the work preferred for making modifications.++1.14. "You" (or "Your")+    means an individual or a legal entity exercising rights under this+    License. For legal entities, "You" includes any entity that+    controls, is controlled by, or is under common control with You. For+    purposes of this definition, "control" means (a) the power, direct+    or indirect, to cause the direction or management of such entity,+    whether by contract or otherwise, or (b) ownership of more than+    fifty percent (50%) of the outstanding shares or beneficial+    ownership of such entity.++2. License Grants and Conditions+--------------------------------++2.1. Grants++Each Contributor hereby grants You a world-wide, royalty-free,+non-exclusive license:++(a) under intellectual property rights (other than patent or trademark)+    Licensable by such Contributor to use, reproduce, make available,+    modify, display, perform, distribute, and otherwise exploit its+    Contributions, either on an unmodified basis, with Modifications, or+    as part of a Larger Work; and++(b) under Patent Claims of such Contributor to make, use, sell, offer+    for sale, have made, import, and otherwise transfer either its+    Contributions or its Contributor Version.++2.2. Effective Date++The licenses granted in Section 2.1 with respect to any Contribution+become effective for each Contribution on the date the Contributor first+distributes such Contribution.++2.3. Limitations on Grant Scope++The licenses granted in this Section 2 are the only rights granted under+this License. No additional rights or licenses will be implied from the+distribution or licensing of Covered Software under this License.+Notwithstanding Section 2.1(b) above, no patent license is granted by a+Contributor:++(a) for any code that a Contributor has removed from Covered Software;+    or++(b) for infringements caused by: (i) Your and any other third party's+    modifications of Covered Software, or (ii) the combination of its+    Contributions with other software (except as part of its Contributor+    Version); or++(c) under Patent Claims infringed by Covered Software in the absence of+    its Contributions.++This License does not grant any rights in the trademarks, service marks,+or logos of any Contributor (except as may be necessary to comply with+the notice requirements in Section 3.4).++2.4. Subsequent Licenses++No Contributor makes additional grants as a result of Your choice to+distribute the Covered Software under a subsequent version of this+License (see Section 10.2) or under the terms of a Secondary License (if+permitted under the terms of Section 3.3).++2.5. Representation++Each Contributor represents that the Contributor believes its+Contributions are its original creation(s) or it has sufficient rights+to grant the rights to its Contributions conveyed by this License.++2.6. Fair Use++This License is not intended to limit any rights You have under+applicable copyright doctrines of fair use, fair dealing, or other+equivalents.++2.7. Conditions++Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted+in Section 2.1.++3. Responsibilities+-------------------++3.1. Distribution of Source Form++All distribution of Covered Software in Source Code Form, including any+Modifications that You create or to which You contribute, must be under+the terms of this License. You must inform recipients that the Source+Code Form of the Covered Software is governed by the terms of this+License, and how they can obtain a copy of this License. You may not+attempt to alter or restrict the recipients' rights in the Source Code+Form.++3.2. Distribution of Executable Form++If You distribute Covered Software in Executable Form then:++(a) such Covered Software must also be made available in Source Code+    Form, as described in Section 3.1, and You must inform recipients of+    the Executable Form how they can obtain a copy of such Source Code+    Form by reasonable means in a timely manner, at a charge no more+    than the cost of distribution to the recipient; and++(b) You may distribute such Executable Form under the terms of this+    License, or sublicense it under different terms, provided that the+    license for the Executable Form does not attempt to limit or alter+    the recipients' rights in the Source Code Form under this License.++3.3. Distribution of a Larger Work++You may create and distribute a Larger Work under terms of Your choice,+provided that You also comply with the requirements of this License for+the Covered Software. If the Larger Work is a combination of Covered+Software with a work governed by one or more Secondary Licenses, and the+Covered Software is not Incompatible With Secondary Licenses, this+License permits You to additionally distribute such Covered Software+under the terms of such Secondary License(s), so that the recipient of+the Larger Work may, at their option, further distribute the Covered+Software under the terms of either this License or such Secondary+License(s).++3.4. Notices++You may not remove or alter the substance of any license notices+(including copyright notices, patent notices, disclaimers of warranty,+or limitations of liability) contained within the Source Code Form of+the Covered Software, except that You may alter any license notices to+the extent required to remedy known factual inaccuracies.++3.5. Application of Additional Terms++You may choose to offer, and to charge a fee for, warranty, support,+indemnity or liability obligations to one or more recipients of Covered+Software. However, You may do so only on Your own behalf, and not on+behalf of any Contributor. You must make it absolutely clear that any+such warranty, support, indemnity, or liability obligation is offered by+You alone, and You hereby agree to indemnify every Contributor for any+liability incurred by such Contributor as a result of warranty, support,+indemnity or liability terms You offer. You may include additional+disclaimers of warranty and limitations of liability specific to any+jurisdiction.++4. Inability to Comply Due to Statute or Regulation+---------------------------------------------------++If it is impossible for You to comply with any of the terms of this+License with respect to some or all of the Covered Software due to+statute, judicial order, or regulation then You must: (a) comply with+the terms of this License to the maximum extent possible; and (b)+describe the limitations and the code they affect. Such description must+be placed in a text file included with all distributions of the Covered+Software under this License. Except to the extent prohibited by statute+or regulation, such description must be sufficiently detailed for a+recipient of ordinary skill to be able to understand it.++5. Termination+--------------++5.1. The rights granted under this License will terminate automatically+if You fail to comply with any of its terms. However, if You become+compliant, then the rights granted under this License from a particular+Contributor are reinstated (a) provisionally, unless and until such+Contributor explicitly and finally terminates Your grants, and (b) on an+ongoing basis, if such Contributor fails to notify You of the+non-compliance by some reasonable means prior to 60 days after You have+come back into compliance. Moreover, Your grants from a particular+Contributor are reinstated on an ongoing basis if such Contributor+notifies You of the non-compliance by some reasonable means, this is the+first time You have received notice of non-compliance with this License+from such Contributor, and You become compliant prior to 30 days after+Your receipt of the notice.++5.2. If You initiate litigation against any entity by asserting a patent+infringement claim (excluding declaratory judgment actions,+counter-claims, and cross-claims) alleging that a Contributor Version+directly or indirectly infringes any patent, then the rights granted to+You by any and all Contributors for the Covered Software under Section+2.1 of this License shall terminate.++5.3. In the event of termination under Sections 5.1 or 5.2 above, all+end user license agreements (excluding distributors and resellers) which+have been validly granted by You or Your distributors under this License+prior to termination shall survive termination.++************************************************************************+*                                                                      *+*  6. Disclaimer of Warranty                                           *+*  -------------------------                                           *+*                                                                      *+*  Covered Software is provided under this License on an "as is"       *+*  basis, without warranty of any kind, either expressed, implied, or  *+*  statutory, including, without limitation, warranties that the       *+*  Covered Software is free of defects, merchantable, fit for a        *+*  particular purpose or non-infringing. The entire risk as to the     *+*  quality and performance of the Covered Software is with You.        *+*  Should any Covered Software prove defective in any respect, You     *+*  (not any Contributor) assume the cost of any necessary servicing,   *+*  repair, or correction. This disclaimer of warranty constitutes an   *+*  essential part of this License. No use of any Covered Software is   *+*  authorized under this License except under this disclaimer.         *+*                                                                      *+************************************************************************++************************************************************************+*                                                                      *+*  7. Limitation of Liability                                          *+*  --------------------------                                          *+*                                                                      *+*  Under no circumstances and under no legal theory, whether tort      *+*  (including negligence), contract, or otherwise, shall any           *+*  Contributor, or anyone who distributes Covered Software as          *+*  permitted above, be liable to You for any direct, indirect,         *+*  special, incidental, or consequential damages of any character      *+*  including, without limitation, damages for lost profits, loss of    *+*  goodwill, work stoppage, computer failure or malfunction, or any    *+*  and all other commercial damages or losses, even if such party      *+*  shall have been informed of the possibility of such damages. This   *+*  limitation of liability shall not apply to liability for death or   *+*  personal injury resulting from such party's negligence to the       *+*  extent applicable law prohibits such limitation. Some               *+*  jurisdictions do not allow the exclusion or limitation of           *+*  incidental or consequential damages, so this exclusion and          *+*  limitation may not apply to You.                                    *+*                                                                      *+************************************************************************++8. Litigation+-------------++Any litigation relating to this License may be brought only in the+courts of a jurisdiction where the defendant maintains its principal+place of business and such litigation shall be governed by laws of that+jurisdiction, without reference to its conflict-of-law provisions.+Nothing in this Section shall prevent a party's ability to bring+cross-claims or counter-claims.++9. Miscellaneous+----------------++This License represents the complete agreement concerning the subject+matter hereof. If any provision of this License is held to be+unenforceable, such provision shall be reformed only to the extent+necessary to make it enforceable. Any law or regulation which provides+that the language of a contract shall be construed against the drafter+shall not be used to construe this License against a Contributor.++10. Versions of the License+---------------------------++10.1. New Versions++Mozilla Foundation is the license steward. Except as provided in Section+10.3, no one other than the license steward has the right to modify or+publish new versions of this License. Each version will be given a+distinguishing version number.++10.2. Effect of New Versions++You may distribute the Covered Software under the terms of the version+of the License under which You originally received the Covered Software,+or under the terms of any subsequent version published by the license+steward.++10.3. Modified Versions++If you create software not governed by this License, and you want to+create a new license for such software, you may create and use a+modified version of this License if you rename the license and remove+any references to the name of the license steward (except to note that+such modified license differs from this License).++10.4. Distributing Source Code Form that is Incompatible With Secondary+Licenses++If You choose to distribute Source Code Form that is Incompatible With+Secondary Licenses under the terms of this version of the License, the+notice described in Exhibit B of this License must be attached.++Exhibit A - Source Code Form License Notice+-------------------------------------------++  This Source Code Form is subject to the terms of the Mozilla Public+  License, v. 2.0. If a copy of the MPL was not distributed with this+  file, You can obtain one at http://mozilla.org/MPL/2.0/.++If it is not possible or desirable to put the notice in a particular+file, then You may include the notice in a location (such as a LICENSE+file in a relevant directory) where a recipient would be likely to look+for such a notice.++You may add additional accurate notices of copyright ownership.++Exhibit B - "Incompatible With Secondary Licenses" Notice+---------------------------------------------------------++  This Source Code Form is "Incompatible With Secondary Licenses", as+  defined by the Mozilla Public License, v. 2.0.
+ README.md view
@@ -0,0 +1,73 @@+# treap++![Treap: tree logo](https://user-images.githubusercontent.com/4276606/56883228-9f32f180-6a98-11e9-9554-13735ff1ed30.png)+[![Hackage](https://img.shields.io/hackage/v/treap.svg)](https://hackage.haskell.org/package/treap)+[![Build status](https://secure.travis-ci.org/chshersh/treap.svg)](https://travis-ci.org/chshersh/treap)+[![MPL-2.0 license](https://img.shields.io/badge/license-MPL--2.0-blue.svg)](LICENSE)++Efficient implementation of the implicit treap data structure.++## What does this package provide?++This package implements a tree-like data structure called _implicit treap_. This+data structure implements interface similar to random-access arrays, but with+fast (logarithmic time complexity)+`insert`/`delete`/`split`/`merge`/`take`/`drop`/`rotate` operations. In addition,+_treap_ allows you to specify and measure values of any monoids on a segment,+like a sum of elements or minimal element on some contiguous part of the array.++## When to use this package?++Use this package when you want the following operations to be fast:++1. Access elements by index.+2. Insert elements by index.+3. Delete elements by index.+4. Calculate monoidal operation (like sum, product, min, etc.) of all elements+   between two indices.+5. Call slicing operations like `take` or `drop` or `split`.++Below you can find the table of time complexity for all operations (where `n` is+the size of the treap):++| Operation | Time complexity | Description                          |+|-----------|-----------------|--------------------------------------|+| `size`    | `O(1)`          | Get number of elements in the treap  |+| `at`      | `O(log n)`      | Access by index                      |+| `insert`  | `O(log n)`      | Insert by index                      |+| `delete`  | `O(log n)`      | Delete by index                      |+| `query`   | `O(log n)`      | Measure monoid on the segment        |+| `splitAt` | `O(log n)`      | Split treap by index into two treaps |+| `merge`   | `O(log n)`      | Merge two treaps into a single one   |+| `take`    | `O(log n)`      | Take first `i` elements of the treap |+| `drop`    | `O(log n)`      | Drop first `i` elements of the treap |+| `rotate`  | `O(log n)`      | Put first `i` elements to the end    |++The package also comes with nice pretty-printing!++```haskell+ghci> t = fromList [1..5] :: RTreap (Sum Int) Int+ghci> prettyPrint t+   5,15:2+      ╱╲+     ╱  ╲+    ╱    ╲+   ╱      ╲+1,1:1   3,12:4+          ╱╲+         ╱  ╲+        ╱    ╲+      1,3:3 1,5:5++```++## Alternatives++If you don't need to calculate monoidal operations, you may alternatively use+[`Seq`](https://hackage.haskell.org/package/containers-0.6.0.1/docs/Data-Sequence.html#t:Seq)+from the `containers` package as it provides more extended interface but doesn't+allow to measure monoidal values on segments.++## Acknowledgement++Icons made by [Freepik](http://www.freepik.com) from [www.flaticon.com](https://www.flaticon.com/) is licensed by [CC 3.0 BY](http://creativecommons.org/licenses/by/3.0/).
+ src/Treap.hs view
@@ -0,0 +1,94 @@+{- |++== General description++Package @treap@ implements a tree-like data structure called /implicit treap/. This+data structure implements interface similar to random-access arrays, but with+fast (logarithmic time complexity)+@'insert'@ \/ @'delete'@ \/ @'Treap.splitAt'@ \/ @'merge'@ \/ @'Treap.take'@ \/ @'Treap.drop'@ \/ @'rotate'@ operations.++In addition, 'Treap.Pure.Treap' and 'RTreap' allow you to specify and measure+values of any monoids on a segment, like a sum of elements or minimal element on+some contiguous part of the array.++== Package structure++This package contains the following modules:++* __"Treap.Measured":__ typeclass 'Measured' that allows telling how to measure+  tree values as monoids.+* __"Treap.Pure":__ the 'Treap.Pure.Treap' data type and functions – pure+  implementation of the implicit treap data structure.+* __"Treap.Rand":__ the 'RTreap' data type and functions – pure implementation+  of the implicit treap which uses a pure random generator to generate+  priorities automatically.+* __"Treap.Pretty":__ pretty-printer for the treap.++Module __"Treap"__ reexports only __"Treap.Measured"__ and __"Treap.Rand"__ modules.++== Usage example++Consider the following example of creating 'RTreap' from list @[1..5]@ where+each element stores the sum of elements in its subtree:++>>> import Data.Monoid (Sum (..))+>>> import GHC.Exts (IsList (..))+>>> t = fromList [1..5] :: RTreap (Sum Int) Int+>>> prettyPrint t+   5,15:2+      ╱╲+     ╱  ╲+    ╱    ╲+   ╱      ╲+1,1:1   3,12:4+          ╱╲+         ╱  ╲+        ╱    ╲+      1,3:3 1,5:5++Each node shows:++1. The overall size of the tree+2. The total monoidal measure of the tree+3. The element itself after @:@++You can try to play with this tree now!++>>> at 0 t+Just 1+>>> at 10 t+Nothing+>>> query 1 4 t+Sum {getSum = 9}++>>> prettyPrint $ Treap.take 2 t+ 2,3:2+  ╱+1,1:1++>>> prettyPrint $ Treap.drop 2 t+  3,12:4+    ╱╲+   ╱  ╲+  ╱    ╲+1,3:3 1,5:5++>>> prettyPrint $ rotate 2 t+   5,15:2+     ╱+  4,13:4+    ╱╲+   ╱  ╲+  ╱    ╲+1,3:3 2,6:5+         ╲+       1,1:1++-}++module Treap+       ( module Treap+       ) where++import Treap.Measured as Treap+import Treap.Rand as Treap
+ src/Treap/Measured.hs view
@@ -0,0 +1,73 @@+{-# LANGUAGE FlexibleInstances #-}++{- | Typeclass that tells how to measure different values as 'Monoid'.+-}++module Treap.Measured+       ( Measured (..)+       ) where++import Data.Functor.Identity (Identity (..))+import Data.Monoid (All (..), Any (..), Dual (..), Endo (..), First (..), Last (..), Product (..),+                    Sum (..))+import Data.Semigroup (Max (..), Min (..))+++{- | This typeclass allows to specify how to convert value of type @a@ into+monoidal value of type @m@.+-}+class Monoid m => Measured m a where+    measure :: a -> m++-- | Measure every 'Monoid' as itself.+instance Monoid a => Measured (Identity a) a where+    measure = Identity+    {-# INLINE measure #-}++-- | Measure every 'Monoid' as its dual.+instance Monoid a => Measured (Dual a) a where+    measure = Dual+    {-# INLINE measure #-}++-- | Measure every endomorphic function with compostion.+instance Measured (Endo a) (a -> a) where+    measure = Endo+    {-# INLINE measure #-}++-- | Measure every numeric value with addition.+instance Num a => Measured (Sum a) a where+    measure = Sum+    {-# INLINE measure #-}++-- | Measure every numeric value with multiplication.+instance Num a => Measured (Product a) a where+    measure = Product+    {-# INLINE measure #-}++-- | Measure every comparable value with minimum.+instance (Ord a, Bounded a) => Measured (Min a) a where+    measure = Min+    {-# INLINE measure #-}++-- | Measure every comparable value with maximum.+instance (Ord a, Bounded a) => Measured (Max a) a where+    measure = Max+    {-# INLINE measure #-}++-- | Measure every value as the 'First' monoid.+instance Measured (First a) a where+    measure = First . Just+    {-# INLINE measure #-}++-- | Measure every value as the 'Last' monoid.+instance Measured (Last a) a where+    measure = Last . Just+    {-# INLINE measure #-}++-- | Measure boolean value with '&&'.+instance Measured All Bool where+    measure = All++-- | Measure boolean value with '||'.+instance Measured Any Bool where+    measure = Any
+ src/Treap/Pretty.hs view
@@ -0,0 +1,182 @@+-- | Very nice 'Treap' visualisation.++module Treap.Pretty+       ( pretty+       , prettyPrint+       , prettyWith+       , compactShowNode++         -- * Internal implementation details+       , BinTree (..)+       , showTree+       , middleLabelPos+       , branchLines+       ) where++import Data.Char (isSpace)+import Data.Coerce (Coercible, coerce)+import Data.List (dropWhileEnd, intercalate)++import Treap.Pure (Priority (..), Size (..), Treap (..))+++{- | Show 'Treap' in a pretty way using 'compactShowNode' function.+-}+pretty :: forall m a . (Coercible m a, Show a) => Treap m a -> String+pretty = prettyWith compactShowNode++-- | Call 'pretty' function and output the result directly to @stdout@.+prettyPrint :: forall m a . (Coercible m a, Show a) => Treap m a -> IO ()+prettyPrint = putStrLn . pretty++{- | Show 'Treap' node in a format:++@+\<size\>,\<acc\>:a+@+-}+compactShowNode+    :: forall m a . (Coercible m a, Show a)+    => Size+    -> Priority+    -> m+    -> a+    -> String+compactShowNode (Size sz) _ m a =+    show sz ++ "," ++ show (coerce @m @a m) ++ ":" ++ show a++-- | Show 'Treap' in a nice way using given function to display node.+prettyWith+    :: forall m a .+       (Size -> Priority -> m -> a -> String)+    -> Treap m a+    -> String+prettyWith display = showTree . toBinTree+  where+    toBinTree :: Treap m a -> BinTree+    toBinTree Empty = Leaf+    toBinTree (Node sz p m a left right) = Branch (display sz p m a) (toBinTree left) (toBinTree right)++-- | Intermidiate structure to help string conversion.+data BinTree+    = Leaf+    | Branch String BinTree BinTree++-- | Hardcore function responsible for pretty showing of the 'BinTree' data type.+showTree :: BinTree -> String+showTree Leaf                  = ""+showTree (Branch label left right) = case (left, right) of+    (Leaf, Leaf) -> label++    (_, Leaf) -> toLines $+        [ spaces rootShiftOnlyLeft   ++ label+        , spaces branchShiftOnlyLeft ++ "╱"+        ] ++ map (spaces leftShiftOnlyLeft ++) leftLines++    (Leaf, _) -> toLines $+        [ spaces rootShiftOnlyRight   ++ label+        , spaces branchShiftOnlyRight ++ "╲"+        ] ++ map (spaces rightShiftOnlyRight ++) rightLines++    (_, _) -> toLines $+        [ spaces rootOffset ++ label+        ]+        ++ map (spaces rootOffset ++ ) (branchLines branchHeight)+        ++ map (spaces childrenOffset ++) (zipChildren leftLines rightLines)+  where+    leftStr, rightStr :: String+    leftStr  = showTree left+    rightStr = showTree right++    leftLines :: [String]+    leftLines  = lines leftStr+    rightLines = lines rightStr++    rootLabelMiddle, leftLabelMiddle, rightLabelMiddle :: Int+    rootLabelMiddle  = middleLabelPos label+    leftLabelMiddle  = middleLabelPos $ head leftLines+    rightLabelMiddle = middleLabelPos $ head rightLines++    -- Case 1: all offsets when node has only left branch+    rootShiftOnlyLeft, leftShiftOnlyLeft, branchShiftOnlyLeft :: Int+    (rootShiftOnlyLeft, leftShiftOnlyLeft) = case compare rootLabelMiddle leftLabelMiddle of+        EQ -> (1, 0)+        GT -> (0, rootLabelMiddle - leftLabelMiddle - 1)+        LT -> (leftLabelMiddle - rootLabelMiddle + 1, 0)+    branchShiftOnlyLeft = rootLabelMiddle + rootShiftOnlyLeft - 1++    -- Case 2: all offsets when node has only right branch+    rootShiftOnlyRight, rightShiftOnlyRight, branchShiftOnlyRight :: Int+    (rootShiftOnlyRight, rightShiftOnlyRight) = case compare rootLabelMiddle rightLabelMiddle of+        EQ -> (0, 1)+        GT -> (0, rootLabelMiddle - rightLabelMiddle + 1)+        LT -> (rightLabelMiddle - rootLabelMiddle - 1, 0)+    branchShiftOnlyRight = rootLabelMiddle + rootShiftOnlyRight + 1++    -- Case 3: both+    leftWidth, rightOffMiddle, childDistance, branchHeight, rootMustMiddle :: Int+    leftWidth      = 1 + maximum (map length leftLines)+    rightOffMiddle = leftWidth + rightLabelMiddle+    childDistance  = rightOffMiddle - leftLabelMiddle+    branchHeight   = childDistance `div` 2+    rootMustMiddle = (leftLabelMiddle + rightOffMiddle) `div` 2++    rootOffset, childrenOffset :: Int+    (rootOffset, childrenOffset) = case compare rootLabelMiddle rootMustMiddle of+        EQ -> (0, 0)+        LT -> (rootMustMiddle - rootLabelMiddle, 0)+        GT -> (0, rootLabelMiddle - rootMustMiddle)++    zipChildren :: [String] -> [String] -> [String]+    zipChildren l []          = l+    zipChildren [] r          = map (spaces leftWidth ++ ) r+    zipChildren (x:xs) (y:ys) =+        let xLen = length x+            newX = x ++ spaces (leftWidth - xLen)+        in (newX ++ y) : zipChildren xs ys++-- | Generates strings containing of @n@ spaces.+spaces :: Int -> String+spaces n = replicate n ' '++{- | Calculates position of middle of non-space part of the string.++>>> s = "   abc "+>>> length s+7+>>> middleLabelPos s+4+-}+middleLabelPos :: String -> Int+middleLabelPos s =+    let (spacePrefix, rest) = span isSpace s+    in length spacePrefix + (length (dropWhileEnd isSpace rest) `div` 2)++-- | Like 'unlines' but doesn't add "\n" to the end.+toLines :: [String] -> String+toLines = intercalate "\n"++{- | Draws branches of the given height.++>>> putStrLn $ toLines $ branchLines 1+╱╲++>>> putStrLn $ toLines $ branchLines 2+ ╱╲+╱  ╲++>>> putStrLn $ toLines $ branchLines 3+  ╱╲+ ╱  ╲+╱    ╲+-}+branchLines :: Int -> [String]+branchLines n = go 0+  where+    go :: Int -> [String]+    go i+        | i == n    = []+        | otherwise = line : go (i + 1)+      where+        line :: String+        line = spaces (n - i - 1) ++ "╱" ++ spaces (2 * i) ++ "╲"
+ src/Treap/Pure.hs view
@@ -0,0 +1,368 @@+{- | Pure efficient implementation of the implicit treap data structure with the+segment tree interface.++__NOTE:__ Letter \( d \) in the documentation below means depth of the tree. Real+depth depends on the strategy for creating 'Priority'. If the strategy is poor,+the depth can be linear. However, if priorities are generated randomly, expected+depth is \( O(\log \ n) \).+-}++{-# LANGUAGE DeriveAnyClass    #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE TypeFamilies      #-}++module Treap.Pure+       ( -- * Data structure+         Size (..)+       , Priority (..)+       , Treap (..)++         -- * Smart constructors+       , empty+       , one++         -- * Query functions+       , size+       , sizeInt+       , monoid+       , at+       , query++         -- * Cuts and joins+       , splitAt+       , merge+       , take+       , drop+       , rotate++         -- * Modification functions+       , insert+       , delete++         -- * Core internal functions+       , recalculate+       ) where++import Prelude hiding (drop, lookup, splitAt, take)++import Control.DeepSeq (NFData)+import Data.Foldable (foldl')+import Data.Word (Word64)+import GHC.Exts (IsList (..))+import GHC.Generics (Generic)++import Treap.Measured (Measured (..))++-- $setup+-- >>> import Data.Monoid+-- >>> import Treap.Pretty++----------------------------------------------------------------------------+-- Data structure and instances+----------------------------------------------------------------------------++{- | Size of the 'Treap' data structure. Guaranteed to be always non-negative.+-}+newtype Size = Size+    { unSize :: Int+    } deriving stock (Show, Read, Generic)+      deriving newtype (Eq, Ord, Num, NFData)++{- | Priority in the 'Treap' data structure.+-}+newtype Priority = Priority+    { unPriority :: Word64+    } deriving stock (Show, Read, Generic)+      deriving newtype (Eq, Ord, NFData)++-- | 'Treap' data structure.+data Treap m a+    = Node !Size !Priority !m a !(Treap m a) !(Treap m a)+    | Empty+    deriving stock (Show, Read, Eq, Generic, Foldable)+    deriving anyclass (NFData)++-- | \( O(1) \). Takes cached value from the root.+instance Monoid m => Measured m (Treap m a) where+    measure = monoid+    {-# INLINE measure #-}++-- #if __GLASGOW_HASKELL__ >= 806+-- -- | Safe 'Functor' instance that performs recalculation of monoidal accumulator.+-- instance (forall b . Measured m b) => Functor (Treap m) where+--     fmap :: forall a b . (a -> b) -> Treap m a -> Treap m b+--     fmap f = go+--       where+--         go :: Treap m a -> Treap m b+--         go Empty = Empty+--         go (Node _ p _ a l r) = recalculate $ new p (f a) (go l) (go r)+-- #endif++{- | This instance allows to create 'Treap' from the list of triples. If all+priorities are random then the expected performance of the @fromList@ function+is \( O(n\ \log \ n)\).++__TODO:__ It's possible to implement \( O(n) \) algorithm however.+See issue #15: <https://github.com/chshersh/treap/issues/15>+-}+instance Measured m a => IsList (Treap m a) where+    type Item (Treap m a) = (Priority, a)++    -- TODO: implement O(n) algorithm+    fromList :: [(Priority, a)] -> Treap m a+    fromList =+        foldl' (\t (i, p, a) -> insert i p a t) Empty+        . zipWith (\i (p, a) -> (i, p, a)) [0..]+    {-# INLINE fromList #-}++    -- TODO: make more efficient+    toList :: Treap m a -> [(Priority, a)]+    toList Empty              = []+    toList (Node _ p _ a l r) = toList l ++ (p, a) : toList r++----------------------------------------------------------------------------+-- Smart constructors+----------------------------------------------------------------------------++-- | \( O(1) \). Creates empty 'Treap'.+empty :: Treap m a+empty = Empty+{-# INLINE empty #-}++-- | \( O(1) \). Creates singleton 'Treap'.+one :: Measured m a => Priority -> a -> Treap m a+one p a = Node (Size 1) p (measure a) a Empty Empty+{-# INLINE one #-}++----------------------------------------------------------------------------+-- Query functions+----------------------------------------------------------------------------++{- | \( O(1) \). Returns the number of the elements in the 'Treap'. Always+non-negative.++__Properties:__++* \( \forall (t\ ::\ \mathrm{Treap}\ m\ a)\ .\ \mathrm{size}\ t \geqslant 0 \)+-}+size :: Treap m a -> Size+size = \case+    Empty -> Size 0+    Node s _ _ _ _ _ -> s+{-# INLINE size #-}++-- | Take size of the 'Treap' as 'Int'.+sizeInt :: Treap m a -> Int+sizeInt = unSize . size+{-# INLINE sizeInt #-}++-- | \( O(1) \). Returns accumulated value in the root of the tree.+monoid :: Monoid m => Treap m a -> m+monoid = \case+    Empty -> mempty+    Node _ _ m _ _ _ -> m+{-# INLINE monoid #-}++-- | \( O(d) \). Lookup a value inside 'Treap' by a given index.+at :: forall m a . Int -> Treap m a -> Maybe a+at i t+    | i < 0          = Nothing+    | i >= sizeInt t = Nothing+    | otherwise      = go i t+  where+    go :: Int -> Treap m a -> Maybe a+    go _ Empty = Nothing+    go k (Node _ _ _ a l r) =+        let lSize = sizeInt l+        in case compare k lSize of+            EQ -> Just a+            LT -> go k l+            GT -> go (k - lSize - 1) r++-- | \( O(d) \). Return value of monoidal accumulator on a segment @[l, r)@.+query :: forall m a . Measured m a => Int -> Int -> Treap m a -> m+query from to t+    | to <= from = mempty+    | otherwise  =+        let (l, _) = splitAt to t+            (_, m) = splitAt from l+        in monoid m++----------------------------------------------------------------------------+-- Cuts and joins+----------------------------------------------------------------------------++-- | Create new 'Node' and recalculate its values.+new :: Measured m a => Priority -> a -> Treap m a -> Treap m a -> Treap m a+new p a l r = recalculate $ Node 0 p mempty a l r+{-# INLINE new #-}++{- | \( O(d) \). @splitAt i t@ splits 'Treap' by the given index into two treaps+@(t1, t2)@ such that the following properties hold:++1. \( \mathrm{size}\ t_1 = i \)+2. \( \mathrm{size}\ t_2 = n - i \)+3. \( \mathrm{merge}\ t_1\ t_2 \equiv t \)++__Special cases:__++1. If \( i \leqslant 0 \) then the result is @('empty', t)@.+2. If \( i \geqslant n \) then the result is @(t, 'empty')@.+-}+splitAt :: forall m a . Measured m a => Int -> Treap m a -> (Treap m a, Treap m a)+splitAt i t+    | i <= 0         = (empty, t)+    | i >= sizeInt t = (t, empty)+    | otherwise      = go i t+  where+    go :: Int -> Treap m a -> (Treap m a, Treap m a)+    go k = \case+        Empty -> (Empty, Empty)+        Node _ p _ a left right ->+            let lSize = sizeInt left+            in case compare k lSize of+                EQ -> (left, new p a Empty right)+                LT ->+                    let (!t1, !newLeft) = go k left+                    in (t1, new p a newLeft right)+                GT ->+                    let (!newRight, !t2) = go (k - lSize - 1) right+                    in (new p a left newRight, t2)++{- | \( O(\max\ d_1\ d_2) \). Merge two 'Treap's into single one.++>>> pone p a = one (Priority p) a :: Treap (Sum Int) Int+>>> prettyPrint $ merge (merge (pone 1 3) (pone 4 5)) (merge (pone 3 0) (pone 5 9))+   4,17:9+     ╱+   3,8:5+     ╱╲+    ╱  ╲+   ╱    ╲+1,3:3 1,0:0+-}+merge :: Measured m a => Treap m a -> Treap m a -> Treap m a+merge Empty r = r+merge l Empty = l+merge l@(Node _ p1 _ a1 l1 r1) r@(Node _ p2 _ a2 l2 r2)+    | p1 > p2   = recalculate $ new p1 a1 l1 (merge r1 r)+    | otherwise = recalculate $ new p2 a2 (merge l l2) r2++{- | \( O(d) \). @'take' n t@ returns 'Treap' that contains first @n@ elements of the given+'Treap' @t@.++__Special cases:__++1. If \( i \leqslant 0 \) then the result is 'empty'.+2. If \( i \geqslant n \) then the result is @t@.+-}+take :: forall m a . Measured m a => Int -> Treap m a -> Treap m a+take n t+    | n <= 0         = Empty+    | n >= sizeInt t = t+    | otherwise      = go n t+  where+    go :: Int -> Treap m a -> Treap m a+    go _ Empty = Empty+    go 0 _     = Empty+    go i (Node _ p _ a l r) =+        let lSize = sizeInt l+        in case compare i lSize of+            LT -> go i l+            EQ -> l+            GT -> new p a l $ go (i - lSize - 1) r++{- | \( O(d) \). @'drop' n t@ returns 'Treap' without first @n@ elements of the given+'Treap' @t@.++__Special cases:__++1. If \( i \leqslant 0 \) then the result is @t@.+2. If \( i \geqslant n \) then the result is 'empty'.+-}+drop :: forall m a . Measured m a => Int -> Treap m a -> Treap m a+drop n t+    | n <= 0         = t+    | n >= sizeInt t = Empty+    | otherwise      = go n t+  where+    go :: Int -> Treap m a -> Treap m a+    go _ Empty = Empty+    go 0 tree  = tree+    go i (Node _ p _ a l r) =+        let lSize = sizeInt l+        in case compare i lSize of+            LT -> new p a (go i l) r+            EQ -> new p a Empty r+            GT -> go (i - lSize - 1) r++{- | \( O(d) \). Rotate a 'Treap' to the right by a given number of elements+modulo treap size. In simple words, @'rotate' n t@ takes first @n@ elements of+@t@ and puts them at the end of @t@ in the same order. If the given index is+negative, then this function rotates left.+-}+rotate :: forall m a . Measured m a => Int -> Treap m a -> Treap m a+rotate n t = case t of+    Empty -> Empty+    _ | n == 0    -> t+      | otherwise -> let (left, right) = splitAt shift t in merge right left+  where+    shift :: Int+    shift = n `mod` sizeInt t++----------------------------------------------------------------------------+-- Modification functions+----------------------------------------------------------------------------++{- | \( O(d) \). Insert a value into 'Treap' with given key and priority.+Updates monoidal accumulator accordingly.+-}+insert :: forall m a . Measured m a => Int -> Priority -> a -> Treap m a -> Treap m a+insert i p a t+    | i < 0          = go 0 t+    | i >= sizeInt t = go (sizeInt t) t+    | otherwise      = go i t+  where+    go :: Int -> Treap m a -> Treap m a+    go _ Empty = one p a+    go k node@(Node _ tp _ ta l r)+      | p <= tp =+          let lSize = sizeInt l+          in if k <= lSize+              then recalculate $ new tp ta (go k l) r+              else recalculate $ new tp ta l (go (k - lSize - 1) r)+      | otherwise =+          let (!newL, !newR) = splitAt k node+          in recalculate $ new p a newL newR++{- | \( O(d) \). Delete element from 'Treap' by the given index. If index is out+of bounds, 'Treap' remains unchanged.+-}+delete :: forall m a . Measured m a => Int -> Treap m a -> Treap m a+delete i t+    | i < 0          = t+    | i >= sizeInt t = t+    | otherwise      = go i t+  where+    go :: Int -> Treap m a -> Treap m a+    go _ Empty = Empty+    go k (Node _ p _ a l r) =+        let lSize = sizeInt l+        in case compare k lSize of+            EQ -> merge l r+            LT -> recalculate $ new p a (go k l) r+            GT -> recalculate $ new p a l (go (k - lSize - 1) r)++----------------------------------------------------------------------------+-- Core internal functions+----------------------------------------------------------------------------++{- | \( O(1) \). Calculate size and the value of the monoidal accumulator+in the given root node. This function doesn't perform any recursive calls and it+assumes that the values in the children are already correct. So use this+function only in bottom-up manner.+-}+recalculate :: Measured m a => Treap m a -> Treap m a+recalculate Empty = Empty+recalculate (Node _ p _ a l r) =+    Node (1 + size l + size r) p (measure l <> measure a <> measure r) a l r
+ src/Treap/Rand.hs view
@@ -0,0 +1,236 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE TypeFamilies      #-}++{- | Fair implementation of the 'Treap' data structure that uses random+generator for priorities.+-}++module Treap.Rand+       ( -- * Data structure+         RTreap (..)++         -- * Smart constructors+       , emptyWithGen+       , oneWithGen+       , empty+       , one++         -- * Query functions+       , size+       , at+       , query++       -- * Cuts and joins+       , splitAt+       , merge+       , take+       , drop+       , rotate++       -- * Modification functions+       , insert+       , delete++         -- * General purpose functions+       , withTreap+       , overTreap++         -- * Pretty printing functions+       , prettyPrint+       ) where++import Prelude hiding (drop, lookup, splitAt, take)++import Control.DeepSeq (NFData (..))+import Data.Coerce (Coercible)+import Data.Foldable (foldl')+import GHC.Exts (IsList (..))+import GHC.Generics (Generic)++import Treap.Measured (Measured (..))+import Treap.Pure (Priority (..), Size (..), Treap)++import qualified System.Random.Mersenne.Pure64 as Random+import qualified Treap.Pretty as Treap+import qualified Treap.Pure as Treap++-- $setup+-- >>> import Data.Monoid++----------------------------------------------------------------------------+-- Data structure and instances+----------------------------------------------------------------------------++{- | Specialized version of 'Treap' where priority is+generated by the stored random generator.+-}+data RTreap m a = RTreap+    { rTreapGen  :: !Random.PureMT+    , rTreapTree :: !(Treap m a)+    } deriving (Show, Generic, Foldable)++-- | \( O(n) \). This instance doesn't compare random generators inside trees.+instance (Eq m, Eq a) => Eq (RTreap m a) where+    (==) :: RTreap m a -> RTreap m a -> Bool+    RTreap _ t1 == RTreap _ t2 = t1 == t2++-- | \( O(1) \). Takes cached value from the root.+instance Monoid m => Measured m (RTreap m a) where+    measure :: RTreap m a -> m+    measure = withTreap measure+    {-# INLINE measure #-}++{- | Pure implementation of 'RTreap' construction functions. Uses+@'empty' :: RTreap k a@ as a starting point. Functions have the following+time complexity:++1. 'fromList': \( O(n\ \log \ n) \)+2. 'toList': \( O(n) \)++>>> prettyPrint $ fromList @(RTreap (Sum Int) Int) [1..5]+   5,15:2+      ╱╲+     ╱  ╲+    ╱    ╲+   ╱      ╲+1,1:1   3,12:4+          ╱╲+         ╱  ╲+        ╱    ╲+      1,3:3 1,5:5+-}+instance Measured m a => IsList (RTreap m a) where+    type Item (RTreap m a) = a++    fromList :: [a] -> RTreap m a+    fromList = foldl' (\t (i, a) -> insert i a t) empty . zip [0..]+    {-# INLINE fromList #-}++    toList :: RTreap m a -> [a]+    toList = map snd . toList . rTreapTree+    {-# INLINE toList #-}++instance (NFData m, NFData a) => NFData (RTreap m a) where+    rnf RTreap{..} = rnf rTreapTree `seq` ()++----------------------------------------------------------------------------+-- Smart constructors+----------------------------------------------------------------------------++defaultRandomGenerator :: Random.PureMT+defaultRandomGenerator = Random.pureMT 0++-- | \( O(1) \). Create empty 'RTreap' with given random generator.+emptyWithGen :: Random.PureMT -> RTreap m a+emptyWithGen gen = RTreap gen Treap.Empty+{-# INLINE emptyWithGen #-}++-- | \( O(1) \). Create empty 'RTreap' using random generator with seed @0@.+empty :: RTreap m a+empty = emptyWithGen defaultRandomGenerator+{-# INLINE empty #-}++-- | \( O(1) \). Create singleton 'RTreap' with given random generator.+oneWithGen :: Measured m a => Random.PureMT -> a -> RTreap m a+oneWithGen gen a =+    let (priority, newGen) = Random.randomWord64 gen+    in RTreap newGen $ Treap.one (Priority priority) a+{-# INLINE oneWithGen #-}++-- | \( O(1) \). Create singleton 'RTreap' using random generator with seed @0@.+one :: Measured m a => a -> RTreap m a+one = oneWithGen defaultRandomGenerator+{-# INLINE one #-}++----------------------------------------------------------------------------+-- Query functions+----------------------------------------------------------------------------++{- | \( O(1) \). Returns the size of the 'RTreap'.++__Properties:__++* \( \forall (t\ ::\ \mathrm{Treap}\ m\ a)\ .\ \mathrm{size}\ t \geqslant 0 \)+-}+size :: RTreap m a -> Int+size = unSize . withTreap Treap.size+{-# INLINE size #-}++-- | \( O(\log \ n) \). Lookup a value by a given key inside 'RTreap'.+at :: Int -> RTreap m a -> Maybe a+at i = withTreap $ Treap.at i+{-# INLINE at #-}++-- | \( O(\log \ n) \). Return value of monoidal accumulator on a segment @[l, r)@.+query :: forall m a . Measured m a => Int -> Int -> RTreap m a -> m+query l r = withTreap (Treap.query l r)+{-# INLINE query #-}++----------------------------------------------------------------------------+-- Cuts and joins+----------------------------------------------------------------------------++-- | \( O(\log \ n) \). Lifted to 'RTreap' version of 'Treap.splitAt'.+splitAt :: forall m a . Measured m a => Int -> RTreap m a -> (RTreap m a, RTreap m a)+splitAt i (RTreap gen t) = let (l, r) = Treap.splitAt i t in (RTreap gen l, RTreap gen r)+{-# INLINE splitAt #-}++-- | \( O(\log \ n) \). Lifted to 'RTreap' version of 'Treap.merge'.+merge :: Measured m a => RTreap m a -> RTreap m a -> RTreap m a+merge (RTreap gen t1) (RTreap _ t2) = RTreap gen (Treap.merge t1 t2)+{-# INLINE merge #-}++-- | \( O(\log \ n) \). Lifted to 'RTreap' version of 'Treap.take'.+take :: forall m a . Measured m a => Int -> RTreap m a -> RTreap m a+take n = overTreap (Treap.take n)+{-# INLINE take #-}++-- | \( O(\log \ n) \). Lifted to 'RTreap' version of 'Treap.drop'.+drop :: forall m a . Measured m a => Int -> RTreap m a -> RTreap m a+drop n = overTreap (Treap.drop n)+{-# INLINE drop #-}++-- | \( O(\log \ n) \). Lifted to 'RTreap' version of 'Treap.rotate'.+rotate :: forall m a . Measured m a => Int -> RTreap m a -> RTreap m a+rotate n = overTreap (Treap.rotate n)+{-# INLINE rotate #-}++----------------------------------------------------------------------------+-- Modification functions+----------------------------------------------------------------------------++-- | \( O(\log \ n) \). Insert a value into 'RTreap' by given key.+insert :: forall m a . Measured m a => Int -> a -> RTreap m a -> RTreap m a+insert i a (RTreap gen t) =+    let (priority, newGen) = Random.randomWord64 gen+    in RTreap newGen $ Treap.insert i (Priority priority) a t+{-# INLINE insert #-}++{- | \( O(\log \ n) \). Delete 'RTreap' node that contains given key. If there is no+such key, 'RTreap' remains unchanged.+-}+delete :: forall m a . Measured m a => Int -> RTreap m a -> RTreap m a+delete i (RTreap gen t) = RTreap gen $ Treap.delete i t+{-# INLINE delete #-}++----------------------------------------------------------------------------+-- Generic functions+----------------------------------------------------------------------------++-- | Lift a function that works with 'Treap' to 'RTreap'.+withTreap :: (Treap m a -> r) -> (RTreap m a -> r)+withTreap f = f . rTreapTree+{-# INLINE withTreap #-}++-- | Lift a function that works with 'Treap' to 'RTreap'.+overTreap :: (Treap m a -> Treap m a) -> (RTreap m a -> RTreap m a)+overTreap set t = t { rTreapTree = set $ rTreapTree t }+{-# INLINE overTreap #-}++----------------------------------------------------------------------------+-- Pretty printing functions+----------------------------------------------------------------------------++-- | Pretty prints 'RTreap' without printing random generator.+prettyPrint :: forall m a . (Coercible m a, Show a) => RTreap m a -> IO ()+prettyPrint = withTreap Treap.prettyPrint
+ test/Doctest.hs view
@@ -0,0 +1,23 @@+module Main (main) where++import System.FilePath.Glob (glob)+import Test.DocTest (doctest)+++main :: IO ()+main = do+    sourceFiles <- glob "src/**/*.hs"+    doctest+        $ "-XInstanceSigs"+        : "-XScopedTypeVariables"+        : "-XRecordWildCards"+        : "-XMultiParamTypeClasses"+        : "-XLambdaCase"+        : "-XBangPatterns"+        : "-XGeneralizedNewtypeDeriving"+        : "-XDerivingStrategies"+        : "-XDeriveAnyClass"+        : "-XDeriveGeneric"+        : "-XDeriveFoldable"+        : "-XTypeApplications"+        : sourceFiles
+ test/Spec.hs view
@@ -0,0 +1,17 @@+module Main (main) where++import System.IO (hSetEncoding, stderr, stdout, utf8)+import Test.Hspec (Spec, hspec)++import Test.Rand (randSpec)+++allUnitTests :: Spec+allUnitTests = randSpec++main :: IO ()+main = do+    hSetEncoding stdout utf8+    hSetEncoding stderr utf8++    hspec allUnitTests
+ test/Test/Common.hs view
@@ -0,0 +1,21 @@+module Test.Common+       ( TestTreap+       , smallTreap+       , extractSum+       ) where++import Data.Monoid (Sum (..))+import GHC.Exts (IsList (..))++import Treap (RTreap, measure)+++-- | Specialized version of 'RTreap' for testing.+type TestTreap = RTreap (Sum Int) Int++-- | Small treap of total size 5.+smallTreap :: TestTreap+smallTreap = fromList [1..5]++extractSum :: TestTreap -> Int+extractSum = getSum . measure
+ test/Test/Rand.hs view
@@ -0,0 +1,16 @@+module Test.Rand+       ( randSpec+       ) where++import Test.Hspec (Spec, describe)++import Test.Rand.Cuts (cutsSpec)+import Test.Rand.Query (querySpec)+import Test.Rand.Update (updateSpec)+++randSpec :: Spec+randSpec = describe "RTreap" $ do+    querySpec+    cutsSpec+    updateSpec
+ test/Test/Rand/Cuts.hs view
@@ -0,0 +1,70 @@+module Test.Rand.Cuts+       ( cutsSpec+       ) where++import Data.Bifunctor (bimap)+import GHC.Exts (IsList (..))+import Test.Hspec (Spec, describe, it, shouldBe)++import Test.Common (TestTreap, smallTreap)++import qualified Treap+++cutsSpec :: Spec+cutsSpec = describe "Cuts and joins tests" $ do+    splitAtSpec+    mergeSpec+    takeSpec+    dropSpec+    rotateSpec++splitAtSpec :: Spec+splitAtSpec = describe "splitAt" $ do+    it "splitAt negative returns treap itself" $+        snd (Treap.splitAt (-1) smallTreap) `shouldBe` smallTreap+    it "splitAt 0 returns treap itself" $+        snd (Treap.splitAt 0 smallTreap) `shouldBe` smallTreap+    it "splitAt n returns treap itself" $+        fst (Treap.splitAt 5 smallTreap) `shouldBe` smallTreap+    it "splitAt 2 returns two treaps" $+        bimap toList toList (Treap.splitAt 2 smallTreap) `shouldBe` ([1..2], [3..5])++mergeSpec :: Spec+mergeSpec = describe "merge" $ do+    it "merge with empty should be treap itself" $ do+        Treap.merge Treap.empty smallTreap `shouldBe` smallTreap+        Treap.merge smallTreap Treap.empty `shouldBe` smallTreap+    it "merge two treaps works" $+        toList (Treap.merge (fromList [1..2]) (fromList [3..5]) :: TestTreap) `shouldBe` [1..5]++takeSpec :: Spec+takeSpec = describe "take" $ do+    it "take negative returns empty treap" $+       Treap.take (-1) smallTreap `shouldBe` Treap.empty+    it "take 0 returns empty treap" $+        Treap.take 0 smallTreap `shouldBe` Treap.empty+    it "take size returns treap itself" $+        Treap.take 5 smallTreap `shouldBe` smallTreap+    it "take 2 returns first two elements" $+        Treap.take 2 smallTreap `shouldBe` fromList [1..2]++dropSpec :: Spec+dropSpec = describe "drop" $ do+    it "drop negative returns treap itself" $+       Treap.drop (-1) smallTreap `shouldBe` smallTreap+    it "drop 0 returns treap itself" $+        Treap.drop 0 smallTreap `shouldBe` smallTreap+    it "drop size returns empty treap" $+        Treap.drop 5 smallTreap `shouldBe` Treap.empty+    it "drop 2 returns first two elements" $+        toList (Treap.drop 2 smallTreap) `shouldBe` [3..5]++rotateSpec :: Spec+rotateSpec = describe "rotate" $ do+    it "rotate 0 does nothing" $+        Treap.rotate 0 smallTreap `shouldBe` smallTreap+    it "rotate 1 moves first element to the end" $+        toList (Treap.rotate 1 smallTreap) `shouldBe` [2, 3, 4, 5, 1]+    it "rotate -1 moves last element to the beginning" $+        toList (Treap.rotate (-1) smallTreap) `shouldBe` [5, 1, 2, 3, 4]
+ test/Test/Rand/Query.hs view
@@ -0,0 +1,51 @@+module Test.Rand.Query+       ( querySpec+       ) where++import Data.Monoid (Sum (..))+import GHC.Exts (IsList (..))+import Test.Hspec (Spec, describe, it, shouldBe)++import Test.Common (TestTreap, extractSum, smallTreap)++import qualified Treap+++querySpec :: Spec+querySpec = describe "Query tests" $ do+    basicSpec+    advancedSpec++basicSpec :: Spec+basicSpec = describe "Sanity checks" $ do+    it "size of empty treap is 0" $+        Treap.size Treap.empty `shouldBe` 0+    it "size of singletone treap is 1" $+        Treap.size (Treap.one 1 :: TestTreap) `shouldBe` 1+    it "size of smallTreap is 5" $+        Treap.size smallTreap `shouldBe` 5+    it "measure of empty treap is mempty" $+        extractSum Treap.empty `shouldBe` 0+    it "measure of singleton treap is mempty" $+        extractSum (Treap.one 42) `shouldBe` 42+    it "toList smallTreap is [1..5]" $+        toList smallTreap `shouldBe` [1..5]+    it "total sum of smallTreap is [1..5]" $+        extractSum smallTreap `shouldBe` sum [1..5]++advancedSpec :: Spec+advancedSpec = describe "Different checks on query functions" $ do+    it "elements by indices are correct" $+        map (`Treap.at` smallTreap) [-1..5] `shouldBe`+            [Nothing, Just 1, Just 2, Just 3, Just 4, Just 5, Nothing]+    it "query on empty segment returns 'mempty'" $+        Treap.query 0 (-1) smallTreap `shouldBe` mempty+    it "query on the non-intersected segment returns 'mempty'" $ do+        Treap.query (-2) (-1) smallTreap `shouldBe` mempty+        Treap.query 5 6 smallTreap `shouldBe` mempty+    it "query on subsegments works" $ do+        Treap.query 0 0 smallTreap `shouldBe` 0+        Treap.query 0 1 smallTreap `shouldBe` 1+        Treap.query 0 2 smallTreap `shouldBe` 3+        Treap.query 1 3 smallTreap `shouldBe` 5+        Treap.query (-1) 10 smallTreap `shouldBe` Sum (sum [1..5])
+ test/Test/Rand/Update.hs view
@@ -0,0 +1,38 @@+module Test.Rand.Update+       ( updateSpec+       ) where++import GHC.Exts (IsList (..))+import Test.Hspec (Spec, describe, it, shouldBe)++import Test.Common (smallTreap)++import qualified Treap+++updateSpec :: Spec+updateSpec = describe "Modification operations tests" $ do+    insertSpec+    deleteSpec++insertSpec :: Spec+insertSpec = describe "insert" $ do+    it "insert negative inserts at the beginning" $+        toList (Treap.insert (-1) 42 smallTreap) `shouldBe` 42 : [1..5]+    it "insert 0 inserts at the beginning" $+        toList (Treap.insert 0 42 smallTreap) `shouldBe` 42 : [1..5]+    it "insert size inserts at the end" $+        toList (Treap.insert 5 42 smallTreap) `shouldBe` [1, 2, 3, 4, 5, 42]+    it "insert in the middle works" $+        toList (Treap.insert 2 42 smallTreap) `shouldBe` [1, 2, 42, 3, 4, 5]++deleteSpec :: Spec+deleteSpec = describe "delete" $ do+    it "delete negative does nothing" $+        Treap.delete (-1) smallTreap `shouldBe` smallTreap+    it "delete size does nothing" $+        Treap.delete 5 smallTreap `shouldBe` smallTreap+    it "delete 0 removes first element" $+        toList (Treap.delete 0 smallTreap) `shouldBe` [2..5]+    it "deletes from the middle works" $+        toList (Treap.delete 2 smallTreap) `shouldBe` [1, 2, 4, 5]
+ treap.cabal view
@@ -0,0 +1,98 @@+cabal-version:       2.4+name:                treap+version:             0.0.0.0+synopsis:            Efficient implementation of the implicit treap data structure+description:+    Efficient implementation of the implicit treap data structure.+    Use this data structure if you want dynamic arrays with fast operations on segments.+homepage:            https://github.com/chshersh/treap+bug-reports:         https://github.com/chshersh/treap/issues+license:             MPL-2.0+license-file:        LICENSE+author:              Dmitrii Kovanikov+maintainer:          kovanikov@gmail.com+copyright:           2019 Dmitrii Kovanikov+category:            Data Structure, Tree+build-type:          Simple+extra-doc-files:     README.md+                   , CHANGELOG.md+tested-with:         GHC == 8.4.4+                   , GHC == 8.6.4++source-repository head+  type:                git+  location:            https://github.com/chshersh/treap.git++common common-options+  build-depends:       base >= 4.11 && < 4.13++  ghc-options:         -Wall+                       -Wincomplete-uni-patterns+                       -Wincomplete-record-updates+                       -Wcompat+                       -Widentities+                       -Wredundant-constraints+                       -Wpartial-fields+                       -fhide-source-paths+                       -freverse-errors++  default-language:    Haskell2010+  default-extensions:  BangPatterns+                       ConstraintKinds+                       DataKinds+                       DeriveFunctor+                       DeriveFoldable+                       DeriveTraversable+                       DeriveGeneric+                       DerivingStrategies+                       GeneralizedNewtypeDeriving+                       InstanceSigs+                       KindSignatures+                       LambdaCase+                       MultiParamTypeClasses+                       OverloadedStrings+                       RecordWildCards+                       ScopedTypeVariables+                       TypeApplications+++library+  import:              common-options+  build-depends:       deepseq ^>= 1.4+                     , mersenne-random-pure64 ^>= 0.2.2++  hs-source-dirs:      src+  exposed-modules:     Treap+                         Treap.Measured+                         Treap.Pretty+                         Treap.Pure+                         Treap.Rand+++test-suite treap-test+  import:              common-options+  type:                exitcode-stdio-1.0+  hs-source-dirs:      test+  main-is:             Spec.hs+  other-modules:       Test.Common+                       Test.Rand+                         Test.Rand.Cuts+                         Test.Rand.Query+                         Test.Rand.Update++  build-depends:       treap+                     , hspec+                     , hspec-core+++test-suite treap-doctest+  import:              common-options+  type:                exitcode-stdio-1.0+  hs-source-dirs:      test+  main-is:             Doctest.hs++  build-depends:       doctest+                     , Glob++  ghc-options:         -threaded+  default-language:    Haskell2010