Skip to content

Commit a7294db

Browse files
committed
Merge branch 'd3.set' of git://github.com/jfirebaugh/d3 into 3.1.0
2 parents f6668a8 + 1f422ae commit a7294db

5 files changed

Lines changed: 206 additions & 4 deletions

File tree

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ d3.core.js: \
3333
src/core/class.js \
3434
src/core/array.js \
3535
src/core/map.js \
36+
src/core/set.js \
3637
src/core/identity.js \
3738
src/core/true.js \
3839
src/core/functor.js \

d3.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,39 @@ d3 = function() {
107107
}
108108
});
109109
var d3_map_prefix = "\0", d3_map_prefixCode = d3_map_prefix.charCodeAt(0);
110+
d3.set = function(array) {
111+
var set = new d3_Set();
112+
if (array) for (var i = 0; i < array.length; i++) set.add(array[i]);
113+
return set;
114+
};
115+
function d3_Set() {}
116+
d3_class(d3_Set, {
117+
has: function(value) {
118+
return d3_map_prefix + value in this;
119+
},
120+
add: function(value) {
121+
this[d3_map_prefix + value] = true;
122+
return value;
123+
},
124+
remove: function(value) {
125+
value = d3_map_prefix + value;
126+
return value in this && delete this[value];
127+
},
128+
values: function() {
129+
var values = [];
130+
this.forEach(function(value) {
131+
values.push(value);
132+
});
133+
return values;
134+
},
135+
forEach: function(f) {
136+
for (var value in this) {
137+
if (value.charCodeAt(0) === d3_map_prefixCode) {
138+
f.call(this, value.substring(1));
139+
}
140+
}
141+
}
142+
});
110143
function d3_identity(d) {
111144
return d;
112145
}

d3.min.js

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/core/set.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
d3.set = function(array) {
2+
var set = new d3_Set();
3+
if (array) for (var i = 0; i < array.length; i++) set.add(array[i]);
4+
return set;
5+
};
6+
7+
function d3_Set() {}
8+
9+
d3_class(d3_Set, {
10+
has: function(value) {
11+
return d3_map_prefix + value in this;
12+
},
13+
add: function(value) {
14+
this[d3_map_prefix + value] = true;
15+
return value;
16+
},
17+
remove: function(value) {
18+
value = d3_map_prefix + value;
19+
return value in this && delete this[value];
20+
},
21+
values: function() {
22+
var values = [];
23+
this.forEach(function(value) {
24+
values.push(value);
25+
});
26+
return values;
27+
},
28+
forEach: function(f) {
29+
for (var value in this) {
30+
if (value.charCodeAt(0) === d3_map_prefixCode) {
31+
f.call(this, value.substring(1));
32+
}
33+
}
34+
}
35+
});

