Skip to content

Commit

Permalink
Add any function (#34)
Browse files Browse the repository at this point in the history
This is a specialized version of `Data.Foldable.any` that can short-circuit.

Co-authored-by: Stefan Fehrenbach <stefan.fehrenbach@gmail.com>
  • Loading branch information
flip111 and fehrenbach committed Mar 8, 2024
1 parent 0192d2c commit e8a0d0f
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 2 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
/.purs*
/.psa*
test-bundle.js
.spago
35 changes: 35 additions & 0 deletions src/Data/HashMap.js
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,26 @@ MapNode.prototype.itraverse = function (pure, apply, f) {
return m;
}

MapNode.prototype.any = function (predicate) {
for (var i = 1; i < popCount(this.datamap) * 2; i = i + 2) {
var v = this.content[i];

if (predicate(v)) {
return true;
}
}

i--;

for (; i < this.content.length; i++) {
if (this.content[i].any(predicate)) {
return true;
}
}

return false;
};

/** @constructor */
function Collision(keys, values) {
this.keys = keys;
Expand Down Expand Up @@ -679,6 +699,15 @@ Collision.prototype.filterWithKey = function collisionFilterWithKey(f) {
return new Collision(keys, values);
}

Collision.prototype.any = function (predicate) {
for (var i = 0; i < this.keys.length; i++) {
if (predicate(this.values[i])) {
return true;
}
}
return false;
};

function mask(keyHash, shift) {
return 1 << ((keyHash >>> shift) & 31);
}
Expand Down Expand Up @@ -917,3 +946,9 @@ export function nubHashPurs(Nothing, Just, eq, hash) {
return r;
};
};

export function anyPurs(pred) {
return function (m) {
return m.any(pred);
};
};
12 changes: 11 additions & 1 deletion src/Data/HashMap.purs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ module Data.HashMap (

nubHash,

debugShow
debugShow,

any
) where

import Prelude
Expand Down Expand Up @@ -407,3 +409,11 @@ nubHash :: forall a. Hashable a => Array a -> Array a
nubHash = runFn4 nubHashPurs Nothing Just (==) hash

foreign import nubHashPurs :: forall a. Fn4 (forall x. Maybe x) (forall x. x -> Maybe x) (a -> a -> Boolean) (a -> Int) (Array a -> Array a)

foreign import anyPurs :: forall k v. (v -> Boolean) -> HashMap k v -> Boolean

-- | Returns true if at least one HashMap element satisfies the given predicate, iterating the HashMap only as necessary and stopping as soon as the predicate yields true.
-- |
-- | Use this function instead of `Foldable.any` for more performance.
any :: forall k v. (v -> Boolean) -> HashMap k v -> Boolean
any = anyPurs
22 changes: 21 additions & 1 deletion test/Main.purs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import Prelude
import Data.Array as A
import Data.Array as Array
import Data.Array.NonEmpty (fromNonEmpty)
import Data.Foldable (all, foldMap, foldl, foldr)
import Data.Foldable (all, foldMap, foldl, foldr, any)
import Data.FoldableWithIndex (allWithIndex, foldMapWithIndex, foldlWithIndex, foldrWithIndex)
import Data.HashMap (HashMap)
import Data.HashMap as HM
Expand Down Expand Up @@ -437,6 +437,26 @@ main = do
Just false -> HM.lookup k mc === HM.lookup k my
Nothing -> false === HM.member k my

log "any"
quickCheck' 10000 $ \(a :: Array (Tuple Int Int)) ->
let hm = HM.fromFoldable a
xs = HM.toArrayBy Tuple hm
in (not (HM.any (\_ -> true) HM.empty)) &&
case A.head xs of
Nothing -> true
Just h -> case A.last xs of
Nothing -> true
Just l -> HM.any (\x -> x == snd h) hm
&& HM.any (\x -> x == snd l) hm
&& (not (HM.any (\_ -> false) hm))

log "any agrees with Foldable any"
quickCheck' 10000 $ \(a :: Array (Tuple CollidingInt Int)) (f :: Int -> Boolean) ->
let m = HM.fromArray a
f' (Tuple _ v) = f v
-- use array instance, so we still test something useful if any ever becomes a method on Foldable
in any f' a === HM.any f m

log "Done."

t54 :: Boolean
Expand Down

0 comments on commit e8a0d0f

Please sign in to comment.