diff --git a/bench/main.hs b/bench/main.hs
new file mode 100644
--- /dev/null
+++ b/bench/main.hs
@@ -0,0 +1,65 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE NoMonomorphismRestriction #-}
+
+import Control.Monad
+import Data.Proxy
+import qualified Data.Text as T
+import Data.Text.Read(decimal)
+import Network.Routing
+import Criterion.Main
+
+p0  :: Proxy  "0"; p0  = Proxy
+p1  :: Proxy  "1"; p1  = Proxy
+p2  :: Proxy  "2"; p2  = Proxy
+p3  :: Proxy  "3"; p3  = Proxy
+p4  :: Proxy  "4"; p4  = Proxy
+p5  :: Proxy  "5"; p5  = Proxy
+p6  :: Proxy  "6"; p6  = Proxy
+p7  :: Proxy  "7"; p7  = Proxy
+p8  :: Proxy  "8"; p8  = Proxy
+p9  :: Proxy  "9"; p9  = Proxy
+p10 :: Proxy "10"; p10 = Proxy
+p11 :: Proxy "11"; p11 = Proxy
+p12 :: Proxy "12"; p12 = Proxy
+p13 :: Proxy "13"; p13 = Proxy
+p14 :: Proxy "14"; p14 = Proxy
+p15 :: Proxy "15"; p15 = Proxy
+p16 :: Proxy "16"; p16 = Proxy
+p17 :: Proxy "17"; p17 = Proxy
+p18 :: Proxy "18"; p18 = Proxy
+p19 :: Proxy "19"; p19 = Proxy
+
+readInt :: T.Text -> Maybe Int
+readInt t = case decimal t of
+    Right (i, "") -> Just i
+    _ -> Nothing
+
+test :: Path '[] Maybe Int
+test = root $ exact "foo" $
+    r p0 $ r p1 $ r p2 $ r p3 $ r p4 $
+    r p5 $ r p6 $ r p7 $ r p8 $ r p9 $
+    r p10 $ r p11 $ r p12 $ r p13 $ r p14 $
+    r p15 $ r p16 $ r p17 $ r p18 $ r p19 $
+    action Nothing $ \d -> Just $
+        get p0 d + get p1 d + get p2 d + get p3 d + get p4 d +
+        get p5 d + get p6 d + get p7 d + get p8 d + get p9 d +
+        get p10 d + get p11 d + get p12 d + get p13 d + get p14 d +
+        get p15 d + get p16 d + get p17 d + get p18 d + get p19 d
+  where
+    r p = fetch p readInt
+
+route :: Router '[] Maybe Int
+route = test +| empty
+
+testPath :: [T.Text]
+testPath = "foo" : map (T.pack . show) [0..19::Int]
+
+main :: IO ()
+main = do
+    unless ((execute route "GET") testPath == Just 190) $
+        fail "result not matched"
+    defaultMain
+        [ bench "routing" $ nf (execute route "GET") testPath
+        ]
diff --git a/src/Network/Routing.hs b/src/Network/Routing.hs
--- a/src/Network/Routing.hs
+++ b/src/Network/Routing.hs
@@ -7,18 +7,22 @@
 {-# LANGUAGE DataKinds #-}
 {-# LANGUAGE GADTs #-}
 
--- | >>> :set -XDataKinds -XOverloadedStrings -XNoMonomorphismRestriction
--- >>> import Data.Proxy (Proxy(..))
+-- | >>> :set -XDataKinds -XPolyKinds -XOverloadedStrings
+-- >>> data Proxy s = Proxy
 -- >>> import Text.Read(readMaybe)
 -- >>> import qualified Data.Text as T
 --
 -- 1. create path
 --
--- >>> data Result = A | B T.Text | C | D Int deriving Show
+-- >>> data Result = A | B T.Text | C | D Int | E T.Text deriving Show
+--
+-- >>> let key = Proxy :: Proxy "key"
+--
 -- >>> let a = root $ exact "foo" $ action Nothing (\_ -> Just A)
--- >>> let b = root $ exact "bar" $ fetch (Proxy :: Proxy "key") Just $ action Nothing (\d -> Just . B $ D.get (Proxy :: Proxy "key") d)
+-- >>> let b = root $ exact "bar" $ fetch key Just $ action Nothing (\d -> Just . B $ D.get key d)
 -- >>> let c = root $ exact "bar" $ any $ action (Just "GET") (\_ -> Just C)
--- >>> let d = root $ exact "bar" $ fetch (Proxy :: Proxy "key") (\t -> readMaybe (T.unpack t) :: Maybe Int) $ action Nothing (\d -> Just . D $ D.get (Proxy :: Proxy "key") d)
+-- >>> let d = root $ exact "bar" $ fetch key (\t -> readMaybe (T.unpack t) :: Maybe Int) $ action Nothing (\d -> Just . D $ D.get key d)
+-- >>> let e = root $ exact "foo" $ fetch key Just $ exact "qux" $ action (Just "POST") (\d -> Just . E $ D.get key d)
 -- >>> a
 -- * /foo
 -- >>> b
@@ -27,10 +31,12 @@
 -- GET /bar/**
 -- >>> d
 -- * /bar/:key
+-- >>> e
+-- POST /foo/:key/qux
 --
 -- 2. create router
 --
--- >>> let r = d +| a +| b +| c +| empty
+-- >>> let r = e +| d +| a +| b +| c +| empty
 --
 -- 3. execute router
 --
@@ -48,18 +54,21 @@
 -- Just C
 -- >>> run "POST" ["bar", "baz", "qux"]
 -- Nothing
+-- >>> run "POST" ["foo", "bar", "baz"]
+-- Nothing
+-- >>> run "POST" ["foo", "bar", "qux"]
+-- Just (E "bar")
 
 module Network.Routing
     ( Method
       -- * Path 
     , Path
-      -- ** Path constructors
     , root
-      -- *** children
+      -- ** children
     , exact
-      -- *** action
+      -- ** action
     , action
-      -- *** get parameter
+      -- ** get parameter
     , Raw
     , raw
     , fetch
@@ -69,26 +78,31 @@
     -- * Router
     , Router
     , empty
-    , add, (+|)
+    , insert, (+|)
 
     -- * execute
     , execute
+
+    -- * reexport
+    , module Network.Routing.Dict
     ) where
 
 import Prelude hiding(any)
 import Control.Monad(MonadPlus(..))
 
 import Network.Routing.Compat(KnownSymbol, symbolVal)
-import qualified Network.Routing.Dict as D
+import qualified Network.Routing.Dict.Internal as D
 import qualified Data.Text as T
 import qualified Data.HashMap.Strict as H
 import qualified Data.ByteString as S
 import qualified Data.ByteString.Char8 as SC
 
+import Network.Routing.Dict
+
 type Method = S.ByteString
 
 data Params d m a where
-    PCons :: (D.Dict d -> [T.Text] -> m (D.Dict d', [T.Text]))
+    PCons :: (D.Store d -> [T.Text] -> m (D.Store d', [T.Text]))
           -> Router d' m a
           -> Params d m a -> Params d m a
     PNil  :: Params d m a
@@ -97,7 +111,7 @@
 data Path d m a where
     Exact :: T.Text -> Path d m a -> Path d m a
 
-    Param :: String -> (D.Dict d -> [T.Text] -> m (D.Dict d', [T.Text]))
+    Param :: String -> (D.Store d -> [T.Text] -> m (D.Store d', [T.Text]))
           -> Path d' m a -> Path d m a
 
     Action :: Maybe Method
@@ -116,9 +130,9 @@
 exact = Exact
 
 type Raw m d d'
-    = D.Dict d -- ^ input dictionary
+    = D.Store d -- ^ input dictionary
     -> [T.Text] -- ^ input path information
-    -> m (D.Dict d', [T.Text]) -- ^ output dictionary and path information
+    -> m (D.Store d', [T.Text]) -- ^ output dictionary and path information
 
 -- | raw get parameter function
 --
@@ -209,25 +223,25 @@
     r { anyMethod = \d -> anyMethod r d `mplus` n d }
 
 -- | insert path to router
-add :: MonadPlus m => Path '[] m a -> Router '[] m a -> Router '[] m a
-add = add'
+insert :: MonadPlus m => Path '[] m a -> Router '[] m a -> Router '[] m a
+insert = add'
 
--- | infix version of 'add'
+-- | infix version of `insert`
 (+|) :: MonadPlus m => Path '[] m a -> Router '[] m a -> Router '[] m a
-(+|) = add
+(+|) = insert
 
-infixr `add`
+infixr `insert`
 infixr +|
 
 -- | execute router
 execute :: MonadPlus m => Router '[] m a -> Method -> [T.Text] -> m a
 execute = execute' D.empty
 
-execute' :: MonadPlus m => D.Dict d -> Router d m a -> Method -> [T.Text] -> m a
+execute' :: MonadPlus m => D.Store d -> Router d m a -> Method -> [T.Text] -> m a
 execute' d Router{params, methods, anyMethod} m [] = fetching d m [] params `mplus`
     case H.lookup m methods of
-        Nothing -> anyMethod d
-        Just f  -> f d
+        Nothing -> anyMethod (D.mkDict d)
+        Just f  -> f (D.mkDict d)
 
 execute' d Router{params, children} m pps@(p:ps) = child `mplus` fetching d m pps params
   where
@@ -235,7 +249,7 @@
         Nothing -> mzero
         Just c  -> execute' d c m ps
 
-fetching :: MonadPlus m => D.Dict d -> Method -> [T.Text] -> Params d m a -> m a
+fetching :: MonadPlus m => D.Store d -> Method -> [T.Text] -> Params d m a -> m a
 fetching d m pps = loop
   where
     loop PNil = mzero
diff --git a/src/Network/Routing/Dict.hs b/src/Network/Routing/Dict.hs
--- a/src/Network/Routing/Dict.hs
+++ b/src/Network/Routing/Dict.hs
@@ -1,145 +1,29 @@
-{-# LANGUAGE FunctionalDependencies #-}
-{-# LANGUAGE UndecidableInstances #-}
-{-# LANGUAGE OverlappingInstances #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE ConstraintKinds #-}
 {-# LANGUAGE KindSignatures #-}
 {-# LANGUAGE TypeOperators #-}
 {-# LANGUAGE TypeFamilies #-}
-{-# LANGUAGE BangPatterns #-} -- for ghc-7.6
 {-# LANGUAGE DataKinds #-}
-{-# LANGUAGE CPP #-}
 
 module Network.Routing.Dict
-    ( -- * dictionary
-      Dict
-    , ShowDict
-    , KV(..)
-    , empty
-
-      -- * insert
+    ( -- * store
+      Store
     , type (</)
     , add
 
-      -- * get
+      -- * dictionary
+    , Dict
     , Member
     , get
 
+      -- * types
+    , ShowDict
+    , KV(..)
+
       -- * convenient
     , Members
     ) where
 
 import GHC.Exts(Constraint)
-
-import Network.Routing.Tree
-
-#if __GLASGOW_HASKELL__ > 707
-import GHC.TypeLits
-#endif
-
-import Network.Routing.Compat
-import Data.Typeable(typeOf, Typeable, TypeRep)
-import Data.List(intercalate)
-import Unsafe.Coerce
-
--- | (kind) key-value pair
-data KV v = Symbol := v
-
--- | heterogeneous dictionary
-newtype Dict (kvs :: [KV *]) = Dict Tree
-
-class ShowDict (kvs :: [KV *]) where
-    showDict :: Int -> Dict kvs -> [(String, String, TypeRep)]
-
-instance ShowDict '[] where
-    showDict _ _ = []
-
-instance (KnownSymbol k, Typeable v, Show v, ShowDict kvs) => ShowDict (k := v ': kvs) where
-    showDict i (Dict t) =
-        (symbolVal (Proxy :: Proxy k), show (unsafeCoerce $ index t i :: v), typeOf (undefined :: v)):
-        showDict (i + 1) (unsafeCoerce $ Dict t :: Dict kvs)
-
-instance ShowDict kvs => Show (Dict kvs) where
-    show d = "Dict {" ++
-        (intercalate ", " . map (\(k, v, t) -> k ++ " = " ++ v ++ " :: " ++ show t) $ showDict 0 d)
-        ++ "}"
-
--- | empty dictionary
-empty :: Dict '[]
-empty = Dict Tip
-
--- | result type for pretty printing type error.
-data HasKeyResult
-    = AlreadyExists Symbol
-    | Dictionary
-
-#if __GLASGOW_HASKELL__ > 707
-type family HasKey (k :: Symbol) (kvs :: [KV *]) :: HasKeyResult where
-  HasKey k '[] = AlreadyExists k
-  HasKey k (k  := v ': kvs) = Dictionary
-  HasKey k (k' := v ': kvs) = HasKey k kvs
-#else
-type family   HasKey (k :: Symbol) (kvs :: [KV *]) :: HasKeyResult
-type instance HasKey k kvs = AlreadyExists k
-#endif
-
--- | 'not elem key' constraint(ghc >= 7.8)
-type k </ v = HasKey k v ~ AlreadyExists k
-
--- | add key value pair to dictionary.
---
--- >>> let a = add (Proxy :: Proxy "foo") (12 :: Int) empty
--- >>> a
--- Dict {foo = 12 :: Int}
---
--- >>> add (Proxy :: Proxy "bar") "baz" a
--- Dict {bar = "baz" :: [Char], foo = 12 :: Int}
-add :: (k </ kvs) => proxy k -> v -> Dict kvs -> Dict (k := v ': kvs)
-add _ v (Dict d) = Dict (unsafeCoerce v `cons` d)
-
-#if __GLASGOW_HASKELL__ > 707
-type family Ix (k :: Symbol) (kvs :: [KV *]) :: Nat where
-  Ix k (k  := v ': kvs) = 0
-  Ix k (k' := v ': kvs) = 1 + Ix k kvs
-
-getImpl :: forall proxy k kvs v. KnownNat (Ix k kvs) => proxy (k :: Symbol) -> Dict kvs -> v
-getImpl _ (Dict d) = unsafeCoerce $ d `index` fromIntegral (natVal (Proxy :: Proxy (Ix k kvs)))
-
-class Member (k :: Symbol) (v :: *) (kvs :: [KV *]) | k kvs -> v where
-    get' :: proxy k -> Dict kvs -> v
-
-instance Member k v (k := v ': kvs) where
-    get' = getImpl
-    {-# INLINE get' #-}
-
-instance (Member k v kvs, KnownNat (Ix k (k' := v' ': kvs))) => Member k v (k' := v' ': kvs) where
-    get' = getImpl
-    {-# INLINE get' #-}
-
-get = get'
-#else
-class Member (k :: Symbol) (v :: *) (kvs :: [KV *]) | k kvs -> v where
-    get' :: Int -> proxy k -> Dict kvs -> v
-
-instance Member k v (k := v ': kvs) where
-    get' !i _ (Dict d) = unsafeCoerce $ d `index` i
-
-instance Member k v kvs => Member k v (k' := v' ': kvs) where
-    get' !i k d = get' (i + 1) k (unsafeCoerce d :: Dict kvs)
-
-get = get' 0
-#endif
-
--- | get key from dictionary
---
--- >>> let d = add (Proxy :: Proxy "foo") 12 $ add (Proxy :: Proxy "bar") "baz" empty
--- >>> get (Proxy :: Proxy "foo") d
--- 12
--- >>> get (Proxy :: Proxy "bar") d
--- "baz"
-get :: Member k v kvs => proxy k -> Dict kvs -> v
+import Network.Routing.Dict.Internal
 
 -- | type family to constraint multi kvs.
 --
diff --git a/src/Network/Routing/Dict/Internal.hs b/src/Network/Routing/Dict/Internal.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Routing/Dict/Internal.hs
@@ -0,0 +1,171 @@
+{-# LANGUAGE FunctionalDependencies #-}
+{-# LANGUAGE UndecidableInstances #-}
+{-# LANGUAGE OverlappingInstances #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE ConstraintKinds #-}
+{-# LANGUAGE KindSignatures #-}
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE BangPatterns #-} -- for ghc-7.6
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE CPP #-}
+
+module Network.Routing.Dict.Internal
+    ( Dict, Store
+    , ShowDict
+    , KV(..)
+    , empty
+    , type (</)
+    , add
+    , Member
+    , get
+    , mkDict
+    ) where
+
+import GHC.Exts(Any)
+
+import GHC.TypeLits
+import Network.Routing.Compat
+import Data.Typeable(typeOf, Typeable, TypeRep)
+import Data.List(intercalate)
+import Unsafe.Coerce
+import qualified Control.Monad.Primitive as P
+import qualified Data.Primitive as P
+import Control.Monad.ST (ST, runST)
+
+-- | (kind) key-value pair
+data KV v = Symbol := v
+
+-- | data store to construct dictionary.
+--
+-- `add` and `mkDict` operation only allowed.
+data Store (kvs :: [KV *]) where
+    Cons  :: {-# UNPACK #-} !Int -> v -> Store kvs -> Store (k := v ': kvs)
+    Empty :: Store '[]
+
+instance ShowDict kvs => Show (Store kvs) where
+    show d = "Store {" ++
+        (intercalate ", " . map (\(k, v, t) -> k ++ " = " ++ v ++ " :: " ++ show t) $ showDict 0 (mkDict d))
+        ++ "}"
+
+empty :: Store '[]
+empty = Empty
+
+size :: Store kvs -> Int
+size Empty        = 0
+size (Cons l _ _) = l
+
+-- | result type for pretty printing type error.
+data HasKeyResult
+    = AlreadyExists Symbol
+    | Dictionary
+
+#if __GLASGOW_HASKELL__ > 707
+type family HasKey (k :: Symbol) (kvs :: [KV *]) :: HasKeyResult where
+  HasKey k '[] = AlreadyExists k
+  HasKey k (k  := v ': kvs) = Dictionary
+  HasKey k (k' := v ': kvs) = HasKey k kvs
+#else
+type family   HasKey (k :: Symbol) (kvs :: [KV *]) :: HasKeyResult
+type instance HasKey k kvs = AlreadyExists k
+#endif
+
+-- | 'not elem key' constraint(ghc >= 7.8)
+type k </ v = HasKey k v ~ AlreadyExists k
+
+-- | O(1) add key value pair to dictionary.
+--
+-- >>> let a = add (Proxy :: Proxy "foo") (12 :: Int) empty
+-- >>> a
+-- Store {foo = 12 :: Int}
+--
+-- >>> add (Proxy :: Proxy "bar") "baz" a
+-- Store {bar = "baz" :: [Char], foo = 12 :: Int}
+add :: (k </ kvs) => proxy k -> v -> Store kvs -> Store (k := v ': kvs)
+add _ v Empty          = Cons 1 v Empty
+add _ v c@(Cons i _ _) = Cons (i + 1) v c
+
+-- | heterogeneous dictionary
+--
+-- 'get' operation only allowed.
+newtype Dict (kvs :: [KV *]) = Dict (P.Array Any)
+
+class ShowDict (kvs :: [KV *]) where
+    showDict :: Int -> Dict kvs -> [(String, String, TypeRep)]
+
+instance ShowDict '[] where
+    showDict _ _ = []
+
+instance (KnownSymbol k, Typeable v, Show v, ShowDict kvs) => ShowDict (k := v ': kvs) where
+    showDict i (Dict t) =
+        (symbolVal (Proxy :: Proxy k), show (unsafeCoerce $ P.indexArray t i :: v), typeOf (undefined :: v)):
+        showDict (i + 1) (unsafeCoerce $ Dict t :: Dict kvs)
+
+instance ShowDict kvs => Show (Dict kvs) where
+    show d = "Dict {" ++
+        (intercalate ", " . map (\(k, v, t) -> k ++ " = " ++ v ++ " :: " ++ show t) $ showDict 0 d)
+        ++ "}"
+
+mkDict' :: forall s kvs. Store kvs -> ST s (Dict kvs)
+mkDict' store = do
+    ary <- P.newArray (size store) undefined
+    go (size store) ary
+    Dict `fmap` P.unsafeFreezeArray ary
+  where
+    go :: Int -> P.MutableArray (P.PrimState (ST s)) Any -> ST s ()
+    go size' array = loop store
+      where
+        loop :: Store kvs -> ST s ()
+        loop (Cons i v ss) = do
+            P.writeArray array (size' - i) (unsafeCoerce v)
+            loop (unsafeCoerce ss)
+        loop Empty = return ()
+
+-- | O(n) convert "Store" to "Dictionary".
+mkDict :: Store kvs -> Dict kvs
+mkDict store = runST $ mkDict' store
+
+-- | O(1) (>= ghc-7.8), O(n) (< ghc-7.8) get key from dictionary
+--
+-- >>> let d = mkDict $ add (Proxy :: Proxy "foo") 12 $ add (Proxy :: Proxy "bar") "baz" empty
+-- >>> get (Proxy :: Proxy "foo") d
+-- 12
+-- >>> get (Proxy :: Proxy "bar") d
+-- "baz"
+get :: Member k v kvs => proxy k -> Dict kvs -> v
+
+#if __GLASGOW_HASKELL__ > 707
+type family Ix (k :: Symbol) (kvs :: [KV *]) :: Nat where
+  Ix k (k  := v ': kvs) = 0
+  Ix k (k' := v ': kvs) = 1 + Ix k kvs
+
+getImpl :: forall proxy k kvs v. KnownNat (Ix k kvs) => proxy (k :: Symbol) -> Dict kvs -> v
+getImpl _ (Dict d) = unsafeCoerce $ d `P.indexArray` fromIntegral (natVal (Proxy :: Proxy (Ix k kvs)))
+
+class Member (k :: Symbol) (v :: *) (kvs :: [KV *]) | k kvs -> v where
+    get' :: proxy k -> Dict kvs -> v
+
+instance Member k v (k := v ': kvs) where
+    get' = getImpl
+    {-# INLINE get' #-}
+
+instance (Member k v kvs, KnownNat (Ix k (k' := v' ': kvs))) => Member k v (k' := v' ': kvs) where
+    get' = getImpl
+    {-# INLINE get' #-}
+
+get = get'
+#else
+class Member (k :: Symbol) (v :: *) (kvs :: [KV *]) | k kvs -> v where
+    get' :: Int -> proxy k -> Dict kvs -> v
+
+instance Member k v (k := v ': kvs) where
+    get' !i _ (Dict d) = unsafeCoerce $ d `P.indexArray` i
+
+instance Member k v kvs => Member k v (k' := v' ': kvs) where
+    get' !i k d = get' (i + 1) k (unsafeCoerce d :: Dict kvs)
+
+get = get' 0
+#endif
diff --git a/src/Network/Routing/Tree.hs b/src/Network/Routing/Tree.hs
deleted file mode 100644
--- a/src/Network/Routing/Tree.hs
+++ /dev/null
@@ -1,30 +0,0 @@
-{-# LANGUAGE BangPatterns #-}
-
-module Network.Routing.Tree
-    ( Tree(Tip)
-    , cons
-    , index
-    , ) where
-
-import GHC.Exts(Any)
-
-data Dir = L | R
-
-data Tree
-    = Branch !Dir !Any !Tree !Tree
-    | Tip
-
-cons :: Any -> Tree -> Tree
-cons v Tip = Branch L v Tip Tip
-cons v (Branch _ a Tip Tip) = Branch R v (Branch L a Tip Tip) Tip
-cons v (Branch _ a l   Tip) = Branch L v l (Branch L a Tip Tip)
-cons v (Branch L a l   r)   = Branch R v (cons a l) r
-cons v (Branch R a l   r)   = Branch L v l (cons a r)
-
-index :: Tree -> Int -> Any
-index Tip _ = error "out of range"
-index (Branch _ v _ _) 0 = v
-index (Branch L _ l r) !i | even i    = index l (i `quot` 2 - 1)
-                          | otherwise = index r (i `quot` 2)
-index (Branch R _ l r) !i | odd i     = index l (i `quot` 2)
-                          | otherwise = index r (i `quot` 2 - 1)
diff --git a/tests/Tree.hs b/tests/Tree.hs
deleted file mode 100644
--- a/tests/Tree.hs
+++ /dev/null
@@ -1,16 +0,0 @@
-module Tree(test) where
-
-import Network.Routing.Tree
-import Test.Tasty
-import Test.Tasty.QuickCheck
-import Unsafe.Coerce
-
-mkTestTree :: Int -> Tree
-mkTestTree i = foldr cons Tip $ map unsafeCoerce [0..i]
-
-testTreeToList :: Int -> Tree -> [Int]
-testTreeToList l t = foldr (\i b -> unsafeCoerce (t `index` i) : b) [] [0..l]
-
-test :: TestTree
-test = testProperty "Data.Apiary.Tree" $ \len ->
-    testTreeToList len (mkTestTree len) == [0..len]
diff --git a/tests/tasty.hs b/tests/tasty.hs
deleted file mode 100644
--- a/tests/tasty.hs
+++ /dev/null
@@ -1,7 +0,0 @@
-import Test.Tasty
-import qualified Tree
-
-main :: IO ()
-main = defaultMain $ testGroup ""
-    [ Tree.test
-    ]
diff --git a/web-routing.cabal b/web-routing.cabal
--- a/web-routing.cabal
+++ b/web-routing.cabal
@@ -1,5 +1,5 @@
 name:                web-routing
-version:             0.1.2
+version:             0.2.0
 synopsis:            simple routing library
 -- description:         
 license:             MIT
@@ -16,12 +16,13 @@
 library
   exposed-modules:     Network.Routing
                        Network.Routing.Dict
-  other-modules:       Network.Routing.Tree
-                       Network.Routing.Compat
+  other-modules:       Network.Routing.Compat
+                       Network.Routing.Dict.Internal
   build-depends:       base                 >=4.6  && <4.8
                      , bytestring           >=0.10 && <0.11
                      , text                 >=1.1  && <1.3 
                      , unordered-containers >=0.2  && <0.3
+                     , primitive            >=0.5  && <0.6
   ghc-options:         -O2 -Wall
   hs-source-dirs:      src
   default-language:    Haskell2010
@@ -35,13 +36,12 @@
                      , doctest >=0.9 && <0.10
   default-language:    Haskell2010
 
-test-suite tasty
+benchmark benchmarks
   type:                exitcode-stdio-1.0
-  ghc-options:         -threaded
-  main-is:             tasty.hs
-  other-modules:       Tree
-  hs-source-dirs:      tests, src
-  build-depends:       base             >=4.6  && <4.8
-                     , tasty            >=0.10 && <0.11
-                     , tasty-quickcheck >=0.8  && <0.9
+  main-is:             bench/main.hs
+  build-depends:       base    >=4.6 && <4.8
+                     , web-routing
+                     , criterion
+                     , text
+  ghc-options:         -O2 -Wall -threaded
   default-language:    Haskell2010