test/core/set-test.js

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
require("../env");
2+
3+
var vows = require("vows"),
4+
assert = require("assert");
5+
6+
var suite = vows.describe("d3.set");
7+
8+
suite.addBatch({
9+
"constructor": {
10+
"set() returns an empty set": function() {
11+
var set = d3.set();
12+
assert.deepEqual(set.values(), []);
13+
},
14+
"set(null) returns an empty set": function() {
15+
var set = d3.set(null);
16+
assert.deepEqual(set.values(), []);
17+
},
18+
"set(array) adds array entries": function() {
19+
var set = d3.set(["foo"]);
20+
assert.isTrue(set.has("foo"));
21+
var set = d3.set(["foo", "bar"]);
22+
assert.isTrue(set.has("foo"));
23+
assert.isTrue(set.has("bar"));
24+
}
25+
},
26+
"forEach": {
27+
"empty sets have an empty values array": function() {
28+
var set = d3.set();
29+
assert.deepEqual(set.values(), []);
30+
set.add("foo");
31+
assert.deepEqual(set.values(), ["foo"]);
32+
set.remove("foo");
33+
assert.deepEqual(set.values(), []);
34+
},
35+
"values are returned in arbitrary order": function() {
36+
var set = d3.set(["foo", "bar"]);
37+
assert.deepEqual(set.values().sort(d3.ascending()), ["bar", "foo"]);
38+
var set = d3.set(["bar", "foo"]);
39+
assert.deepEqual(set.values().sort(d3.ascending()), ["bar", "foo"]);
40+
},
41+
"observes changes via add and remove": function() {
42+
var set = d3.set(["foo", "bar"]);
43+
assert.deepEqual(set.values().sort(d3.ascending()), ["bar", "foo"]);
44+
set.remove("foo");
45+
assert.deepEqual(set.values(), ["bar"]);
46+
set.add("bar");
47+
assert.deepEqual(set.values(), ["bar"]);
48+
set.add("foo");
49+
assert.deepEqual(set.values().sort(d3.ascending()), ["bar", "foo"]);
50+
set.remove("bar");
51+
assert.deepEqual(set.values(), ["foo"]);
52+
set.remove("foo");
53+
assert.deepEqual(set.values(), []);
54+
set.remove("foo");
55+
assert.deepEqual(set.values(), []);
56+
}
57+
},
58+
"values": {
59+
"returns an array of string values": function() {
60+
var set = d3.set(["foo", "bar"]);
61+
assert.deepEqual(set.values().sort(), ["bar", "foo"]);
62+
}
63+
},
64+
"has": {
65+
"empty sets do not have object built-ins": function() {
66+
var set = d3.set();
67+
assert.isFalse(set.has("__proto__"));
68+
assert.isFalse(set.has("hasOwnProperty"));
69+
},
70+
"coerces values to strings": function() {
71+
var set = d3.set(["42", "null", "undefined"]);
72+
assert.isTrue(set.has(42));
73+
assert.isTrue(set.has(null));
74+
assert.isTrue(set.has(undefined));
75+
},
76+
"observes changes via add and remove": function() {
77+
var set = d3.set(["foo"]);
78+
assert.isTrue(set.has("foo"));
79+
set.add("foo");
80+
assert.isTrue(set.has("foo"));
81+
set.remove("foo");
82+
assert.isFalse(set.has("foo"));
83+
set.add("foo");
84+
assert.isTrue(set.has("foo"));
85+
},
86+
"returns undefined for missing values": function() {
87+
var set = d3.set(["foo"]);
88+
assert.isFalse(set.has("bar"));
89+
}
90+
},
91+
"add": {
92+
"returns the set value": function() {
93+
var set = d3.set();
94+
assert.equal(set.add("foo"), "foo");
95+
},
96+
"can add values using built-in names": function() {
97+
var set = d3.set();
98+
set.add("__proto__");
99+
assert.isTrue(set.has("__proto__"));
100+
},
101+
"coerces values to strings": function() {
102+
var set = d3.set();
103+
set.add(42);
104+
assert.isTrue(set.has(42));
105+
set.add(null);
106+
assert.isTrue(set.has(null));
107+
set.add(undefined);
108+
assert.isTrue(set.has(undefined));
109+
assert.deepEqual(set.values().sort(), ["42", "null", "undefined"]);
110+
},
111+
"can add null, undefined or empty string values": function() {
112+
var set = d3.set();
113+
set.add("");
114+
set.add("null");
115+
set.add("undefined");
116+
assert.isTrue(set.has(""));
117+
assert.isTrue(set.has("null"));
118+
assert.isTrue(set.has("undefined"));
119+
}
120+
},
121+
"remove": {
122+
"returns true if the value was removed": function() {
123+
var set = d3.set(["foo"]);
124+
assert.isTrue(set.remove("foo"));
125+
},
126+
"returns false if the value is not an element": function() {
127+
var set = d3.set();
128+
assert.isFalse(set.remove("foo"));
129+
}
130+
}
131+
});
132+
133+
suite.export(module);

0 commit comments

Comments
 (0)