squint-cljs 0.14.202 → 0.14.203

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -218,7 +218,13 @@ function hAnd(a, b, field) {
218
218
  }
219
219
  export function parents(a, b) { return hAnd(a, b, 'parents'); }
220
220
  export function ancestors(a, b) { return hAnd(a, b, 'ancestors'); }
221
- export function descendants(a, b) { return hAnd(a, b, 'descendants'); }
221
+ export function descendants(a, b) {
222
+ // like CLJS: a constructor has no derive-based descendants, JS type
223
+ // inheritance is not tracked
224
+ const tag = b === undefined ? a : b;
225
+ if (typeof tag === 'function') throw new Error("Can't get descendants of constructors");
226
+ return hAnd(a, b, 'descendants');
227
+ }
222
228
 
223
229
  function _prefers(prefer, a, b) {
224
230
  const key = findKeyByEquiv(prefer, a);
@@ -0,0 +1,103 @@
1
+ import {
2
+ IRecord,
3
+ ILookup__lookup,
4
+ IAssociative__assoc,
5
+ IAssociative__contains_key_QMARK_,
6
+ IMap__dissoc,
7
+ ICounted__count,
8
+ IKVReduce__kv_reduce,
9
+ ICollection__conj,
10
+ IEquiv__equiv,
11
+ ISeqable__seq,
12
+ ISeqable,
13
+ _EQ_,
14
+ vector_QMARK_,
15
+ seq,
16
+ } from './core.js';
17
+
18
+ // shared defrecord implementations: every record type points its protocol
19
+ // slots at these, so call sites stay monomorphic across record types
20
+ function recordLookup(rec, k, nf) {
21
+ const v = rec[k];
22
+ return v === undefined ? nf : v;
23
+ }
24
+ function recordCopy(rec) {
25
+ return Object.assign(Object.create(Object.getPrototypeOf(rec)), rec);
26
+ }
27
+ function recordAssoc(rec, k, v) {
28
+ const r = recordCopy(rec);
29
+ r[k] = v;
30
+ return r;
31
+ }
32
+ function recordContains(rec, k) {
33
+ return Object.prototype.hasOwnProperty.call(rec, k);
34
+ }
35
+ function recordDissoc(rec, k) {
36
+ // removing a basis field demotes to a plain map, like CLJS
37
+ if (rec[IRecord.__sym].includes(k)) {
38
+ const m = { ...rec };
39
+ delete m[k];
40
+ return m;
41
+ }
42
+ const r = recordCopy(rec);
43
+ delete r[k];
44
+ return r;
45
+ }
46
+ function recordCount(rec) {
47
+ return Object.keys(rec).length;
48
+ }
49
+ function recordKvReduce(rec, f, init) {
50
+ let acc = init;
51
+ for (const k of Object.keys(rec)) acc = f(acc, k, rec[k]);
52
+ return acc;
53
+ }
54
+ function recordConj(rec, x) {
55
+ if (vector_QMARK_(x)) return recordAssoc(rec, x[0], x[1]);
56
+ let r = rec;
57
+ for (const e of seq(x) ?? []) r = recordAssoc(r, e[0], e[1]);
58
+ return r;
59
+ }
60
+ function recordEquiv(rec, other) {
61
+ if (other == null || Object.getPrototypeOf(rec) !== Object.getPrototypeOf(other)) return false;
62
+ const ka = Object.keys(rec);
63
+ if (ka.length !== Object.keys(other).length) return false;
64
+ for (const k of ka) {
65
+ if (!Object.prototype.hasOwnProperty.call(other, k) || !_EQ_(rec[k], other[k])) return false;
66
+ }
67
+ return true;
68
+ }
69
+ function recordSeq(rec) {
70
+ return seq(Object.entries(rec));
71
+ }
72
+
73
+ export function attach(proto, basis, aliases) {
74
+ proto[IRecord.__sym] = basis;
75
+ proto[ILookup__lookup] = recordLookup;
76
+ proto[IAssociative__assoc] = recordAssoc;
77
+ proto[IAssociative__contains_key_QMARK_] = recordContains;
78
+ proto[IMap__dissoc] = recordDissoc;
79
+ proto[ICounted__count] = recordCount;
80
+ proto[IKVReduce__kv_reduce] = recordKvReduce;
81
+ proto[ICollection__conj] = recordConj;
82
+ proto[IEquiv__equiv] = recordEquiv;
83
+ proto[ISeqable__seq] = recordSeq;
84
+ proto[ISeqable.__sym] = true;
85
+ proto[Symbol.iterator] = function* () {
86
+ for (const k of Object.keys(this)) yield [k, this[k]];
87
+ };
88
+ Object.defineProperty(proto, Symbol.toStringTag, {
89
+ get() { return this.constructor.name; },
90
+ });
91
+ proto[Symbol.for('nodejs.util.inspect.custom')] = function (_depth, opts, inspect) {
92
+ return '#' + this.constructor.name + ' ' + inspect({ ...this }, opts);
93
+ };
94
+ if (aliases !== undefined) {
95
+ for (const munged of Object.keys(aliases)) {
96
+ const field = aliases[munged];
97
+ Object.defineProperty(proto, munged, {
98
+ get() { return this[field]; },
99
+ });
100
+ }
101
+ }
102
+ return null;
103
+ }
package/src/squint/set.js CHANGED
@@ -1,43 +1,120 @@
1
1
  import * as core from './core.js';
2
+ import {
3
+ ICounted__count,
4
+ IAssociative__contains_key_QMARK_,
5
+ ICollection__conj,
6
+ ISet__disjoin,
7
+ IEditableCollection__as_transient,
8
+ ITransientCollection__conj_BANG_,
9
+ ITransientCollection__persistent_BANG_,
10
+ ITransientSet__disjoin_BANG_,
11
+ } from './core.js';
2
12
 
3
13
  function _bubble_max_key(k, coll) {
4
14
  const max = core.max_key(k, ...coll);
5
15
  return [max, ...coll.filter(x => x !== max)];
6
16
  }
7
17
 
18
+ // a js/Set or set-like with reference .has/.add (SortedSet); a persistent
19
+ // set from squint.immutable dispatches through core instead
20
+ function jsSetLike(x) {
21
+ return x instanceof Set || (x != null && typeof x.has === 'function' && typeof x.add === 'function');
22
+ }
23
+
24
+ // the persistent paths dispatch through the slot symbols directly: the
25
+ // symbols are tiny consts, where the core wrapper fns (count, conj!, ...)
26
+ // drag their whole dispatch chains into js-Set-only bundles
27
+ function setSize(x) {
28
+ return typeof x.size === 'number' ? x.size : x[ICounted__count](x);
29
+ }
30
+
31
+ function setHas(x, e) {
32
+ return jsSetLike(x) ? x.has(e) : x[IAssociative__contains_key_QMARK_](x, e);
33
+ }
34
+
35
+ // fold elements into a copy of target, preserving its type: js/Set mutates a
36
+ // copy, a protocol set goes through its transient when it has one and folds
37
+ // persistent -conj otherwise (a set type need not implement transients)
38
+ function addAll(target, elems) {
39
+ if (jsSetLike(target)) {
40
+ const res = new Set(target);
41
+ for (const e of elems) res.add(e);
42
+ return res;
43
+ }
44
+ const es = core.iterable(elems);
45
+ if (target[IEditableCollection__as_transient] !== undefined) {
46
+ let t = target[IEditableCollection__as_transient](target);
47
+ for (const e of es) t = t[ITransientCollection__conj_BANG_](t, e);
48
+ return t[ITransientCollection__persistent_BANG_](t);
49
+ }
50
+ let res = target;
51
+ for (const e of es) res = res[ICollection__conj](res, e);
52
+ return res;
53
+ }
54
+
55
+ // remove each elem for which pred is true, preserving the set's type
56
+ function removeWhere(xset, pred) {
57
+ const es = core.iterable(xset);
58
+ if (xset[IEditableCollection__as_transient] !== undefined) {
59
+ let t = xset[IEditableCollection__as_transient](xset);
60
+ for (const e of es) {
61
+ if (pred(e)) t = t[ITransientSet__disjoin_BANG_](t, e);
62
+ }
63
+ return t[ITransientCollection__persistent_BANG_](t);
64
+ }
65
+ let res = xset;
66
+ for (const e of es) {
67
+ if (pred(e)) res = res[ISet__disjoin](res, e);
68
+ }
69
+ return res;
70
+ }
71
+
8
72
  function _intersection2(x, y) {
9
- if (x.size > y.size) {
73
+ if (setSize(x) > setSize(y)) {
10
74
  const tmp = y;
11
75
  y = x;
12
76
  x = tmp;
13
77
  }
14
- const res = new Set();
15
- for (const elem of x) {
16
- if (y.has(elem)) {
17
- res.add(elem);
78
+ if (jsSetLike(x)) {
79
+ const res = new Set();
80
+ for (const elem of x) {
81
+ if (setHas(y, elem)) {
82
+ res.add(elem);
83
+ }
18
84
  }
85
+ return res;
19
86
  }
20
- return res;
87
+ // protocol set: disj the non-members, keeping the type and sharing
88
+ return removeWhere(x, (elem) => !setHas(y, elem));
21
89
  }
22
90
 
23
91
  export function intersection(...xs) {
24
92
  switch (xs.length) {
25
93
  case 0: return null;
26
94
  case 1: return xs[0];
27
- case 2: return xs[0].size > xs[1].size ?
28
- _intersection2(xs[0], xs[1]) :
29
- _intersection2(xs[1], xs[0]);
30
- default: return _bubble_max_key((x) => 0 - x.size, xs).reduce(_intersection2);
95
+ case 2: return _intersection2(xs[0], xs[1]);
96
+ default: return _bubble_max_key((x) => 0 - setSize(x), xs).reduce(_intersection2);
31
97
  }
32
98
  }
33
99
 
34
100
  function _difference2(x, y) {
35
- const res = new Set();
36
- for (const elem of x) {
37
- if (!y.has(elem)) {
38
- res.add(elem);
101
+ if (jsSetLike(x)) {
102
+ const res = new Set();
103
+ for (const elem of x) {
104
+ if (!setHas(y, elem)) {
105
+ res.add(elem);
106
+ }
39
107
  }
108
+ return res;
109
+ }
110
+ const ys = core.iterable(y);
111
+ if (x[IEditableCollection__as_transient] !== undefined) {
112
+ let t = x[IEditableCollection__as_transient](x);
113
+ for (const elem of ys) t = t[ITransientSet__disjoin_BANG_](t, elem);
114
+ return t[ITransientCollection__persistent_BANG_](t);
40
115
  }
116
+ let res = x;
117
+ for (const elem of ys) res = res[ISet__disjoin](res, elem);
41
118
  return res;
42
119
  }
43
120
 
@@ -51,32 +128,31 @@ export function difference(...xs) {
51
128
  }
52
129
 
53
130
  function _union2(x, y) {
54
- const res = new Set(x);
55
- for (const elem of y) {
56
- res.add(elem);
131
+ if (setSize(x) < setSize(y)) {
132
+ const tmp = y;
133
+ y = x;
134
+ x = tmp;
57
135
  }
58
- return res;
136
+ return addAll(x, y);
59
137
  }
60
138
 
61
139
  export function union(...xs) {
62
140
  switch (xs.length) {
63
141
  case 0: return null;
64
142
  case 1: return xs[0];
65
- case 2: return xs[0].size > xs[1].size ?
66
- _union2(xs[0], xs[1]) :
67
- _union2(xs[1], xs[0]);
68
- default: return _bubble_max_key((x) => x.size, xs).reduce(_union2);
143
+ case 2: return _union2(xs[0], xs[1]);
144
+ default: return _bubble_max_key((x) => setSize(x), xs).reduce(_union2);
69
145
  }
70
146
  }
71
147
 
72
148
  function _subset_QMARK_2(x, y) {
73
- for (const elem of x) {
74
- if (!y.has(elem)) {
149
+ for (const elem of core.iterable(x)) {
150
+ if (!setHas(y, elem)) {
75
151
  return false;
76
152
  }
77
153
  }
78
154
  return true;
79
- }
155
+ }
80
156
 
81
157
  export function subset_QMARK_(x, y) {
82
158
  if (x === undefined) {
@@ -85,21 +161,12 @@ export function subset_QMARK_(x, y) {
85
161
  if (y === undefined) {
86
162
  return false;
87
163
  }
88
- if (x.size > y.size) {
164
+ if (setSize(x) > setSize(y)) {
89
165
  return false;
90
166
  }
91
167
  return _subset_QMARK_2(x, y);
92
168
  }
93
169
 
94
- function _superset_QMARK_2(x, y) {
95
- for (const elem of x) {
96
- if (!y.has(elem)) {
97
- return false;
98
- }
99
- }
100
- return true;
101
- }
102
-
103
170
  export function superset_QMARK_(x, y) {
104
171
  if (x === undefined) {
105
172
  return true;
@@ -107,28 +174,44 @@ export function superset_QMARK_(x, y) {
107
174
  if (y === undefined) {
108
175
  return true;
109
176
  }
110
- if (x.size < y.size) {
177
+ if (setSize(x) < setSize(y)) {
111
178
  return false;
112
179
  }
113
- return _superset_QMARK_2(y, x);
180
+ return _subset_QMARK_2(y, x);
114
181
  }
115
182
 
116
183
  export function select(pred, xset) {
117
184
  if (xset === undefined) {
118
185
  return null;
119
186
  }
120
- const res = new Set();
121
- for (const elem of xset) {
122
- if (core.truth_(pred(elem))) {
123
- res.add(elem);
187
+ if (jsSetLike(xset)) {
188
+ const res = new Set();
189
+ for (const elem of xset) {
190
+ if (core.truth_(pred(elem))) {
191
+ res.add(elem);
192
+ }
124
193
  }
194
+ return res;
125
195
  }
126
- return res;
196
+ return removeWhere(xset, (elem) => !core.truth_(pred(elem)));
197
+ }
198
+
199
+ // true when m is an immutable slot-map: mutate-in-place helpers would corrupt it
200
+ function slotMap(m) {
201
+ return m != null && m[core.IAssociative__assoc] !== undefined;
127
202
  }
128
203
 
129
204
  export function rename_keys(map, kmap) {
130
205
  const ks = core.keys(kmap);
131
206
  let without = core.dissoc(map, ...ks);
207
+ if (slotMap(without)) {
208
+ return ks.reduce((m, k) => {
209
+ if (core.contains_QMARK_(map, k)) {
210
+ return core.assoc(m, core.get(kmap, k), core.get(map, k));
211
+ }
212
+ return m;
213
+ }, without);
214
+ }
132
215
  if (without === map) {
133
216
  without = {...map};
134
217
  }
@@ -142,18 +225,31 @@ export function rename_keys(map, kmap) {
142
225
  }
143
226
 
144
227
  export function rename(xrel, kmap) {
145
- return core.set(core.map(x => rename_keys(x, kmap), xrel));
228
+ return into_set_like(xrel, core.map(x => rename_keys(x, kmap), xrel));
146
229
  }
147
230
 
148
231
  export function project(xrel, ...ks) {
149
- return core.set(core.map(x => core.select_keys(x, ...ks), xrel));
232
+ return into_set_like(xrel, core.map(x => core.select_keys(x, ...ks), xrel));
233
+ }
234
+
235
+ // an empty set of the same kind as rel (a persistent set stays persistent),
236
+ // filled from elems
237
+ function into_set_like(rel, elems) {
238
+ const empty = rel != null && !jsSetLike(rel) && rel[ISet__disjoin] !== undefined
239
+ ? core.empty(rel)
240
+ : new Set();
241
+ return addAll(empty, elems);
150
242
  }
151
243
 
152
244
  export function map_invert(xmap) {
153
245
  if (xmap === undefined) {
154
246
  return {};
155
247
  }
156
- return core.reduce_kv((m, k, v) => core.assoc_BANG_(m, v, k), core.empty(xmap), xmap);
248
+ const empty = core.empty(xmap);
249
+ if (slotMap(empty)) {
250
+ return core.reduce_kv((m, k, v) => core.assoc(m, v, k), empty, xmap);
251
+ }
252
+ return core.reduce_kv((m, k, v) => core.assoc_BANG_(m, v, k), empty, xmap);
157
253
  }
158
254
 
159
255
  export function join(xrel, yrel, kmap) {
@@ -179,4 +275,4 @@ export function join(xrel, yrel, kmap) {
179
275
  return found ? core.reduce((acc, y) => acc.add(core.merge(y, x)), ret, found) : ret;
180
276
  }, new Set(), s);
181
277
  }
182
- }
278
+ }