Skip to content

IntMap should offer lookup variant for likely successful lookup #794

@Boarders

Description

@Boarders

Currently lookup is defined to fail early by checking if the prefix mask agrees with the key:

lookup :: Key -> IntMap a -> Maybe a
lookup !k = go
  where
    go (Bin p m l r) | nomatch k p m = Nothing
                     | zero k m  = go l
                     | otherwise = go r
    go (Tip kx x) | k == kx   = Just x
                  | otherwise = Nothing
    go Nil = Nothing

In the original paper they note that if we expect our lookups to be successful then we should instead prioritize testing if the kth bit is zero and failing only when we reach leaves. If I understand correctly, then this would just be the following code:

lookupSucc :: Key -> IntMap a -> Maybe a
lookupSucc !k = go
 where
   go (Bin _p m l r)
                    | zero k m  = go l
                    | otherwise = go r    
   go (Tip kx x) | k == kx   = Just x
                 | otherwise = Nothing
   go Nil = Nothing

Is that correct? It seems to pass the tests in any case. This can certainly lead to large speed ups when we know we are doing many successful lookups. For example, in the lookup benchmark we get the following (this is a best case scenario as the benchmark does not test a map with misses which seems like a bad design for a benchmark):

benchmarked lookup
time                 172.2 μs   (170.3 μs .. 174.1 μs)
                    0.998 R²   (0.994 R² .. 1.000 R²)
mean                 176.6 μs   (175.3 μs .. 181.2 μs)
std dev              7.148 μs   (2.786 μs .. 15.37 μs)

benchmarked lookupSucc
time                 153.0 μs   (151.6 μs .. 154.0 μs)
                    1.000 R²   (1.000 R² .. 1.000 R²)
mean                 152.2 μs   (151.7 μs .. 152.7 μs)
std dev              1.783 μs   (1.306 μs .. 2.362 μs)

Even if this is not quite the correct implementation, containers should probably offer this sort of function to allow users to tune their code to their needs as both variants are worthwhile.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions