sync the repo
[hiphop-php.git] / hphp / hsl / src / keyset / select.php
blobf3c5c3d194111df4b35885d8deb380c6965aba28
1 <?hh
2 /*
3 * Copyright (c) 2004-present, Facebook, Inc.
4 * All rights reserved.
6 * This source code is licensed under the MIT license found in the
7 * LICENSE file in the hphp/hsl/ subdirectory of this source tree.
9 */
11 namespace HH\Lib\Keyset;
13 use namespace HH\Lib\C;
15 /**
16 * Returns a new keyset containing only the elements of the first Traversable
17 * that do not appear in any of the other ones.
19 * Time complexity: O(n + m), where n is size of `$first` and m is the combined
20 * size of `$second` plus all the `...$rest`
21 * Space complexity: O(n), where n is size of `$first`
23 function diff<Tv1 as arraykey, Tv2 as arraykey>(
24 Traversable<Tv1> $first,
25 Traversable<Tv2> $second,
26 Container<Tv2> ...$rest
27 )[]: keyset<Tv1> {
28 if (!$first is keyset<_>) {
29 $first = keyset($first);
31 if (C\is_empty($first)) { // nothing to remove, so return early.
32 return $first;
34 foreach ($second as $value) {
35 if (C\contains_key($first, $value)) {
36 unset($first[HH\FIXME\UNSAFE_CAST<Tv2, Tv1>(
37 $value,
38 '$value is type Tv1 because it\'s in $first',
39 )]);
42 foreach ($rest as $container) {
43 if (C\is_empty($first)) { // nothing to remove, so return early.
44 return $first;
46 foreach ($container as $value) {
47 if (C\contains_key($first, $value)) {
48 unset($first[HH\FIXME\UNSAFE_CAST<Tv2, Tv1>(
49 $value,
50 '$value is type Tv1 because it\'s in $first',
51 )]);
55 return $first;
57 /**
58 * Returns a new keyset containing all except the first `$n` elements of
59 * the given Traversable.
61 * To take only the first `$n` elements, see `Keyset\take()`.
63 * Time complexity: O(n), where n is the size of `$traversable`
64 * Space complexity: O(n), where n is the size of `$traversable`
66 function drop<Tv as arraykey>(
67 Traversable<Tv> $traversable,
68 int $n,
69 )[]: keyset<Tv> {
70 invariant($n >= 0, 'Expected non-negative N, got %d.', $n);
71 $result = keyset[];
72 $ii = -1;
73 foreach ($traversable as $value) {
74 $ii++;
75 if ($ii < $n) {
76 continue;
78 $result[] = $value;
80 return $result;
83 /**
84 * Returns a new keyset containing only the values for which the given predicate
85 * returns `true`. The default predicate is casting the value to boolean.
87 * To remove null values in a typechecker-visible way, see `Keyset\filter_nulls()`.
89 * Time complexity: O(n * p), where p is the complexity of `$value_predicate`
90 * Space complexity: O(n)
92 function filter<Tv as arraykey>(
93 Traversable<Tv> $traversable,
94 ?(function(Tv)[_]: bool) $value_predicate = null,
95 )[ctx $value_predicate]: keyset<Tv> {
96 $value_predicate ??= \HH\Lib\_Private\boolval<>;
97 $result = keyset[];
98 foreach ($traversable as $value) {
99 if ($value_predicate($value)) {
100 $result[] = $value;
103 return $result;
107 * Returns a new keyset containing only non-null values of the given
108 * Traversable.
110 * Time complexity: O(n)
111 * Space complexity: O(n)
113 function filter_nulls<Tv as arraykey>(
114 Traversable<?Tv> $traversable,
115 )[]: keyset<Tv> {
116 $result = keyset[];
117 foreach ($traversable as $value) {
118 if ($value !== null) {
119 $result[] = $value;
122 return $result;
126 * Returns a new keyset containing only the values for which the given predicate
127 * returns `true`.
129 * If you don't need access to the key, see `Keyset\filter()`.
131 * Time complexity: O(n * p), where p is the complexity of `$predicate`
132 * Space complexity: O(n)
134 function filter_with_key<Tk, Tv as arraykey>(
135 KeyedTraversable<Tk, Tv> $traversable,
136 (function(Tk, Tv)[_]: bool) $predicate,
137 )[ctx $predicate]: keyset<Tv> {
138 $result = keyset[];
139 foreach ($traversable as $key => $value) {
140 if ($predicate($key, $value)) {
141 $result[] = $value;
144 return $result;
148 * Returns a new keyset containing the keys of the given KeyedTraversable,
149 * maintaining the iteration order.
151 function keys<Tk as arraykey, Tv>(
152 KeyedTraversable<Tk, Tv> $traversable,
153 )[]: keyset<Tk> {
154 $result = keyset[];
155 foreach ($traversable as $key => $_) {
156 $result[] = $key;
158 return $result;
162 * Returns a new keyset containing only the elements of the first Traversable
163 * that appear in all the other ones.
165 * Time complexity: O(n + m), where n is size of `$first` and m is the combined
166 * size of `$second` plus all the `...$rest`
167 * Space complexity: O(n), where n is size of `$first`
169 function intersect<Tv as arraykey>(
170 Traversable<Tv> $first,
171 Traversable<Tv> $second,
172 Container<Tv> ...$rest
173 )[]: keyset<Tv> {
174 if (!$first || !$second) {
175 return keyset[];
177 $intersection = keyset($first);
178 $rest[] = $second;
179 foreach ($rest as $traversable) {
180 $next_intersection = keyset[];
181 $keyed_traversable = keyset($traversable);
182 foreach ($intersection as $value) {
183 if (C\contains_key($keyed_traversable, $value)) {
184 $next_intersection[] = $value;
187 if (!$next_intersection) {
188 return keyset[];
190 $intersection = $next_intersection;
192 return $intersection;
196 * Returns a new keyset containing the first `$n` elements of the given
197 * Traversable.
199 * If there are duplicate values in the Traversable, the keyset may be shorter
200 * than the specified length.
202 * To drop the first `$n` elements, see `Keyset\drop()`.
204 * Time complexity: O(n), where n is `$n`
205 * Space complexity: O(n), where n is `$n`
207 function take<Tv as arraykey>(
208 Traversable<Tv> $traversable,
209 int $n,
210 )[]: keyset<Tv> {
211 if ($n === 0) {
212 return keyset[];
214 invariant($n > 0, 'Expected non-negative N, got %d.', $n);
215 $result = keyset[];
216 $ii = 0;
217 foreach ($traversable as $value) {
218 $result[] = $value;
219 $ii++;
220 if ($ii === $n) {
221 break;
224 return $result;