diff options
author | Rogan Creswick <creswick@galois.com> | 2012-03-30 17:07:02 -0700 |
---|---|---|
committer | Rogan Creswick <creswick@galois.com> | 2012-03-30 17:07:02 -0700 |
commit | f6ab6622aab00fe7c2f4c3dc41f786ebbe0f0d73 (patch) | |
tree | 870111038542cd27153e1396ebdc063573249689 /contexts/data/lib/closure-library/closure/goog/structs |
initial revision
Diffstat (limited to 'contexts/data/lib/closure-library/closure/goog/structs')
113 files changed, 24882 insertions, 0 deletions
diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/all-wcprops b/contexts/data/lib/closure-library/closure/goog/structs/.svn/all-wcprops new file mode 100644 index 0000000..b2c333f --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/all-wcprops @@ -0,0 +1,227 @@ +K 25 +svn:wc:ra_dav:version-url +V 45 +/svn/!svn/ver/1472/trunk/closure/goog/structs +END +linkedmap.js +K 25 +svn:wc:ra_dav:version-url +V 57 +/svn/!svn/ver/850/trunk/closure/goog/structs/linkedmap.js +END +map_test.html +K 25 +svn:wc:ra_dav:version-url +V 59 +/svn/!svn/ver/1464/trunk/closure/goog/structs/map_test.html +END +treenode.js +K 25 +svn:wc:ra_dav:version-url +V 57 +/svn/!svn/ver/1273/trunk/closure/goog/structs/treenode.js +END +structs.js +K 25 +svn:wc:ra_dav:version-url +V 56 +/svn/!svn/ver/1472/trunk/closure/goog/structs/structs.js +END +prioritypool.js +K 25 +svn:wc:ra_dav:version-url +V 61 +/svn/!svn/ver/1302/trunk/closure/goog/structs/prioritypool.js +END +queue_test.html +K 25 +svn:wc:ra_dav:version-url +V 60 +/svn/!svn/ver/850/trunk/closure/goog/structs/queue_test.html +END +heap.js +K 25 +svn:wc:ra_dav:version-url +V 53 +/svn/!svn/ver/1089/trunk/closure/goog/structs/heap.js +END +set_test.html +K 25 +svn:wc:ra_dav:version-url +V 58 +/svn/!svn/ver/850/trunk/closure/goog/structs/set_test.html +END +queue.js +K 25 +svn:wc:ra_dav:version-url +V 53 +/svn/!svn/ver/850/trunk/closure/goog/structs/queue.js +END +collection.js +K 25 +svn:wc:ra_dav:version-url +V 58 +/svn/!svn/ver/894/trunk/closure/goog/structs/collection.js +END +treenode_test.html +K 25 +svn:wc:ra_dav:version-url +V 64 +/svn/!svn/ver/1273/trunk/closure/goog/structs/treenode_test.html +END +structs_test.html +K 25 +svn:wc:ra_dav:version-url +V 62 +/svn/!svn/ver/850/trunk/closure/goog/structs/structs_test.html +END +inversionmap_test.html +K 25 +svn:wc:ra_dav:version-url +V 67 +/svn/!svn/ver/850/trunk/closure/goog/structs/inversionmap_test.html +END +quadtree_test.html +K 25 +svn:wc:ra_dav:version-url +V 63 +/svn/!svn/ver/850/trunk/closure/goog/structs/quadtree_test.html +END +prioritypool_test.html +K 25 +svn:wc:ra_dav:version-url +V 67 +/svn/!svn/ver/850/trunk/closure/goog/structs/prioritypool_test.html +END +trie.js +K 25 +svn:wc:ra_dav:version-url +V 52 +/svn/!svn/ver/850/trunk/closure/goog/structs/trie.js +END +heap_test.html +K 25 +svn:wc:ra_dav:version-url +V 59 +/svn/!svn/ver/850/trunk/closure/goog/structs/heap_test.html +END +stringset_test.html +K 25 +svn:wc:ra_dav:version-url +V 64 +/svn/!svn/ver/850/trunk/closure/goog/structs/stringset_test.html +END +pool.js +K 25 +svn:wc:ra_dav:version-url +V 53 +/svn/!svn/ver/1024/trunk/closure/goog/structs/pool.js +END +quadtree.js +K 25 +svn:wc:ra_dav:version-url +V 56 +/svn/!svn/ver/850/trunk/closure/goog/structs/quadtree.js +END +inversionmap.js +K 25 +svn:wc:ra_dav:version-url +V 60 +/svn/!svn/ver/850/trunk/closure/goog/structs/inversionmap.js +END +priorityqueue_test.html +K 25 +svn:wc:ra_dav:version-url +V 68 +/svn/!svn/ver/850/trunk/closure/goog/structs/priorityqueue_test.html +END +map.js +K 25 +svn:wc:ra_dav:version-url +V 52 +/svn/!svn/ver/1472/trunk/closure/goog/structs/map.js +END +collection_test.html +K 25 +svn:wc:ra_dav:version-url +V 65 +/svn/!svn/ver/894/trunk/closure/goog/structs/collection_test.html +END +stringset.js +K 25 +svn:wc:ra_dav:version-url +V 57 +/svn/!svn/ver/850/trunk/closure/goog/structs/stringset.js +END +simplepool.js +K 25 +svn:wc:ra_dav:version-url +V 59 +/svn/!svn/ver/1024/trunk/closure/goog/structs/simplepool.js +END +node.js +K 25 +svn:wc:ra_dav:version-url +V 52 +/svn/!svn/ver/850/trunk/closure/goog/structs/node.js +END +circularbuffer_test.html +K 25 +svn:wc:ra_dav:version-url +V 69 +/svn/!svn/ver/850/trunk/closure/goog/structs/circularbuffer_test.html +END +priorityqueue.js +K 25 +svn:wc:ra_dav:version-url +V 61 +/svn/!svn/ver/850/trunk/closure/goog/structs/priorityqueue.js +END +avltree_test.html +K 25 +svn:wc:ra_dav:version-url +V 62 +/svn/!svn/ver/893/trunk/closure/goog/structs/avltree_test.html +END +trie_test.html +K 25 +svn:wc:ra_dav:version-url +V 59 +/svn/!svn/ver/850/trunk/closure/goog/structs/trie_test.html +END +set.js +K 25 +svn:wc:ra_dav:version-url +V 52 +/svn/!svn/ver/1472/trunk/closure/goog/structs/set.js +END +linkedmap_test.html +K 25 +svn:wc:ra_dav:version-url +V 64 +/svn/!svn/ver/850/trunk/closure/goog/structs/linkedmap_test.html +END +circularbuffer.js +K 25 +svn:wc:ra_dav:version-url +V 62 +/svn/!svn/ver/850/trunk/closure/goog/structs/circularbuffer.js +END +set_perf.html +K 25 +svn:wc:ra_dav:version-url +V 58 +/svn/!svn/ver/850/trunk/closure/goog/structs/set_perf.html +END +pool_test.html +K 25 +svn:wc:ra_dav:version-url +V 59 +/svn/!svn/ver/850/trunk/closure/goog/structs/pool_test.html +END +avltree.js +K 25 +svn:wc:ra_dav:version-url +V 55 +/svn/!svn/ver/894/trunk/closure/goog/structs/avltree.js +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/entries b/contexts/data/lib/closure-library/closure/goog/structs/.svn/entries new file mode 100644 index 0000000..9c736c5 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/entries @@ -0,0 +1,1286 @@ +10 + +dir +1494 +http://closure-library.googlecode.com/svn/trunk/closure/goog/structs +http://closure-library.googlecode.com/svn + + + +2011-12-13T22:20:28.000000Z +1472 +ccalabro@google.com + + + + + + + + + + + + + + +0b95b8e8-c90f-11de-9d4f-f947ee5921c8 + +linkedmap.js +file + + + + +2011-12-23T22:42:32.866385Z +1d1a4d93f5410375e2d67ea6864d8fde +2011-04-12T20:35:47.000000Z +850 +diegosalas@google.com +has-props + + + + + + + + + + + + + + + + + + + + +13230 + +map_test.html +file + + + + +2011-12-23T22:42:32.866385Z +58bff88f087dce09b4ddd23243c9902c +2011-12-09T02:22:04.000000Z +1464 +terryok@google.com +has-props + + + + + + + + + + + + + + + + + + + + +10508 + +treenode.js +file + + + + +2011-12-23T22:42:32.866385Z +69486be5e3128cb262846961fe3c25db +2011-09-08T08:46:43.000000Z +1273 +pallosp@google.com +has-props + + + + + + + + + + + + + + + + + + + + +12017 + +structs.js +file + + + + +2011-12-23T22:42:32.867385Z +74176fd655eb69cc7cf5d789e4d4d255 +2011-12-13T22:20:28.000000Z +1472 +ccalabro@google.com +has-props + + + + + + + + + + + + + + + + + + + + +11116 + +prioritypool.js +file + + + + +2011-12-23T22:42:32.867385Z +4434761ca03dda42a4b58f39590f0fb1 +2011-09-27T00:20:47.000000Z +1302 +bmccann@google.com +has-props + + + + + + + + + + + + + + + + + + + + +5498 + +queue_test.html +file + + + + +2011-12-23T22:42:32.867385Z +283a41a7fc978a9234c707e05487ff30 +2011-04-12T20:35:47.000000Z +850 +diegosalas@google.com +has-props + + + + + + + + + + + + + + + + + + + + +4266 + +heap.js +file + + + + +2011-12-23T22:42:32.867385Z +33b081d2c902ef579718205559db4b8e +2011-07-01T12:47:03.000000Z +1089 +pallosp@google.com +has-props + + + + + + + + + + + + + + + + + + + + +8671 + +set_test.html +file + + + + +2011-12-23T22:42:32.868385Z +52f46f8e2162d784f30f6f5a3696e92b +2011-04-12T20:35:47.000000Z +850 +diegosalas@google.com +has-props + + + + + + + + + + + + + + + + + + + + +15377 + +queue.js +file + + + + +2011-12-23T22:42:32.868385Z +93ebf7c7da9e02a050fdc73a98540a89 +2011-04-12T20:35:47.000000Z +850 +diegosalas@google.com +has-props + + + + + + + + + + + + + + + + + + + + +3774 + +collection.js +file + + + + +2011-12-23T22:42:32.869385Z +f22e5fb1e4f3962080d0208d69965797 +2011-04-28T00:46:08.000000Z +894 +nnaze@google.com +has-props + + + + + + + + + + + + + + + + + + + + +1349 + +treenode_test.html +file + + + + +2011-12-23T22:42:32.869385Z +d7b29eb10be5c97bc31eb4cd48b11bd7 +2011-09-08T08:46:43.000000Z +1273 +pallosp@google.com +has-props + + + + + + + + + + + + + + + + + + + + +13124 + +structs_test.html +file + + + + +2011-12-23T22:42:32.869385Z +5c85580c58ff3df030a53e1240e8c5e1 +2011-04-12T20:35:47.000000Z +850 +diegosalas@google.com +has-props + + + + + + + + + + + + + + + + + + + + +26975 + +inversionmap_test.html +file + + + + +2011-12-23T22:42:32.869385Z +e0af3883e2267d2f9e8389619c382f08 +2011-04-12T20:35:47.000000Z +850 +diegosalas@google.com +has-props + + + + + + + + + + + + + + + + + + + + +5279 + +quadtree_test.html +file + + + + +2011-12-23T22:42:32.870385Z +8c01f1655e71a64b04b04ce5ca953346 +2011-04-12T20:35:47.000000Z +850 +diegosalas@google.com +has-props + + + + + + + + + + + + + + + + + + + + +5579 + +prioritypool_test.html +file + + + + +2011-12-23T22:42:32.870385Z +e588d717c28ec29bf8bbb3accf5d4d3b +2011-04-12T20:35:47.000000Z +850 +diegosalas@google.com +has-props + + + + + + + + + + + + + + + + + + + + +11241 + +trie.js +file + + + + +2011-12-23T22:42:32.870385Z +a1da7893ceec2444f1e3f4fef7eea595 +2011-04-12T20:35:47.000000Z +850 +diegosalas@google.com +has-props + + + + + + + + + + + + + + + + + + + + +11094 + +heap_test.html +file + + + + +2011-12-23T22:42:32.870385Z +25631c554e406eed02a1a2bf83aa7b74 +2011-04-12T20:35:47.000000Z +850 +diegosalas@google.com +has-props + + + + + + + + + + + + + + + + + + + + +5233 + +stringset_test.html +file + + + + +2011-12-23T22:42:32.871385Z +4e5a13e15ad12535269f9dbfed74d69f +2011-04-12T20:35:47.000000Z +850 +diegosalas@google.com +has-props + + + + + + + + + + + + + + + + + + + + +8518 + +pool.js +file + + + + +2011-12-23T22:42:32.871385Z +1d6f600dfd8a6945b9c55c93507e8224 +2011-06-10T12:08:17.000000Z +1024 +pallosp@google.com +has-props + + + + + + + + + + + + + + + + + + + + +10544 + +quadtree.js +file + + + + +2011-12-23T22:42:32.871385Z +93516469e492bce6a8cec09407636a98 +2011-04-12T20:35:47.000000Z +850 +diegosalas@google.com +has-props + + + + + + + + + + + + + + + + + + + + +15959 + +inversionmap.js +file + + + + +2011-12-23T22:42:32.871385Z +81b590e2ba1b157504cebf25c756ffcf +2011-04-12T20:35:47.000000Z +850 +diegosalas@google.com +has-props + + + + + + + + + + + + + + + + + + + + +5048 + +priorityqueue_test.html +file + + + + +2011-12-23T22:42:32.872385Z +c071bd55dd0ddc9cca59b466e473583d +2011-04-12T20:35:47.000000Z +850 +diegosalas@google.com +has-props + + + + + + + + + + + + + + + + + + + + +4346 + +map.js +file + + + + +2011-12-23T22:42:32.872385Z +8edd6885e649260b336ef4f2d0f8fd05 +2011-12-13T22:20:28.000000Z +1472 +ccalabro@google.com +has-props + + + + + + + + + + + + + + + + + + + + +12321 + +collection_test.html +file + + + + +2011-12-23T22:42:32.873385Z +9250c055315ad0d9824981d0900da956 +2011-04-28T00:46:08.000000Z +894 +nnaze@google.com +has-props + + + + + + + + + + + + + + + + + + + + +1361 + +stringset.js +file + + + + +2011-12-23T22:42:32.872385Z +270b9ebd91b05bedc57bbea65f0c788a +2011-04-12T20:35:47.000000Z +850 +diegosalas@google.com +has-props + + + + + + + + + + + + + + + + + + + + +11599 + +simplepool.js +file + + + + +2011-12-23T22:42:32.873385Z +e54248964695a611a5f5c5cbabb1ef55 +2011-06-10T12:08:17.000000Z +1024 +pallosp@google.com +has-props + + + + + + + + + + + + + + + + + + + + +5876 + +node.js +file + + + + +2011-12-23T22:42:32.874385Z +3dc510de90c9751b771412a6d4675d37 +2011-04-12T20:35:47.000000Z +850 +diegosalas@google.com +has-props + + + + + + + + + + + + + + + + + + + + +1664 + +circularbuffer_test.html +file + + + + +2011-12-23T22:42:32.874385Z +1370cc8894fe3487d5be3d1df175b180 +2011-04-12T20:35:47.000000Z +850 +diegosalas@google.com +has-props + + + + + + + + + + + + + + + + + + + + +2756 + +priorityqueue.js +file + + + + +2011-12-23T22:42:32.874385Z +827ef3c1ad0dae638c1a7a1ca391debc +2011-04-12T20:35:47.000000Z +850 +diegosalas@google.com +has-props + + + + + + + + + + + + + + + + + + + + +1856 + +avltree_test.html +file + + + + +2011-12-23T22:42:32.874385Z +48601942752ffd00f4496783f218ae86 +2011-04-27T21:45:37.000000Z +893 +nnaze@google.com +has-props + + + + + + + + + + + + + + + + + + + + +6932 + +trie_test.html +file + + + + +2011-12-23T22:42:32.875385Z +652a0fda0df46b6eaa7387069d3c86e2 +2011-04-12T20:35:47.000000Z +850 +diegosalas@google.com +has-props + + + + + + + + + + + + + + + + + + + + +13684 + +set.js +file + + + + +2011-12-23T22:42:32.875385Z +d80fdbaf09feedebfcb7e5fbf6d9d4c4 +2011-12-13T22:20:28.000000Z +1472 +ccalabro@google.com +has-props + + + + + + + + + + + + + + + + + + + + +8142 + +linkedmap_test.html +file + + + + +2011-12-23T22:42:32.875385Z +dbd767c587a6dc85c05050f89133ab2c +2011-04-12T20:35:47.000000Z +850 +diegosalas@google.com +has-props + + + + + + + + + + + + + + + + + + + + +7703 + +circularbuffer.js +file + + + + +2011-12-23T22:42:32.875385Z +efbd3a5428640405306996c8f0d11c9b +2011-04-12T20:35:47.000000Z +850 +diegosalas@google.com +has-props + + + + + + + + + + + + + + + + + + + + +5626 + +set_perf.html +file + + + + +2011-12-23T22:42:32.876385Z +17541e672e7d704bb8da04b03ebbba6f +2011-04-12T20:35:47.000000Z +850 +diegosalas@google.com +has-props + + + + + + + + + + + + + + + + + + + + +7002 + +pool_test.html +file + + + + +2011-12-23T22:42:32.876385Z +7ee93b27afb05e29c396822a07e9e476 +2011-04-12T20:35:47.000000Z +850 +diegosalas@google.com +has-props + + + + + + + + + + + + + + + + + + + + +6782 + +avltree.js +file + + + + +2011-12-23T22:42:32.876385Z +514e3a8a68668c89fb661140a7a950c7 +2011-04-28T00:46:08.000000Z +894 +nnaze@google.com +has-props + + + + + + + + + + + + + + + + + + + + +22646 + diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/avltree.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/avltree.js.svn-base new file mode 100644 index 0000000..530636b --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/avltree.js.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 15 +text/javascript +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/avltree_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/avltree_test.html.svn-base new file mode 100644 index 0000000..d356868 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/avltree_test.html.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 9 +text/html +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/circularbuffer.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/circularbuffer.js.svn-base new file mode 100644 index 0000000..530636b --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/circularbuffer.js.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 15 +text/javascript +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/circularbuffer_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/circularbuffer_test.html.svn-base new file mode 100644 index 0000000..d356868 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/circularbuffer_test.html.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 9 +text/html +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/collection.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/collection.js.svn-base new file mode 100644 index 0000000..530636b --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/collection.js.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 15 +text/javascript +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/collection_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/collection_test.html.svn-base new file mode 100644 index 0000000..d356868 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/collection_test.html.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 9 +text/html +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/heap.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/heap.js.svn-base new file mode 100644 index 0000000..530636b --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/heap.js.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 15 +text/javascript +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/heap_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/heap_test.html.svn-base new file mode 100644 index 0000000..d356868 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/heap_test.html.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 9 +text/html +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/inversionmap.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/inversionmap.js.svn-base new file mode 100644 index 0000000..530636b --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/inversionmap.js.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 15 +text/javascript +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/inversionmap_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/inversionmap_test.html.svn-base new file mode 100644 index 0000000..d356868 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/inversionmap_test.html.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 9 +text/html +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/linkedmap.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/linkedmap.js.svn-base new file mode 100644 index 0000000..530636b --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/linkedmap.js.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 15 +text/javascript +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/linkedmap_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/linkedmap_test.html.svn-base new file mode 100644 index 0000000..d356868 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/linkedmap_test.html.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 9 +text/html +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/map.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/map.js.svn-base new file mode 100644 index 0000000..530636b --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/map.js.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 15 +text/javascript +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/map_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/map_test.html.svn-base new file mode 100644 index 0000000..d356868 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/map_test.html.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 9 +text/html +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/node.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/node.js.svn-base new file mode 100644 index 0000000..530636b --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/node.js.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 15 +text/javascript +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/pool.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/pool.js.svn-base new file mode 100644 index 0000000..530636b --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/pool.js.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 15 +text/javascript +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/pool_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/pool_test.html.svn-base new file mode 100644 index 0000000..d356868 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/pool_test.html.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 9 +text/html +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/prioritypool.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/prioritypool.js.svn-base new file mode 100644 index 0000000..530636b --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/prioritypool.js.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 15 +text/javascript +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/prioritypool_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/prioritypool_test.html.svn-base new file mode 100644 index 0000000..d356868 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/prioritypool_test.html.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 9 +text/html +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/priorityqueue.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/priorityqueue.js.svn-base new file mode 100644 index 0000000..530636b --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/priorityqueue.js.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 15 +text/javascript +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/priorityqueue_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/priorityqueue_test.html.svn-base new file mode 100644 index 0000000..d356868 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/priorityqueue_test.html.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 9 +text/html +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/quadtree.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/quadtree.js.svn-base new file mode 100644 index 0000000..530636b --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/quadtree.js.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 15 +text/javascript +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/quadtree_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/quadtree_test.html.svn-base new file mode 100644 index 0000000..d356868 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/quadtree_test.html.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 9 +text/html +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/queue.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/queue.js.svn-base new file mode 100644 index 0000000..530636b --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/queue.js.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 15 +text/javascript +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/queue_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/queue_test.html.svn-base new file mode 100644 index 0000000..d356868 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/queue_test.html.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 9 +text/html +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/set.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/set.js.svn-base new file mode 100644 index 0000000..530636b --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/set.js.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 15 +text/javascript +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/set_perf.html.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/set_perf.html.svn-base new file mode 100644 index 0000000..d356868 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/set_perf.html.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 9 +text/html +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/set_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/set_test.html.svn-base new file mode 100644 index 0000000..d356868 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/set_test.html.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 9 +text/html +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/simplepool.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/simplepool.js.svn-base new file mode 100644 index 0000000..530636b --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/simplepool.js.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 15 +text/javascript +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/stringset.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/stringset.js.svn-base new file mode 100644 index 0000000..530636b --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/stringset.js.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 15 +text/javascript +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/stringset_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/stringset_test.html.svn-base new file mode 100644 index 0000000..d356868 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/stringset_test.html.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 9 +text/html +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/structs.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/structs.js.svn-base new file mode 100644 index 0000000..530636b --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/structs.js.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 15 +text/javascript +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/structs_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/structs_test.html.svn-base new file mode 100644 index 0000000..d356868 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/structs_test.html.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 9 +text/html +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/treenode.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/treenode.js.svn-base new file mode 100644 index 0000000..530636b --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/treenode.js.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 15 +text/javascript +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/treenode_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/treenode_test.html.svn-base new file mode 100644 index 0000000..d356868 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/treenode_test.html.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 9 +text/html +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/trie.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/trie.js.svn-base new file mode 100644 index 0000000..530636b --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/trie.js.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 15 +text/javascript +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/trie_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/trie_test.html.svn-base new file mode 100644 index 0000000..d356868 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/prop-base/trie_test.html.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 9 +text/html +END diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/avltree.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/avltree.js.svn-base new file mode 100644 index 0000000..306ab2a --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/avltree.js.svn-base @@ -0,0 +1,772 @@ +// Copyright 2007 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Datastructure: AvlTree. + * + * + * This file provides the implementation of an AVL-Tree datastructure. The tree + * maintains a set of unique values in a sorted order. The values can be + * accessed efficiently in their sorted order since the tree enforces an O(logn) + * maximum height. See http://en.wikipedia.org/wiki/Avl_tree for more detail. + * + * The big-O notation for all operations are below: + * <pre> + * Method big-O + * ---------------------------------------------------------------------------- + * - add O(logn) + * - remove O(logn) + * - clear O(1) + * - contains O(logn) + * - getCount O(1) + * - getMinimum O(1), or O(logn) when optional root is specified + * - getMaximum O(1), or O(logn) when optional root is specified + * - getHeight O(1) + * - getValues O(n) + * - inOrderTraverse O(logn + k), where k is number of traversed nodes + * - reverseOrderTraverse O(logn + k), where k is number of traversed nodes + * </pre> + */ + + +goog.provide('goog.structs.AvlTree'); +goog.provide('goog.structs.AvlTree.Node'); + +goog.require('goog.structs'); +goog.require('goog.structs.Collection'); + + + +/** + * Constructs an AVL-Tree, which uses the specified comparator to order its + * values. The values can be accessed efficiently in their sorted order since + * the tree enforces a O(logn) maximum height. + * + * @param {Function=} opt_comparator Function used to order the tree's nodes. + * @constructor + * @implements {goog.structs.Collection} + */ +goog.structs.AvlTree = function(opt_comparator) { + this.comparator_ = opt_comparator || + goog.structs.AvlTree.DEFAULT_COMPARATOR_; +}; + + +/** + * String comparison function used to compare values in the tree. This function + * is used by default if no comparator is specified in the tree's constructor. + * + * @param {string} a The first string. + * @param {string} b The second string. + * @return {number} -1 if a < b, 1 if a > b, 0 if a = b. + * @private + */ +goog.structs.AvlTree.DEFAULT_COMPARATOR_ = function(a, b) { + if (String(a) < String(b)) { + return -1; + } else if (String(a) > String(b)) { + return 1; + } + return 0; +}; + + +/** + * Pointer to the root node of the tree. + * + * @type {goog.structs.AvlTree.Node} + * @private + */ +goog.structs.AvlTree.prototype.root_ = null; + + +/** + * Comparison function used to compare values in the tree. This function should + * take two values, a and b, and return x where: + * <pre> + * x < 0 if a < b, + * x > 0 if a > b, + * x = 0 otherwise + * </pre> + * + * @type {Function} + * @private + */ +goog.structs.AvlTree.prototype.comparator_ = null; + + +/** + * Pointer to the node with the smallest value in the tree. + * + * @type {goog.structs.AvlTree.Node} + * @private + */ +goog.structs.AvlTree.prototype.minNode_ = null; + + +/** + * Pointer to the node with the largest value in the tree. + * + * @type {goog.structs.AvlTree.Node} + * @private + */ +goog.structs.AvlTree.prototype.maxNode_ = null; + + +/** + * Keeps track of the number of nodes in the tree. + * + * @type {number} + * @private + */ +goog.structs.AvlTree.prototype.count_ = 0; + + +/** + * Inserts a node into the tree with the specified value if the tree does + * not already contain a node with the specified value. If the value is + * inserted, the tree is balanced to enforce the AVL-Tree height property. + * + * @param {*} value Value to insert into the tree. + * @return {boolean} Whether value was inserted into the tree. + */ +goog.structs.AvlTree.prototype.add = function(value) { + // If the tree is empty, create a root node with the specified value + if (this.root_ == null) { + this.root_ = new goog.structs.AvlTree.Node(value); + this.minNode_ = this.root_; + this.maxNode_ = this.root_; + this.count_ = 1; + return true; + } + + // Assume a node is not added and change status when one is + var retStatus = false; + + // Depth traverse the tree and insert the value if we reach a null node + this.traverse_(function(node) { + var retNode = null; + if (this.comparator_(node.value, value) > 0) { + retNode = node.left; + if (node.left == null) { + var newNode = new goog.structs.AvlTree.Node(value, node); + node.left = newNode; + if (node == this.minNode_) { + this.minNode_ = newNode; + } + retStatus = true; // Value was added to tree + this.balance_(node); // Maintain the AVL-tree balance + } + } else if (this.comparator_(node.value, value) < 0) { + retNode = node.right; + if (node.right == null) { + var newNode = new goog.structs.AvlTree.Node(value, node); + node.right = newNode; + if (node == this.maxNode_) { + this.maxNode_ = newNode; + } + retStatus = true; // Value was added to tree + this.balance_(node); // Maintain the AVL-tree balance + } + } + return retNode; // If null, we'll stop traversing the tree + }); + + // If a node was added, increment count + if (retStatus) { + this.count_ += 1; + } + + // Return true if a node was added, false otherwise + return retStatus; +}; + + +/** + * Removes a node from the tree with the specified value if the tree contains a + * node with this value. If a node is removed the tree is balanced to enforce + * the AVL-Tree height property. The value of the removed node is returned. + * + * @param {*} value Value to find and remove from the tree. + * @return {*} The value of the removed node or null if the value was not in + * the tree. + */ +goog.structs.AvlTree.prototype.remove = function(value) { + // Assume the value is not removed and set the value when it is removed + var retValue = null; + + // Depth traverse the tree and remove the value if we find it + this.traverse_(function(node) { + var retNode = null; + if (this.comparator_(node.value, value) > 0) { + retNode = node.left; + } else if (this.comparator_(node.value, value) < 0) { + retNode = node.right; + } else { + retValue = node.value; + this.removeNode_(node); + } + return retNode; // If null, we'll stop traversing the tree + }); + + // If a node was removed, decrement count. + if (retValue) { + // Had traverse_() cleared the tree, set to 0. + this.count_ = this.root_ ? this.count_ - 1 : 0; + } + + // Return the value that was removed, null if the value was not in the tree + return retValue; +}; + + +/** + * Removes all nodes from the tree. + */ +goog.structs.AvlTree.prototype.clear = function() { + this.root_ = null; + this.minNode_ = null; + this.maxNode_ = null; + this.count_ = 0; +}; + + +/** + * Returns true if the tree contains a node with the specified value, false + * otherwise. + * + * @param {*} value Value to find in the tree. + * @return {boolean} Whether the tree contains a node with the specified value. + */ +goog.structs.AvlTree.prototype.contains = function(value) { + // Assume the value is not in the tree and set this value if it is found + var isContained = false; + + // Depth traverse the tree and set isContained if we find the node + this.traverse_(function(node) { + var retNode = null; + if (this.comparator_(node.value, value) > 0) { + retNode = node.left; + } else if (this.comparator_(node.value, value) < 0) { + retNode = node.right; + } else { + isContained = true; + } + return retNode; // If null, we'll stop traversing the tree + }); + + // Return true if the value is contained in the tree, false otherwise + return isContained; +}; + + +/** + * Returns the number of values stored in the tree. + * + * @return {number} The number of values stored in the tree. + */ +goog.structs.AvlTree.prototype.getCount = function() { + return this.count_; +}; + + +/** + * Returns the value u, such that u is contained in the tree and u < v, for all + * values v in the tree where v != u. + * + * @return {*} The minimum value contained in the tree. + */ +goog.structs.AvlTree.prototype.getMinimum = function() { + return this.getMinNode_().value; +}; + + +/** + * Returns the value u, such that u is contained in the tree and u > v, for all + * values v in the tree where v != u. + * + * @return {*} The maximum value contained in the tree. + */ +goog.structs.AvlTree.prototype.getMaximum = function() { + return this.getMaxNode_().value; +}; + + +/** + * Returns the height of the tree (the maximum depth). This height should + * always be <= 1.4405*(Math.log(n+2)/Math.log(2))-1.3277, where n is the + * number of nodes in the tree. + * + * @return {number} The height of the tree. + */ +goog.structs.AvlTree.prototype.getHeight = function() { + return this.root_ ? this.root_.height : 0; +}; + + +/** + * Inserts the values stored in the tree into a new Array and returns the Array. + * + * @return {Array} An array containing all of the trees values in sorted order. + */ +goog.structs.AvlTree.prototype.getValues = function() { + var ret = []; + this.inOrderTraverse(function(value) { + ret.push(value); + }); + return ret; +}; + + +/** + * Performs an in-order traversal of the tree and calls {@code func} with each + * traversed node, optionally starting from the smallest node with a value >= to + * the specified start value. The traversal ends after traversing the tree's + * maximum node or when {@code func} returns a value that evaluates to true. + * + * @param {Function} func Function to call on each traversed node. + * @param {Object=} opt_startValue If specified, traversal will begin on the + * node with the smallest value >= opt_startValue. + */ +goog.structs.AvlTree.prototype.inOrderTraverse = + function(func, opt_startValue) { + // If our tree is empty, return immediately + if (!this.root_) { + return; + } + + // Depth traverse the tree to find node to begin in-order traversal from + var startNode; + if (opt_startValue) { + this.traverse_(function(node) { + var retNode = null; + if (this.comparator_(node.value, opt_startValue) > 0) { + retNode = node.left; + startNode = node; + } else if (this.comparator_(node.value, opt_startValue) < 0) { + retNode = node.right; + } else { + startNode = node; + } + return retNode; // If null, we'll stop traversing the tree + }); + } else { + startNode = this.getMinNode_(); + } + + // Traverse the tree and call func on each traversed node's value + var node = startNode, prev = startNode.left ? startNode.left : startNode; + while (node != null) { + if (node.left != null && node.left != prev && node.right != prev) { + node = node.left; + } else { + if (node.right != prev) { + if (func(node.value)) { + return; + } + } + var temp = node; + node = node.right != null && node.right != prev ? + node.right : + node.parent; + prev = temp; + } + } +}; + + +/** + * Performs a reverse-order traversal of the tree and calls {@code func} with + * each traversed node, optionally starting from the largest node with a value + * <= to the specified start value. The traversal ends after traversing the + * tree's minimum node or when func returns a value that evaluates to true. + * + * @param {Function} func Function to call on each traversed node. + * @param {Object=} opt_startValue If specified, traversal will begin on the + * node with the largest value <= opt_startValue. + */ +goog.structs.AvlTree.prototype.reverseOrderTraverse = + function(func, opt_startValue) { + // If our tree is empty, return immediately + if (!this.root_) { + return; + } + + // Depth traverse the tree to find node to begin reverse-order traversal from + var startNode; + if (opt_startValue) { + this.traverse_(goog.bind(function(node) { + var retNode = null; + if (this.comparator_(node.value, opt_startValue) > 0) { + retNode = node.left; + } else if (this.comparator_(node.value, opt_startValue) < 0) { + retNode = node.right; + startNode = node; + } else { + startNode = node; + } + return retNode; // If null, we'll stop traversing the tree + }, this)); + } else { + startNode = this.getMaxNode_(); + } + + // Traverse the tree and call func on each traversed node's value + var node = startNode, prev = startNode.right ? startNode.right : startNode; + while (node != null) { + if (node.right != null && node.right != prev && node.left != prev) { + node = node.right; + } else { + if (node.left != prev) { + if (func(node.value)) { + return; + } + } + var temp = node; + node = node.left != null && node.left != prev ? + node.left : + node.parent; + prev = temp; + } + } +}; + + +/** + * Performs a traversal defined by the supplied {@code traversalFunc}. The first + * call to {@code traversalFunc} is passed the root or the optionally specified + * startNode. After that, calls {@code traversalFunc} with the node returned + * by the previous call to {@code traversalFunc} until {@code traversalFunc} + * returns null or the optionally specified endNode. The first call to + * traversalFunc is passed the root or the optionally specified startNode. + * + * @param {Function} traversalFunc Function used to traverse the tree. Takes a + * node as a parameter and returns a node. + * @param {goog.structs.AvlTree.Node=} opt_startNode The node at which the + * traversal begins. + * @param {goog.structs.AvlTree.Node=} opt_endNode The node at which the + * traversal ends. + * @private + */ +goog.structs.AvlTree.prototype.traverse_ = + function(traversalFunc, opt_startNode, opt_endNode) { + var node = opt_startNode ? opt_startNode : this.root_; + var endNode = opt_endNode ? opt_endNode : null; + while (node && node != endNode) { + node = traversalFunc.call(this, node); + } +}; + + +/** + * Ensures that the specified node and all its ancestors are balanced. If they + * are not, performs left and right tree rotations to achieve a balanced + * tree. This method assumes that at most 2 rotations are necessary to balance + * the tree (which is true for AVL-trees that are balanced after each node is + * added or removed). + * + * @param {goog.structs.AvlTree.Node} node Node to begin balance from. + * @private + */ +goog.structs.AvlTree.prototype.balance_ = function(node) { + + this.traverse_(function(node) { + // Calculate the left and right node's heights + var lh = node.left ? node.left.height : 0; + var rh = node.right ? node.right.height : 0; + + // Rotate tree rooted at this node if it is not AVL-tree balanced + if (lh - rh > 1) { + if (node.left.right && (!node.left.left || + node.left.left.height < node.left.right.height)) { + this.leftRotate_(node.left); + } + this.rightRotate_(node); + } else if (rh - lh > 1) { + if (node.right.left && (!node.right.right || + node.right.right.height < node.right.left.height)) { + this.rightRotate_(node.right); + } + this.leftRotate_(node); + } + + // Recalculate the left and right node's heights + lh = node.left ? node.left.height : 0; + rh = node.right ? node.right.height : 0; + + // Set this node's height + node.height = Math.max(lh, rh) + 1; + + // Traverse up tree and balance parent + return node.parent; + }, node); + +}; + + +/** + * Performs a left tree rotation on the specified node. + * + * @param {goog.structs.AvlTree.Node} node Pivot node to rotate from. + * @private + */ +goog.structs.AvlTree.prototype.leftRotate_ = function(node) { + // Re-assign parent-child references for the parent of the node being removed + if (node.isLeftChild()) { + node.parent.left = node.right; + node.right.parent = node.parent; + } else if (node.isRightChild()) { + node.parent.right = node.right; + node.right.parent = node.parent; + } else { + this.root_ = node.right; + this.root_.parent = null; + } + + // Re-assign parent-child references for the child of the node being removed + var temp = node.right; + node.right = node.right.left; + if (node.right != null) node.right.parent = node; + temp.left = node; + node.parent = temp; +}; + + +/** + * Performs a right tree rotation on the specified node. + * + * @param {goog.structs.AvlTree.Node} node Pivot node to rotate from. + * @private + */ +goog.structs.AvlTree.prototype.rightRotate_ = function(node) { + // Re-assign parent-child references for the parent of the node being removed + if (node.isLeftChild()) { + node.parent.left = node.left; + node.left.parent = node.parent; + } else if (node.isRightChild()) { + node.parent.right = node.left; + node.left.parent = node.parent; + } else { + this.root_ = node.left; + this.root_.parent = null; + } + + // Re-assign parent-child references for the child of the node being removed + var temp = node.left; + node.left = node.left.right; + if (node.left != null) node.left.parent = node; + temp.right = node; + node.parent = temp; +}; + + +/** + * Removes the specified node from the tree and ensures the tree still + * maintains the AVL-tree balance. + * + * @param {goog.structs.AvlTree.Node} node The node to be removed. + * @private + */ +goog.structs.AvlTree.prototype.removeNode_ = function(node) { + // Perform normal binary tree node removal, but balance the tree, starting + // from where we removed the node + if (node.left != null || node.right != null) { + var b = null; // Node to begin balance from + var r; // Node to replace the node being removed + if (node.left != null) { + r = this.getMaxNode_(node.left); + if (r != node.left) { + r.parent.right = r.left; + if (r.left) r.left.parent = r.parent; + r.left = node.left; + r.left.parent = r; + b = r.parent; + } + r.parent = node.parent; + r.right = node.right; + if (r.right) r.right.parent = r; + if (node == this.maxNode_) this.maxNode_ = r; + } else { + r = this.getMinNode_(node.right); + if (r != node.right) { + r.parent.left = r.right; + if (r.right) r.right.parent = r.parent; + r.right = node.right; + r.right.parent = r; + b = r.parent; + } + r.parent = node.parent; + r.left = node.left; + if (r.left) r.left.parent = r; + if (node == this.minNode_) this.minNode_ = r; + } + + // Update the parent of the node being removed to point to its replace + if (node.isLeftChild()) { + node.parent.left = r; + } else if (node.isRightChild()) { + node.parent.right = r; + } else { + this.root_ = r; + } + + // Balance the tree + this.balance_(b ? b : r); + } else { + // If the node is a leaf, remove it and balance starting from its parent + if (node.isLeftChild()) { + this.special = 1; + node.parent.left = null; + if (node == this.minNode_) this.minNode_ = node.parent; + this.balance_(node.parent); + } else if (node.isRightChild()) { + node.parent.right = null; + if (node == this.maxNode_) this.maxNode_ = node.parent; + this.balance_(node.parent); + } else { + this.clear(); + } + } +}; + + +/** + * Returns the node with the smallest value in tree, optionally rooted at + * {@code opt_rootNode}. + * + * @param {goog.structs.AvlTree.Node=} opt_rootNode Optional root node. + * @return {goog.structs.AvlTree.Node} The node with the smallest value in + * the tree. + * @private + */ +goog.structs.AvlTree.prototype.getMinNode_ = function(opt_rootNode) { + if (!opt_rootNode) { + return this.minNode_; + } + + var minNode = opt_rootNode; + this.traverse_(function(node) { + var retNode = null; + if (node.left) { + minNode = node.left; + retNode = node.left; + } + return retNode; // If null, we'll stop traversing the tree + }, opt_rootNode); + + return minNode; +}; + + +/** + * Returns the node with the largest value in tree, optionally rooted at + * opt_rootNode. + * + * @param {goog.structs.AvlTree.Node=} opt_rootNode Optional root node. + * @return {goog.structs.AvlTree.Node} The node with the largest value in + * the tree. + * @private + */ +goog.structs.AvlTree.prototype.getMaxNode_ = function(opt_rootNode) { + if (!opt_rootNode) { + return this.maxNode_; + } + + var maxNode = opt_rootNode; + this.traverse_(function(node) { + var retNode = null; + if (node.right) { + maxNode = node.right; + retNode = node.right; + } + return retNode; // If null, we'll stop traversing the tree + }, opt_rootNode); + + return maxNode; +}; + + + +/** + * Constructs an AVL-Tree node with the specified value. If no parent is + * specified, the node's parent is assumed to be null. The node's height + * defaults to 1 and its children default to null. + * + * @param {*} value Value to store in the node. + * @param {goog.structs.AvlTree.Node=} opt_parent Optional parent node. + * @constructor + */ +goog.structs.AvlTree.Node = function(value, opt_parent) { + /** + * The value stored by the node. + * + * @type {*} + */ + this.value = value; + + /** + * The node's parent. Null if the node is the root. + * + * @type {goog.structs.AvlTree.Node} + */ + this.parent = opt_parent ? opt_parent : null; +}; + + +/** + * The node's left child. Null if the node does not have a left child. + * + * @type {goog.structs.AvlTree.Node?} + */ +goog.structs.AvlTree.Node.prototype.left = null; + + +/** + * The node's right child. Null if the node does not have a right child. + * + * @type {goog.structs.AvlTree.Node?} + */ +goog.structs.AvlTree.Node.prototype.right = null; + + +/** + * The height of the tree rooted at this node. + * + * @type {number} + */ +goog.structs.AvlTree.Node.prototype.height = 1; + + +/** + * Returns true iff the specified node has a parent and is the right child of + * its parent. + * + * @return {boolean} Whether the specified node has a parent and is the right + * child of its parent. + */ +goog.structs.AvlTree.Node.prototype.isRightChild = function() { + return !!this.parent && this.parent.right == this; +}; + + +/** + * Returns true iff the specified node has a parent and is the left child of + * its parent. + * + * @return {boolean} Whether the specified node has a parent and is the left + * child of its parent. + */ +goog.structs.AvlTree.Node.prototype.isLeftChild = function() { + return !!this.parent && this.parent.left == this; +}; diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/avltree_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/avltree_test.html.svn-base new file mode 100644 index 0000000..144047d --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/avltree_test.html.svn-base @@ -0,0 +1,251 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright 2007 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> +<head> +<meta http-equiv="X-UA-Compatible" content="IE=edge"> +<title>Closure Unit Tests - goog.structs.AvlTree</title> +<script src="../base.js"></script> +<script> + goog.require('goog.structs'); + goog.require('goog.structs.AvlTree'); + goog.require('goog.testing.jsunit'); +</script> +</head> +<body> +<script> + + /** + * This test verifies that we can insert strings into the AvlTree and have + * them be stored and sorted correctly by the default comparator. + */ + function testInsertsWithDefaultComparator() { + var tree = new goog.structs.AvlTree(); + var values = ['bill', 'blake', 'elliot', 'jacob', 'john', 'myles', 'ted']; + + // Insert strings into tree out of order + tree.add(values[4]); + tree.add(values[3]); + tree.add(values[0]); + tree.add(values[6]); + tree.add(values[5]); + tree.add(values[1]); + tree.add(values[2]); + + // Verify strings are stored in sorted order + var i = 0; + tree.inOrderTraverse(function(value) { + assertEquals(values[i], value); + i += 1; + }); + assertEquals(i, values.length); + }; + + /** + * This test verifies that we can insert strings into and remove strings from + * the AvlTree and have the only the non-removed values be stored and sorted + * correctly by the default comparator. + */ + function testRemovesWithDefaultComparator() { + var tree = new goog.structs.AvlTree(); + var values = ['bill', 'blake', 'elliot', 'jacob', 'john', 'myles', 'ted']; + + // Insert strings into tree out of order + tree.add('frodo'); + tree.add(values[4]); + tree.add(values[3]); + tree.add(values[0]); + tree.add(values[6]); + tree.add('samwise'); + tree.add(values[5]); + tree.add(values[1]); + tree.add(values[2]); + tree.add('pippin'); + + // Remove strings from tree + assertEquals(tree.remove('samwise'), 'samwise'); + assertEquals(tree.remove('pippin'), 'pippin'); + assertEquals(tree.remove('frodo'), 'frodo'); + assertEquals(tree.remove('merry'), null); + + + // Verify strings are stored in sorted order + var i = 0; + tree.inOrderTraverse(function(value) { + assertEquals(values[i], value); + i += 1; + }); + assertEquals(i, values.length); + }; + + /** + * This test verifies that we can insert values into and remove values from + * the AvlTree and have them be stored and sorted correctly by a custom + * comparator. + */ + function testInsertsAndRemovesWithCustomComparator() { + var tree = new goog.structs.AvlTree(function(a, b) { + return a - b; + }); + + var NUM_TO_INSERT = 37; + var valuesToRemove = [1, 0, 6, 7, 36]; + + // Insert ints into tree out of order + var values = []; + for (var i = 0; i < NUM_TO_INSERT; i += 1) { + tree.add(i); + values.push(i); + } + + for (var i = 0; i < valuesToRemove.length; i += 1) { + assertEquals(tree.remove(valuesToRemove[i]), valuesToRemove[i]); + goog.array.remove(values, valuesToRemove[i]); + } + assertEquals(tree.remove(-1), null); + assertEquals(tree.remove(37), null); + + // Verify strings are stored in sorted order + var i = 0; + tree.inOrderTraverse(function(value) { + assertEquals(values[i], value); + i += 1; + }); + assertEquals(i, values.length); + }; + + /** + * This test verifies that we can insert values into and remove values from + * the AvlTree and have it maintain the AVL-Tree upperbound on its height. + */ + function testAvlTreeHeight() { + var tree = new goog.structs.AvlTree(function(a, b) { + return a - b; + }); + + var NUM_TO_INSERT = 2000; + var NUM_TO_REMOVE = 500; + + // Insert ints into tree out of order + for (var i = 0; i < NUM_TO_INSERT; i += 1) { + tree.add(i); + } + + // Remove valuse + for (var i = 0; i < NUM_TO_REMOVE; i += 1) { + tree.remove(i); + } + + assertTrue(tree.getHeight() <= 1.4405 * + (Math.log(NUM_TO_INSERT - NUM_TO_REMOVE + 2) / Math.log(2)) - 1.3277); + }; + + /** + * This test verifies that we can insert values into and remove values from + * the AvlTree and have its contains method correctly determine the values it + * is contains. + */ + function testAvlTreeContains() { + var tree = new goog.structs.AvlTree(); + var values = ['bill', 'blake', 'elliot', 'jacob', 'john', 'myles', 'ted']; + + // Insert strings into tree out of order + tree.add('frodo'); + tree.add(values[4]); + tree.add(values[3]); + tree.add(values[0]); + tree.add(values[6]); + tree.add('samwise'); + tree.add(values[5]); + tree.add(values[1]); + tree.add(values[2]); + tree.add('pippin'); + + // Remove strings from tree + assertEquals(tree.remove('samwise'), 'samwise'); + assertEquals(tree.remove('pippin'), 'pippin'); + assertEquals(tree.remove('frodo'), 'frodo'); + + for (var i = 0; i < values.length; i += 1) { + assertTrue(tree.contains(values[i])); + } + assertFalse(tree.contains('samwise')); + assertFalse(tree.contains('pippin')); + assertFalse(tree.contains('frodo')); + }; + + /** + * This test verifies that we can insert values into and remove values from + * the AvlTree and have its minValue and maxValue routines return the correct + * min and max values contained by the tree. + */ + function testMinAndMaxValues() { + var tree = new goog.structs.AvlTree(function(a, b) { + return a - b; + }); + + var NUM_TO_INSERT = 2000; + var NUM_TO_REMOVE = 500; + + // Insert ints into tree out of order + for (var i = 0; i < NUM_TO_INSERT; i += 1) { + tree.add(i); + } + + // Remove valuse + for (var i = 0; i < NUM_TO_REMOVE; i += 1) { + tree.remove(i); + } + + assertEquals(tree.getMinimum(), NUM_TO_REMOVE); + assertEquals(tree.getMaximum(), NUM_TO_INSERT - 1); + }; + + /** + * This test verifies that we can insert values into and remove values from + * the AvlTree and traverse the tree in reverse order using the + * reverseOrderTraverse routine. + */ + function testReverseOrderTraverse() { + var tree = new goog.structs.AvlTree(function(a, b) { + return a - b; + }); + + var NUM_TO_INSERT = 2000; + var NUM_TO_REMOVE = 500; + + // Insert ints into tree out of order + for (var i = 0; i < NUM_TO_INSERT; i += 1) { + tree.add(i); + } + + // Remove valuse + for (var i = 0; i < NUM_TO_REMOVE; i += 1) { + tree.remove(i); + } + + var i = NUM_TO_INSERT - 1; + tree.reverseOrderTraverse(function(value) { + assertEquals(value, i); + i -= 1; + }); + assertEquals(i, NUM_TO_REMOVE - 1); + }; + + /** + * Verifies correct behavior of getCount(). See http://b/4347755 + */ + function testGetCountBehavior() { + var tree = new goog.structs.AvlTree(); + tree.add(1); + tree.remove(1); + assertEquals(0, tree.getCount()); + } + +</script> +</body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/circularbuffer.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/circularbuffer.js.svn-base new file mode 100644 index 0000000..2964559 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/circularbuffer.js.svn-base @@ -0,0 +1,219 @@ +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +/** + * @fileoverview Datastructure: Circular Buffer. + * + * Implements a buffer with a maximum size. New entries override the oldest + * entries when the maximum size has been reached. + * + */ + + +goog.provide('goog.structs.CircularBuffer'); + + + +/** + * Class for CircularBuffer. + * @param {number=} opt_maxSize The maximum size of the buffer. + * @constructor + */ +goog.structs.CircularBuffer = function(opt_maxSize) { + /** + * Maximum size of the the circular array structure. + * @type {number} + * @private + */ + this.maxSize_ = opt_maxSize || 100; + + /** + * Underlying array for the CircularBuffer. + * @type {Array} + * @private + */ + this.buff_ = []; +}; + + +/** + * Index of the next element in the circular array structure. + * @type {number} + * @private + */ +goog.structs.CircularBuffer.prototype.nextPtr_ = 0; + + +/** + * Adds an item to the buffer. May remove the oldest item if the buffer is at + * max size. + * @param {*} item The item to add. + */ +goog.structs.CircularBuffer.prototype.add = function(item) { + this.buff_[this.nextPtr_] = item; + this.nextPtr_ = (this.nextPtr_ + 1) % this.maxSize_; +}; + + +/** + * Returns the item at the specified index. + * @param {number} index The index of the item. The index of an item can change + * after calls to {@code add()} if the buffer is at maximum size. + * @return {*} The item at the specified index. + */ +goog.structs.CircularBuffer.prototype.get = function(index) { + index = this.normalizeIndex_(index); + return this.buff_[index]; +}; + + +/** + * Sets the item at the specified index. + * @param {number} index The index of the item. The index of an item can change + * after calls to {@code add()} if the buffer is at maximum size. + * @param {*} item The item to add. + */ +goog.structs.CircularBuffer.prototype.set = function(index, item) { + index = this.normalizeIndex_(index); + this.buff_[index] = item; +}; + + +/** + * Returns the current number of items in the buffer. + * @return {number} The current number of items in the buffer. + */ +goog.structs.CircularBuffer.prototype.getCount = function() { + return this.buff_.length; +}; + + +/** + * @return {boolean} Whether the buffer is empty. + */ +goog.structs.CircularBuffer.prototype.isEmpty = function() { + return this.buff_.length == 0; +}; + + +/** + * Empties the current buffer. + */ +goog.structs.CircularBuffer.prototype.clear = function() { + this.buff_.length = 0; + this.nextPtr_ = 0; +}; + + +/** + * @return {Array} The values in the buffer. + */ +goog.structs.CircularBuffer.prototype.getValues = function() { + // getNewestValues returns all the values if the maxCount parameter is the + // count + return this.getNewestValues(this.getCount()); +}; + + +/** + * Returns the newest values in the buffer up to {@code count}. + * @param {number} maxCount The maximum number of values to get. Should be a + * positive number. + * @return {Array} The newest values in the buffer up to {@code count}. + */ +goog.structs.CircularBuffer.prototype.getNewestValues = function(maxCount) { + var l = this.getCount(); + var start = this.getCount() - maxCount; + var rv = []; + for (var i = start; i < l; i++) { + rv[i] = this.get(i); + } + return rv; +}; + + +/** + * @return {Array} The indexes in the buffer. + */ +goog.structs.CircularBuffer.prototype.getKeys = function() { + var rv = []; + var l = this.getCount(); + for (var i = 0; i < l; i++) { + rv[i] = i; + } + return rv; +}; + + +/** + * Whether the buffer contains the key/index. + * @param {number} key The key/index to check for. + * @return {boolean} Whether the buffer contains the key/index. + */ +goog.structs.CircularBuffer.prototype.containsKey = function(key) { + return key < this.getCount(); +}; + + +/** + * Whether the buffer contains the given value. + * @param {*} value The value to check for. + * @return {boolean} Whether the buffer contains the given value. + */ +goog.structs.CircularBuffer.prototype.containsValue = function(value) { + var l = this.getCount(); + for (var i = 0; i < l; i++) { + if (this.get(i) == value) { + return true; + } + } + return false; +}; + + +/** + * Returns the last item inserted into the buffer. + * @return {*} The last item inserted into the buffer, or null if the buffer is + * empty. + */ +goog.structs.CircularBuffer.prototype.getLast = function() { + if (this.getCount() == 0) { + return null; + } + return this.get(this.getCount() - 1); +}; + + +/** + * Helper function to convert an index in the number space of oldest to + * newest items in the array to the position that the element will be at in the + * underlying array. + * @param {number} index The index of the item in a list ordered from oldest to + * newest. + * @return {number} The index of the item in the CircularBuffer's underlying + * array. + * @private + */ +goog.structs.CircularBuffer.prototype.normalizeIndex_ = function(index) { + if (index >= this.buff_.length) { + throw Error('Out of bounds exception'); + } + + if (this.buff_.length < this.maxSize_) { + return index; + } + + return (this.nextPtr_ + Number(index)) % this.maxSize_; +}; diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/circularbuffer_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/circularbuffer_test.html.svn-base new file mode 100644 index 0000000..8d891c8 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/circularbuffer_test.html.svn-base @@ -0,0 +1,105 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright 2006 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> +<head> +<meta http-equiv="X-UA-Compatible" content="IE=edge"> +<title>Closure Unit Tests - goog.structs</title> +<script src="../base.js"></script> +<script> + goog.require('goog.structs.CircularBuffer'); + goog.require('goog.testing.jsunit'); +</script> +</head> +<body> +<script> + +function testCircularBuffer() { + var buff = new goog.structs.CircularBuffer(2); + buff.add('first'); + assertEquals(1, buff.getCount()); + assertEquals('first', buff.get(0)); + assertEquals('first', buff.getLast()); + buff.add('second'); + assertEquals(2, buff.getCount()); + assertEquals('first', buff.get(0)); + assertEquals('second', buff.get(1)); + assertEquals('second', buff.getLast()); + buff.add('third'); + assertEquals(2, buff.getCount()); + assertEquals('second', buff.get(0)); + assertEquals('third', buff.get(1)); + assertEquals('third', buff.getLast()); +} + +function testIsEmpty() { + var buff = new goog.structs.CircularBuffer(2); + assertTrue('initially empty', buff.isEmpty()); + buff.add('first'); + assertFalse('not empty after add empty', buff.isEmpty()); +} + +function testClear() { + var buff = new goog.structs.CircularBuffer(2); + buff.add('first'); + buff.clear(); + assertTrue('should be empty after clear', buff.isEmpty()); + +} + +function testGetValues() { + var buff = new goog.structs.CircularBuffer(2); + buff.add('first'); + buff.add('second'); + assertEquals('firstsecond', buff.getValues().join('')); +} + +function testGetNewestVtalues() { + var buff = new goog.structs.CircularBuffer(5); + buff.add('first'); + buff.add('second'); + buff.add('third'); + buff.add('fourth'); + buff.add('fifth'); + assertEquals('fourthfifth', buff.getNewestValues(2).join('')); +} + + +function testGetKeys() { + var buff = new goog.structs.CircularBuffer(2); + buff.add('first'); + buff.add('second'); + assertEquals('01', buff.getKeys().join('')); +} + +function testContainsValue() { + var buff = new goog.structs.CircularBuffer(2); + buff.add('first'); + buff.add('second'); + assertTrue(buff.containsValue('first')); + assertTrue(buff.containsValue('second')); + assertFalse(buff.containsValue('third')); +} + +function testContainsKey() { + var buff = new goog.structs.CircularBuffer(3); + buff.add('first'); + buff.add('second'); + buff.add('third'); + assertTrue(buff.containsKey(0)); + assertTrue(buff.containsKey('0')); + assertTrue(buff.containsKey(1)); + assertTrue(buff.containsKey('1')); + assertTrue(buff.containsKey(2)); + assertTrue(buff.containsKey('2')); + assertFalse(buff.containsKey(3)); + assertFalse(buff.containsKey('3')); +} + +</script> +</body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/collection.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/collection.js.svn-base new file mode 100644 index 0000000..8ba8cb3 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/collection.js.svn-base @@ -0,0 +1,54 @@ +// Copyright 2011 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Defines the collection interface. + * + */ + +goog.provide('goog.structs.Collection'); + + + +/** + * An interface for a collection of values. + * @interface + */ +goog.structs.Collection = function() {}; + + +/** + * @param {*} value Value to add to the collection. + */ +goog.structs.Collection.prototype.add; + + +/** + * @param {*} value Value to remove from the collection. + */ +goog.structs.Collection.prototype.remove; + + +/** + * @param {*} value Value to find in the tree. + * @return {boolean} Whether the collection contains the specified value. + */ +goog.structs.Collection.prototype.contains; + + +/** + * @return {number} The number of values stored in the collection. + */ +goog.structs.Collection.prototype.getCount; + diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/collection_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/collection_test.html.svn-base new file mode 100644 index 0000000..1ce9932 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/collection_test.html.svn-base @@ -0,0 +1,57 @@ +<!doctype html> +<html> +<!-- +Copyright 2011 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> + <head> + <title>Closure Unit Tests - goog.structs.Collection</title> + <script src="../base.js"></script> + <script> + goog.require('goog.structs.AvlTree'); + goog.require('goog.structs.Collection'); + goog.require('goog.structs.Set'); + goog.require('goog.testing.jsunit'); + </script> + </head> + <body> + <script> + +function testSet() { + var set = new goog.structs.Set(); + exerciseCollection(set) +} + +function testAvlTree() { + var tree = new goog.structs.AvlTree(); + exerciseCollection(tree) +} + +// Simple exercise of a collection object. +function exerciseCollection(collection) { + assertEquals(0, collection.getCount()); + + for (var i = 1; i <= 10; i++) { + assertFalse(collection.contains(i)); + collection.add(i); + assertTrue(collection.contains(i)); + assertEquals(i, collection.getCount()); + } + + assertEquals(10, collection.getCount()); + + for (var i = 10; i > 0; i--) { + assertTrue(collection.contains(i)); + collection.remove(i); + assertFalse(collection.contains(i)); + assertEquals(i - 1, collection.getCount()); + } + + assertEquals(0, collection.getCount()); +} + + </script> + </body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/heap.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/heap.js.svn-base new file mode 100644 index 0000000..98c7695 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/heap.js.svn-base @@ -0,0 +1,333 @@ +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Datastructure: Heap. + * + * + * This file provides the implementation of a Heap datastructure. Smaller keys + * rise to the top. + * + * The big-O notation for all operations are below: + * <pre> + * Method big-O + * ---------------------------------------------------------------------------- + * - insert O(logn) + * - remove O(logn) + * - peek O(1) + * - contains O(n) + * </pre> + */ +// TODO(user): Should this rely on natural ordering via some Comparable +// interface? + + +goog.provide('goog.structs.Heap'); + +goog.require('goog.array'); +goog.require('goog.object'); +goog.require('goog.structs.Node'); + + + +/** + * Class for a Heap datastructure. + * + * @param {goog.structs.Heap|Object=} opt_heap Optional goog.structs.Heap or + * Object to initialize heap with. + * @constructor + */ +goog.structs.Heap = function(opt_heap) { + /** + * The nodes of the heap. + * @private + * @type {Array.<goog.structs.Node>} + */ + this.nodes_ = []; + + if (opt_heap) { + this.insertAll(opt_heap); + } +}; + + +/** + * Insert the given value into the heap with the given key. + * @param {*} key The key. + * @param {*} value The value. + */ +goog.structs.Heap.prototype.insert = function(key, value) { + var node = new goog.structs.Node(key, value); + var nodes = this.nodes_; + nodes.push(node); + this.moveUp_(nodes.length - 1); +}; + + +/** + * Adds multiple key-value pairs from another goog.structs.Heap or Object + * @param {goog.structs.Heap|Object} heap Object containing the data to add. + */ +goog.structs.Heap.prototype.insertAll = function(heap) { + var keys, values; + if (heap instanceof goog.structs.Heap) { + keys = heap.getKeys(); + values = heap.getValues(); + + // If it is a heap and the current heap is empty, I can realy on the fact + // that the keys/values are in the correct order to put in the underlying + // structure. + if (heap.getCount() <= 0) { + var nodes = this.nodes_; + for (var i = 0; i < keys.length; i++) { + nodes.push(new goog.structs.Node(keys[i], values[i])); + } + return; + } + } else { + keys = goog.object.getKeys(heap); + values = goog.object.getValues(heap); + } + + for (var i = 0; i < keys.length; i++) { + this.insert(keys[i], values[i]); + } +}; + + +/** + * Retrieves and removes the root value of this heap. + * @return {*} The value removed from the root of the heap. Returns + * undefined if the heap is empty. + */ +goog.structs.Heap.prototype.remove = function() { + var nodes = this.nodes_; + var count = nodes.length; + var rootNode = nodes[0]; + if (count <= 0) { + return undefined; + } else if (count == 1) { + goog.array.clear(nodes); + } else { + nodes[0] = nodes.pop(); + this.moveDown_(0); + } + return rootNode.getValue(); +}; + + +/** + * Retrieves but does not remove the root value of this heap. + * @return {*} The value at the root of the heap. Returns + * undefined if the heap is empty. + */ +goog.structs.Heap.prototype.peek = function() { + var nodes = this.nodes_; + if (nodes.length == 0) { + return undefined; + } + return nodes[0].getValue(); +}; + + +/** + * Retrieves but does not remove the key of the root node of this heap. + * @return {*} The key at the root of the heap. Returns undefined if the + * heap is empty. + */ +goog.structs.Heap.prototype.peekKey = function() { + return this.nodes_[0] && this.nodes_[0].getKey(); +}; + + +/** + * Moves the node at the given index down to its proper place in the heap. + * @param {number} index The index of the node to move down. + * @private + */ +goog.structs.Heap.prototype.moveDown_ = function(index) { + var nodes = this.nodes_; + var count = nodes.length; + + // Save the node being moved down. + var node = nodes[index]; + // While the current node has a child. + while (index < (count >> 1)) { + var leftChildIndex = this.getLeftChildIndex_(index); + var rightChildIndex = this.getRightChildIndex_(index); + + // Determine the index of the smaller child. + var smallerChildIndex = rightChildIndex < count && + nodes[rightChildIndex].getKey() < nodes[leftChildIndex].getKey() ? + rightChildIndex : leftChildIndex; + + // If the node being moved down is smaller than its children, the node + // has found the correct index it should be at. + if (nodes[smallerChildIndex].getKey() > node.getKey()) { + break; + } + + // If not, then take the smaller child as the current node. + nodes[index] = nodes[smallerChildIndex]; + index = smallerChildIndex; + } + nodes[index] = node; +}; + + +/** + * Moves the node at the given index up to its proper place in the heap. + * @param {number} index The index of the node to move up. + * @private + */ +goog.structs.Heap.prototype.moveUp_ = function(index) { + var nodes = this.nodes_; + var node = nodes[index]; + + // While the node being moved up is not at the root. + while (index > 0) { + // If the parent is less than the node being moved up, move the parent down. + var parentIndex = this.getParentIndex_(index); + if (nodes[parentIndex].getKey() > node.getKey()) { + nodes[index] = nodes[parentIndex]; + index = parentIndex; + } else { + break; + } + } + nodes[index] = node; +}; + + +/** + * Gets the index of the left child of the node at the given index. + * @param {number} index The index of the node to get the left child for. + * @return {number} The index of the left child. + * @private + */ +goog.structs.Heap.prototype.getLeftChildIndex_ = function(index) { + return index * 2 + 1; +}; + + +/** + * Gets the index of the right child of the node at the given index. + * @param {number} index The index of the node to get the right child for. + * @return {number} The index of the right child. + * @private + */ +goog.structs.Heap.prototype.getRightChildIndex_ = function(index) { + return index * 2 + 2; +}; + + +/** + * Gets the index of the parent of the node at the given index. + * @param {number} index The index of the node to get the parent for. + * @return {number} The index of the parent. + * @private + */ +goog.structs.Heap.prototype.getParentIndex_ = function(index) { + return (index - 1) >> 1; +}; + + +/** + * Gets the values of the heap. + * @return {Array} The values in the heap. + */ +goog.structs.Heap.prototype.getValues = function() { + var nodes = this.nodes_; + var rv = []; + var l = nodes.length; + for (var i = 0; i < l; i++) { + rv.push(nodes[i].getValue()); + } + return rv; +}; + + +/** + * Gets the keys of the heap. + * @return {Array} The keys in the heap. + */ +goog.structs.Heap.prototype.getKeys = function() { + var nodes = this.nodes_; + var rv = []; + var l = nodes.length; + for (var i = 0; i < l; i++) { + rv.push(nodes[i].getKey()); + } + return rv; +}; + + +/** + * Whether the heap contains the given value. + * @param {Object} val The value to check for. + * @return {boolean} Whether the heap contains the value. + */ +goog.structs.Heap.prototype.containsValue = function(val) { + return goog.array.some(this.nodes_, function(node) { + return node.getValue() == val; + }); +}; + + +/** + * Whether the heap contains the given key. + * @param {Object} key The key to check for. + * @return {boolean} Whether the heap contains the key. + */ +goog.structs.Heap.prototype.containsKey = function(key) { + return goog.array.some(this.nodes_, function(node) { + return node.getKey() == key; + }); +}; + + +/** + * Clones a heap and returns a new heap + * @return {goog.structs.Heap} A new goog.structs.Heap with the same key-value + * pairs. + */ +goog.structs.Heap.prototype.clone = function() { + return new goog.structs.Heap(this); +}; + + +/** + * The number of key-value pairs in the map + * @return {number} The number of pairs. + */ +goog.structs.Heap.prototype.getCount = function() { + return this.nodes_.length; +}; + + +/** + * Returns true if this heap contains no elements. + * @return {boolean} Whether this heap contains no elements. + */ +goog.structs.Heap.prototype.isEmpty = function() { + return goog.array.isEmpty(this.nodes_); +}; + + +/** + * Removes all elements from the heap. + */ +goog.structs.Heap.prototype.clear = function() { + goog.array.clear(this.nodes_); +}; diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/heap_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/heap_test.html.svn-base new file mode 100644 index 0000000..de7e093 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/heap_test.html.svn-base @@ -0,0 +1,220 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright 2006 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> +<head> +<meta http-equiv="X-UA-Compatible" content="IE=edge"> +<title>Closure Unit Tests - goog.structs.Heap</title> +<script src="../base.js"></script> +<script> + goog.require('goog.structs'); + goog.require('goog.structs.Heap'); + goog.require('goog.testing.jsunit'); +</script> +</head> +<body> +<script> + +function getHeap() { + var h = new goog.structs.Heap(); + h.insert(0, 'a'); + h.insert(1, 'b'); + h.insert(2, 'c'); + h.insert(3, 'd'); + return h; +} + + +function getHeap2() { + var h = new goog.structs.Heap(); + h.insert(1, 'b'); + h.insert(3, 'd'); + h.insert(0, 'a'); + h.insert(2, 'c'); + return h; +} + + +function testGetCount1() { + var h = getHeap(); + assertEquals('count, should be 4', h.getCount(), 4); + h.remove(); + assertEquals('count, should be 3', h.getCount(), 3); +} + +function testGetCount2() { + var h = getHeap(); + h.remove(); + h.remove(); + h.remove(); + h.remove(); + assertEquals('count, should be 0', h.getCount(), 0); +} + + +function testKeys() { + var h = getHeap(); + var keys = h.getKeys(); + for (var i = 0; i < 4; i++) { + assertTrue('getKeys, key ' + i + ' found', goog.structs.contains(keys, i)); + } + assertEquals('getKeys, Should be 4 keys', goog.structs.getCount(keys), 4); +} + + +function testValues() { + var h = getHeap(); + var values = h.getValues(); + + assertTrue('getKeys, value "a" found', goog.structs.contains(values, 'a')); + assertTrue('getKeys, value "b" found', goog.structs.contains(values, 'b')); + assertTrue('getKeys, value "c" found', goog.structs.contains(values, 'c')); + assertTrue('getKeys, value "d" found', goog.structs.contains(values, 'd')); + assertEquals('getKeys, Should be 4 keys', goog.structs.getCount(values), 4); +} + + +function testContainsKey() { + var h = getHeap(); + + for (var i = 0; i < 4; i++) { + assertTrue('containsKey, key ' + i + ' found', h.containsKey(i)); + } + assertFalse('containsKey, value 4 not found', h.containsKey(4)); +} + + +function testContainsValue() { + var h = getHeap(); + + assertTrue('containsValue, value "a" found', h.containsValue('a')); + assertTrue('containsValue, value "b" found', h.containsValue('b')); + assertTrue('containsValue, value "c" found', h.containsValue('c')); + assertTrue('containsValue, value "d" found', h.containsValue('d')); + assertFalse('containsValue, value "e" not found', h.containsValue('e')); +} + + +function testClone() { + var h = getHeap(); + var h2 = h.clone(); + assertTrue('clone so it should not be empty', !h2.isEmpty()); + assertTrue('clone so it should contain key 0', h2.containsKey(0)); + assertTrue('clone so it should contain value "a"', h2.containsValue('a')); +} + + +function testClear() { + var h = getHeap(); + h.clear(); + assertTrue('cleared so it should be empty', h.isEmpty()); +} + + +function testIsEmpty() { + var h = getHeap(); + assertFalse('4 values so should not be empty', h.isEmpty()); + + h.remove(); + h.remove(); + h.remove(); + assertFalse('1 values so should not be empty', h.isEmpty()); + + h.remove(); + assertTrue('0 values so should be empty', h.isEmpty()); +} + + +function testPeek1() { + var h = getHeap(); + assertEquals('peek, Should be "a"', h.peek(), 'a'); +} + + +function testPeek2() { + var h = getHeap2(); + assertEquals('peek, Should be "a"', h.peek(), 'a'); +} + + +function testPeek3() { + var h = getHeap(); + h.clear(); + assertEquals('peek, Should be "undefined"', h.peek(), undefined); +} + + +function testPeekKey1() { + var h = getHeap(); + assertEquals('peekKey, Should be "0"', h.peekKey(), 0); +} + + +function testPeekKey2() { + var h = getHeap2(); + assertEquals('peekKey, Should be "0"', h.peekKey(), 0); +} + + +function testPeekKey3() { + var h = getHeap(); + h.clear(); + assertEquals('peekKey, Should be "undefined"', h.peekKey(), undefined); +} + + +function testRemove1() { + var h = getHeap(); + + assertEquals('remove, Should be "a"', h.remove(), 'a'); + assertEquals('remove, Should be "b"', h.remove(), 'b'); + assertEquals('remove, Should be "c"', h.remove(), 'c'); + assertEquals('remove, Should be "d"', h.remove(), 'd'); +} + + +function testRemove2() { + var h = getHeap2(); + + assertEquals('remove, Should be "a"', h.remove(), 'a'); + assertEquals('remove, Should be "b"', h.remove(), 'b'); + assertEquals('remove, Should be "c"', h.remove(), 'c'); + assertEquals('remove, Should be "d"', h.remove(), 'd'); +} + + +function testInsertPeek1() { + var h = new goog.structs.Heap(); + + h.insert(3, 'd'); + assertEquals('peek, Should be "d"', h.peek(), 'd'); + h.insert(2, 'c'); + assertEquals('peek, Should be "c"', h.peek(), 'c'); + h.insert(1, 'b'); + assertEquals('peek, Should be "b"', h.peek(), 'b'); + h.insert(0, 'a'); + assertEquals('peek, Should be "a"', h.peek(), 'a'); +} + + +function testInsertPeek2() { + var h = new goog.structs.Heap(); + + h.insert(1, 'b'); + assertEquals('peak, Should be "b"', h.peek(), 'b'); + h.insert(3, 'd'); + assertEquals('peak, Should be "b"', h.peek(), 'b'); + h.insert(0, 'a'); + assertEquals('peak, Should be "a"', h.peek(), 'a'); + h.insert(2, 'c'); + assertEquals('peak, Should be "a"', h.peek(), 'a'); +} + + +</script> +</body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/inversionmap.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/inversionmap.js.svn-base new file mode 100644 index 0000000..1c7c2e2 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/inversionmap.js.svn-base @@ -0,0 +1,159 @@ +// Copyright 2008 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Provides inversion and inversion map functionality for storing + * integer ranges and corresponding values. + * + */ + +goog.provide('goog.structs.InversionMap'); + +goog.require('goog.array'); + + + +/** + * Maps ranges to values using goog.structs.Inversion. + * @param {Array.<number>} rangeArray An array of monotonically + * increasing integer values, with at least one instance. + * @param {Array.<*>} valueArray An array of corresponding values. + * Length must be the same as rangeArray. + * @param {boolean=} opt_delta If true, saves only delta from previous value. + * @constructor + */ +goog.structs.InversionMap = function(rangeArray, valueArray, opt_delta) { + if (rangeArray.length != valueArray.length) { + // rangeArray and valueArray has to match in number of entries. + return null; + } + this.storeInversion_(rangeArray, opt_delta); + + /** + * @type {Array} + * @protected + */ + this.values = valueArray; +}; + + +/** + * @type {Array} + * @protected + */ +goog.structs.InversionMap.prototype.rangeArray; + + +/** + * Stores the integers as ranges (half-open). + * If delta is true, the integers are delta from the previous value and + * will be restored to the absolute value. + * When used as a set, even indices are IN, and odd are OUT. + * @param {Array.<number?>} rangeArray An array of monotonically + * increasing integer values, with at least one instance. + * @param {boolean=} opt_delta If true, saves only delta from previous value. + * @private + */ +goog.structs.InversionMap.prototype.storeInversion_ = function(rangeArray, + opt_delta) { + this.rangeArray = rangeArray; + + for (var i = 1; i < rangeArray.length; i++) { + if (rangeArray[i] == null) { + rangeArray[i] = rangeArray[i - 1] + 1; + } else if (opt_delta) { + rangeArray[i] += rangeArray[i - 1]; + } + } +}; + + +/** + * Splices a range -> value map into this inversion map. + * @param {Array.<number>} rangeArray An array of monotonically + * increasing integer values, with at least one instance. + * @param {Array.<*>} valueArray An array of corresponding values. + * Length must be the same as rangeArray. + * @param {boolean=} opt_delta If true, saves only delta from previous value. + */ +goog.structs.InversionMap.prototype.spliceInversion = function( + rangeArray, valueArray, opt_delta) { + // By building another inversion map, we build the arrays that we need + // to splice in. + var otherMap = new goog.structs.InversionMap( + rangeArray, valueArray, opt_delta); + + // Figure out where to splice those arrays. + var startRange = otherMap.rangeArray[0]; + var endRange = + (/** @type {number} */ goog.array.peek(otherMap.rangeArray)); + var startSplice = this.getLeast(startRange); + var endSplice = this.getLeast(endRange); + + // The inversion map works by storing the start points of ranges... + if (startRange != this.rangeArray[startSplice]) { + // ...if we're splicing in a start point that isn't already here, + // then we need to insert it after the insertion point. + startSplice++; + } // otherwise we overwrite the insertion point. + + var spliceLength = endSplice - startSplice + 1; + goog.partial(goog.array.splice, this.rangeArray, startSplice, + spliceLength).apply(null, otherMap.rangeArray); + goog.partial(goog.array.splice, this.values, startSplice, + spliceLength).apply(null, otherMap.values); +}; + + +/** + * Gets the value corresponding to a number from the inversion map. + * @param {number} intKey The number for which value needs to be retrieved + * from inversion map. + * @return {*} Value retrieved from inversion map; null if not found. + */ +goog.structs.InversionMap.prototype.at = function(intKey) { + var index = this.getLeast(intKey); + if (index < 0) { + return null; + } + return this.values[index]; +}; + + +/** + * Gets the largest index such that rangeArray[index] <= intKey from the + * inversion map. + * @param {number} intKey The probe for which rangeArray is searched. + * @return {number} Largest index such that rangeArray[index] <= intKey. + * @protected + */ +goog.structs.InversionMap.prototype.getLeast = function(intKey) { + var arr = this.rangeArray; + var low = 0; + var high = arr.length; + while (high - low > 8) { + var mid = (high + low) >> 1; + if (arr[mid] <= intKey) { + low = mid; + } else { + high = mid; + } + } + for (; low < high; ++low) { + if (intKey < arr[low]) { + break; + } + } + return low - 1; +}; diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/inversionmap_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/inversionmap_test.html.svn-base new file mode 100644 index 0000000..d461edf --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/inversionmap_test.html.svn-base @@ -0,0 +1,157 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright 2008 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> +<head> +<meta http-equiv="X-UA-Compatible" content="IE=edge"> +<title>Closure Unit Tests - goog.structs.InversionMap</title> +<script type="text/javascript" src="../base.js"></script> +<script type="text/javascript"> + goog.require('goog.structs.InversionMap'); + goog.require('goog.testing.jsunit'); +</script> +</head> +<body> +<script type="text/javascript"> + function testInversionWithDelta() { + var alphabetNames = new goog.structs.InversionMap( + [ 0, 97, 1, 1, 1, 20, 1, 1, 1 ], + [ null, + 'LATIN SMALL LETTER A', + 'LATIN SMALL LETTER B', + 'LATIN SMALL LETTER C', + null, + 'LATIN SMALL LETTER X', + 'LATIN SMALL LETTER Y', + 'LATIN SMALL LETTER Z', + null ], + true); + + assertEquals('LATIN SMALL LETTER A', alphabetNames.at(97)); + assertEquals('LATIN SMALL LETTER Y', alphabetNames.at(121)); + assertEquals(null, alphabetNames.at(140)); + assertEquals(null, alphabetNames.at(0)); + } + + function testInversionWithoutDelta() { + var alphabetNames = new goog.structs.InversionMap( + [ 0, 97, 98, 99, 100, 120, 121, 122, 123 ], + [ null, + 'LATIN SMALL LETTER A', + 'LATIN SMALL LETTER B', + 'LATIN SMALL LETTER C', + null, + 'LATIN SMALL LETTER X', + 'LATIN SMALL LETTER Y', + 'LATIN SMALL LETTER Z', + null ], + false); + + assertEquals('LATIN SMALL LETTER A', alphabetNames.at(97)); + assertEquals('LATIN SMALL LETTER Y', alphabetNames.at(121)); + assertEquals(null, alphabetNames.at(140)); + assertEquals(null, alphabetNames.at(0)); + } + + function testInversionWithoutDeltaNoOpt() { + var alphabetNames = new goog.structs.InversionMap( + [ 0, 97, 98, 99, 100, 120, 121, 122, 123 ], + [ null, + 'LATIN SMALL LETTER A', + 'LATIN SMALL LETTER B', + 'LATIN SMALL LETTER C', + null, + 'LATIN SMALL LETTER X', + 'LATIN SMALL LETTER Y', + 'LATIN SMALL LETTER Z', + null ]); + + assertEquals('LATIN SMALL LETTER A', alphabetNames.at(97)); + assertEquals('LATIN SMALL LETTER Y', alphabetNames.at(121)); + assertEquals(null, alphabetNames.at(140)); + assertEquals(null, alphabetNames.at(0)); + } + + function testInversionMapSplice1() { + var alphabetNames = newAsciiMap(); + alphabetNames.spliceInversion( + [ 99, 105, 114 ], [ 'XXX', 'YYY', 'ZZZ' ]); + assertEquals('LATIN SMALL LETTER B', alphabetNames.at(98)); + assertEquals('XXX', alphabetNames.at(100)); + assertEquals('ZZZ', alphabetNames.at(114)); + assertEquals('ZZZ', alphabetNames.at(119)); + assertEquals('LATIN SMALL LETTER X', alphabetNames.at(120)); + } + + function testInversionMapSplice2() { + var alphabetNames = newAsciiMap(); + alphabetNames.spliceInversion( + [ 105, 114, 121 ], [ 'XXX', 'YYY', 'ZZZ' ]); + assertEquals(null, alphabetNames.at(104)); + assertEquals('XXX', alphabetNames.at(105)); + assertEquals('YYY', alphabetNames.at(120)); + assertEquals('ZZZ', alphabetNames.at(121)); + assertEquals('LATIN SMALL LETTER Z', alphabetNames.at(122)); + } + + function testInversionMapSplice3() { + var alphabetNames = newAsciiMap(); + alphabetNames.spliceInversion( + [ 98, 99 ], [ 'CHANGED LETTER B', 'CHANGED LETTER C' ]); + assertEquals('LATIN SMALL LETTER A', alphabetNames.at(97)); + assertEquals('CHANGED LETTER B', alphabetNames.at(98)); + assertEquals('CHANGED LETTER C', alphabetNames.at(99)); + assertEquals('LATIN SMALL LETTER D', alphabetNames.at(100)); + assertEquals(null, alphabetNames.at(101)); + } + + function testInversionMapSplice4() { + var alphabetNames = newAsciiMap(); + alphabetNames.spliceInversion( + [ 98, 1 ], [ 'CHANGED LETTER B', 'CHANGED LETTER C' ], + true /* delta mode */); + assertEquals('LATIN SMALL LETTER A', alphabetNames.at(97)); + assertEquals('CHANGED LETTER B', alphabetNames.at(98)); + assertEquals('CHANGED LETTER C', alphabetNames.at(99)); + assertEquals('LATIN SMALL LETTER D', alphabetNames.at(100)); + assertEquals(null, alphabetNames.at(101)); + } + + function testInversionMapSplice5() { + var map = new goog.structs.InversionMap( + [0, 97, 98, 99], + [null, + 'LATIN SMALL LETTER A', + 'LATIN SMALL LETTER B', + 'LATIN SMALL LETTER C']); + map.spliceInversion( + [98], ['CHANGED LETTER B']); + assertEquals('LATIN SMALL LETTER A', map.at(97)); + assertEquals('CHANGED LETTER B', map.at(98)); + assertEquals('LATIN SMALL LETTER C', map.at(99)); + + assertArrayEquals([0, 97, 98, 99], map.rangeArray); + } + + function newAsciiMap() { + return new goog.structs.InversionMap( + [ 0, 97, 98, 99, 100, 101, 120, 121, 122, 123 ], + [ null, + 'LATIN SMALL LETTER A', + 'LATIN SMALL LETTER B', + 'LATIN SMALL LETTER C', + 'LATIN SMALL LETTER D', + null, + 'LATIN SMALL LETTER X', + 'LATIN SMALL LETTER Y', + 'LATIN SMALL LETTER Z', + null ]); + } + +</script> +</body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/linkedmap.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/linkedmap.js.svn-base new file mode 100644 index 0000000..bfaf230 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/linkedmap.js.svn-base @@ -0,0 +1,472 @@ +// Copyright 2007 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview A LinkedMap data structure that is accessed using key/value + * pairs like an ordinary Map, but which guarantees a consistent iteration + * order over its entries. The iteration order is either insertion order (the + * default) or ordered from most recent to least recent use. By setting a fixed + * size, the LRU version of the LinkedMap makes an effective object cache. This + * data structure is similar to Java's LinkedHashMap. + * + */ + + +goog.provide('goog.structs.LinkedMap'); + +goog.require('goog.structs.Map'); + + + +/** + * Class for a LinkedMap datastructure, which combines O(1) map access for + * key/value pairs with a linked list for a consistent iteration order. Sample + * usage: + * + * <pre> + * var m = new LinkedMap(); + * m.set('param1', 'A'); + * m.set('param2', 'B'); + * m.set('param3', 'C'); + * alert(m.getKeys()); // param1, param2, param3 + * + * var c = new LinkedMap(5, true); + * for (var i = 0; i < 10; i++) { + * c.set('entry' + i, false); + * } + * alert(c.getKeys()); // entry9, entry8, entry7, entry6, entry5 + * + * c.set('entry5', true); + * c.set('entry1', false); + * alert(c.getKeys()); // entry1, entry5, entry9, entry8, entry7 + * </pre> + * + * @param {number=} opt_maxCount The maximum number of objects to store in the + * LinkedMap. If unspecified or 0, there is no maximum. + * @param {boolean=} opt_cache When set, the LinkedMap stores items in order + * from most recently used to least recently used, instead of insertion + * order. + * @constructor + */ +goog.structs.LinkedMap = function(opt_maxCount, opt_cache) { + /** + * The maximum number of entries to allow, or null if there is no limit. + * @type {?number} + * @private + */ + this.maxCount_ = opt_maxCount || null; + + /** + * @type {boolean} + * @private + */ + this.cache_ = !!opt_cache; + + this.map_ = new goog.structs.Map(); + + this.head_ = new goog.structs.LinkedMap.Node_('', undefined); + this.head_.next = this.head_.prev = this.head_; +}; + + +/** + * Finds a node and updates it to be the most recently used. + * @param {string} key The key of the node. + * @return {goog.structs.LinkedMap.Node_} The node or null if not found. + * @private + */ +goog.structs.LinkedMap.prototype.findAndMoveToTop_ = function(key) { + var node = /** @type {goog.structs.LinkedMap.Node_} */ (this.map_.get(key)); + if (node) { + if (this.cache_) { + node.remove(); + this.insert_(node); + } + } + return node; +}; + + +/** + * Retrieves the value for a given key. If this is a caching LinkedMap, the + * entry will become the most recently used. + * @param {string} key The key to retrieve the value for. + * @param {*=} opt_val A default value that will be returned if the key is + * not found, defaults to undefined. + * @return {*} The retrieved value. + */ +goog.structs.LinkedMap.prototype.get = function(key, opt_val) { + var node = this.findAndMoveToTop_(key); + return node ? node.value : opt_val; +}; + + +/** + * Retrieves the value for a given key without updating the entry to be the + * most recently used. + * @param {string} key The key to retrieve the value for. + * @param {*=} opt_val A default value that will be returned if the key is + * not found. + * @return {*} The retrieved value. + */ +goog.structs.LinkedMap.prototype.peekValue = function(key, opt_val) { + var node = this.map_.get(key); + return node ? node.value : opt_val; +}; + + +/** + * Sets a value for a given key. If this is a caching LinkedMap, this entry + * will become the most recently used. + * @param {string} key The key to retrieve the value for. + * @param {*} value A default value that will be returned if the key is + * not found. + */ +goog.structs.LinkedMap.prototype.set = function(key, value) { + var node = this.findAndMoveToTop_(key); + if (node) { + node.value = value; + } else { + node = new goog.structs.LinkedMap.Node_(key, value); + this.map_.set(key, node); + this.insert_(node); + } +}; + + +/** + * Returns the value of the first node without making any modifications. + * @return {*} The value of the first node or undefined if the map is empty. + */ +goog.structs.LinkedMap.prototype.peek = function() { + return this.head_.next.value; +}; + + +/** + * Returns the value of the last node without making any modifications. + * @return {*} The value of the last node or undefined if the map is empty. + */ +goog.structs.LinkedMap.prototype.peekLast = function() { + return this.head_.prev.value; +}; + + +/** + * Removes the first node from the list and returns its value. + * @return {*} The value of the popped node, or undefined if the map was empty. + */ +goog.structs.LinkedMap.prototype.shift = function() { + return this.popNode_(this.head_.next); +}; + + +/** + * Removes the last node from the list and returns its value. + * @return {*} The value of the popped node, or undefined if the map was empty. + */ +goog.structs.LinkedMap.prototype.pop = function() { + return this.popNode_(this.head_.prev); +}; + + +/** + * Removes a value from the LinkedMap based on its key. + * @param {string} key The key to remove. + * @return {boolean} True if the entry was removed, false if the key was not + * found. + */ +goog.structs.LinkedMap.prototype.remove = function(key) { + var node = /** @type {goog.structs.LinkedMap.Node_} */ (this.map_.get(key)); + if (node) { + this.removeNode(node); + return true; + } + return false; +}; + + +/** + * Removes a node from the {@code LinkedMap}. It can be overridden to do + * further cleanup such as disposing of the node value. + * @param {!goog.structs.LinkedMap.Node_} node The node to remove. + * @protected + */ +goog.structs.LinkedMap.prototype.removeNode = function(node) { + node.remove(); + this.map_.remove(node.key); +}; + + +/** + * @return {number} The number of items currently in the LinkedMap. + */ +goog.structs.LinkedMap.prototype.getCount = function() { + return this.map_.getCount(); +}; + + +/** + * @return {boolean} True if the cache is empty, false if it contains any items. + */ +goog.structs.LinkedMap.prototype.isEmpty = function() { + return this.map_.isEmpty(); +}; + + +/** + * Sets the maximum number of entries allowed in this object, truncating any + * excess objects if necessary. + * @param {number} maxCount The new maximum number of entries to allow. + */ +goog.structs.LinkedMap.prototype.setMaxCount = function(maxCount) { + this.maxCount_ = maxCount || null; + if (this.maxCount_ != null) { + this.truncate_(this.maxCount_); + } +}; + + +/** + * @return {Array.<string>} The list of the keys in the appropriate order for + * this LinkedMap. + */ +goog.structs.LinkedMap.prototype.getKeys = function() { + return this.map(function(val, key) { + return key; + }); +}; + + +/** + * @return {!Array} The list of the values in the appropriate order for + * this LinkedMap. + */ +goog.structs.LinkedMap.prototype.getValues = function() { + return this.map(function(val, key) { + return val; + }); +}; + + +/** + * Tests whether a provided value is currently in the LinkedMap. This does not + * affect item ordering in cache-style LinkedMaps. + * @param {Object} value The value to check for. + * @return {boolean} Whether the value is in the LinkedMap. + */ +goog.structs.LinkedMap.prototype.contains = function(value) { + return this.some(function(el) { + return el == value; + }); +}; + + +/** + * Tests whether a provided key is currently in the LinkedMap. This does not + * affect item ordering in cache-style LinkedMaps. + * @param {string} key The key to check for. + * @return {boolean} Whether the key is in the LinkedMap. + */ +goog.structs.LinkedMap.prototype.containsKey = function(key) { + return this.map_.containsKey(key); +}; + + +/** + * Removes all entries in this object. + */ +goog.structs.LinkedMap.prototype.clear = function() { + this.truncate_(0); +}; + + +/** + * Calls a function on each item in the LinkedMap. + * + * @see goog.structs.forEach + * @param {Function} f The function to call for each item. The function takes + * three arguments: the value, the key, and the LinkedMap. + * @param {Object=} opt_obj The object context to use as "this" for the + * function. + */ +goog.structs.LinkedMap.prototype.forEach = function(f, opt_obj) { + for (var n = this.head_.next; n != this.head_; n = n.next) { + f.call(opt_obj, n.value, n.key, this); + } +}; + + +/** + * Calls a function on each item in the LinkedMap and returns the results of + * those calls in an array. + * + * @see goog.structs.map + * @param {!Function} f The function to call for each item. The function takes + * three arguments: the value, the key, and the LinkedMap. + * @param {Object=} opt_obj The object context to use as "this" for the + * function. + * @return {!Array} The results of the function calls for each item in the + * LinkedMap. + */ +goog.structs.LinkedMap.prototype.map = function(f, opt_obj) { + var rv = []; + for (var n = this.head_.next; n != this.head_; n = n.next) { + rv.push(f.call(opt_obj, n.value, n.key, this)); + } + return rv; +}; + + +/** + * Calls a function on each item in the LinkedMap and returns true if any of + * those function calls returns a true-like value. + * + * @see goog.structs.some + * @param {Function} f The function to call for each item. The function takes + * three arguments: the value, the key, and the LinkedMap, and returns a + * boolean. + * @param {Object=} opt_obj The object context to use as "this" for the + * function. + * @return {boolean} Whether f evaluates to true for at least one item in the + * LinkedMap. + */ +goog.structs.LinkedMap.prototype.some = function(f, opt_obj) { + for (var n = this.head_.next; n != this.head_; n = n.next) { + if (f.call(opt_obj, n.value, n.key, this)) { + return true; + } + } + return false; +}; + + +/** + * Calls a function on each item in the LinkedMap and returns true only if every + * function call returns a true-like value. + * + * @see goog.structs.some + * @param {Function} f The function to call for each item. The function takes + * three arguments: the value, the key, and the Cache, and returns a + * boolean. + * @param {Object=} opt_obj The object context to use as "this" for the + * function. + * @return {boolean} Whether f evaluates to true for every item in the Cache. + */ +goog.structs.LinkedMap.prototype.every = function(f, opt_obj) { + for (var n = this.head_.next; n != this.head_; n = n.next) { + if (!f.call(opt_obj, n.value, n.key, this)) { + return false; + } + } + return true; +}; + + +/** + * Appends a node to the list. LinkedMap in cache mode adds new nodes to + * the head of the list, otherwise they are appended to the tail. If there is a + * maximum size, the list will be truncated if necessary. + * + * @param {goog.structs.LinkedMap.Node_} node The item to insert. + * @private + */ +goog.structs.LinkedMap.prototype.insert_ = function(node) { + if (this.cache_) { + node.next = this.head_.next; + node.prev = this.head_; + + this.head_.next = node; + node.next.prev = node; + } else { + node.prev = this.head_.prev; + node.next = this.head_; + + this.head_.prev = node; + node.prev.next = node; + } + + if (this.maxCount_ != null) { + this.truncate_(this.maxCount_); + } +}; + + +/** + * Removes elements from the LinkedMap if the given count has been exceeded. + * In cache mode removes nodes from the tail of the list. Otherwise removes + * nodes from the head. + * @param {number} count Number of elements to keep. + * @private + */ +goog.structs.LinkedMap.prototype.truncate_ = function(count) { + for (var i = this.map_.getCount(); i > count; i--) { + this.removeNode(this.cache_ ? this.head_.prev : this.head_.next); + } +}; + + +/** + * Removes the node from the LinkedMap if it is not the head, and returns + * the node's value. + * @param {!goog.structs.LinkedMap.Node_} node The item to remove. + * @return {*} The value of the popped node. + * @private + */ +goog.structs.LinkedMap.prototype.popNode_ = function(node) { + if (this.head_ != node) { + this.removeNode(node); + } + return node.value; +}; + + + +/** + * Internal class for a doubly-linked list node containing a key/value pair. + * @param {string} key The key. + * @param {*} value The value. + * @constructor + * @private + */ +goog.structs.LinkedMap.Node_ = function(key, value) { + this.key = key; + this.value = value; +}; + + +/** + * The next node in the list. + * @type {!goog.structs.LinkedMap.Node_} + */ +goog.structs.LinkedMap.Node_.prototype.next; + + +/** + * The previous node in the list. + * @type {!goog.structs.LinkedMap.Node_} + */ +goog.structs.LinkedMap.Node_.prototype.prev; + + +/** + * Causes this node to remove itself from the list. + */ +goog.structs.LinkedMap.Node_.prototype.remove = function() { + this.prev.next = this.next; + this.next.prev = this.prev; + + delete this.prev; + delete this.next; +}; diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/linkedmap_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/linkedmap_test.html.svn-base new file mode 100644 index 0000000..d20faac --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/linkedmap_test.html.svn-base @@ -0,0 +1,300 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright 2006 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> +<head> +<meta http-equiv="X-UA-Compatible" content="IE=edge"> +<title>Closure Unit Tests - goog.structs.LinkedMap</title> +<script src="../base.js"></script> +<script> + goog.require('goog.structs.LinkedMap'); + goog.require('goog.testing.jsunit'); + goog.require('goog.testing.recordFunction'); +</script> +</head> +<body> +<script> + +function fillLinkedMap(m) { + m.set('a', 0); + m.set('b', 1); + m.set('c', 2); + m.set('d', 3); +} + +var someObj = {}; + +function testLinkedMap() { + var m = new goog.structs.LinkedMap(); + fillLinkedMap(m); + + assertArrayEquals(['a', 'b', 'c', 'd'], m.getKeys()); + assertArrayEquals([0, 1, 2, 3], m.getValues()); +} + +function testMaxSizeLinkedMap() { + var m = new goog.structs.LinkedMap(3); + fillLinkedMap(m); + + assertArrayEquals(['b', 'c', 'd'], m.getKeys()); + assertArrayEquals([1, 2, 3], m.getValues()); +} + +function testLruLinkedMap() { + var m = new goog.structs.LinkedMap(undefined, true); + fillLinkedMap(m); + + assertArrayEquals(['d', 'c', 'b', 'a'], m.getKeys()); + assertArrayEquals([3, 2, 1, 0], m.getValues()); + + m.get('a'); + assertArrayEquals(['a', 'd', 'c', 'b'], m.getKeys()); + assertArrayEquals([0, 3, 2, 1], m.getValues()); + + m.set('b', 4); + assertArrayEquals(['b', 'a', 'd', 'c'], m.getKeys()); + assertArrayEquals([4, 0, 3, 2], m.getValues()); +} + +function testMaxSizeLruLinkedMap() { + var m = new goog.structs.LinkedMap(3, true); + fillLinkedMap(m); + + assertArrayEquals(['d', 'c', 'b'], m.getKeys()); + assertArrayEquals([3, 2, 1], m.getValues()); + + m.get('c'); + assertArrayEquals(['c', 'd', 'b'], m.getKeys()); + assertArrayEquals([2, 3, 1], m.getValues()); + + m.set('d', 4); + assertArrayEquals(['d', 'c', 'b'], m.getKeys()); + assertArrayEquals([4, 2, 1], m.getValues()); +} + +function testGetCount() { + var m = new goog.structs.LinkedMap(); + assertEquals(0, m.getCount()); + m.set('a', 0); + assertEquals(1, m.getCount()); + m.set('a', 1); + assertEquals(1, m.getCount()); + m.set('b', 2); + assertEquals(2, m.getCount()); + m.remove('a'); + assertEquals(1, m.getCount()); +} + +function testIsEmpty() { + var m = new goog.structs.LinkedMap(); + assertTrue(m.isEmpty()); + m.set('a', 0); + assertFalse(m.isEmpty()); + m.remove('a'); + assertTrue(m.isEmpty()); +} + +function testSetMaxCount() { + var m = new goog.structs.LinkedMap(3); + fillLinkedMap(m); + assertEquals(3, m.getCount()); + + m.setMaxCount(5); + m.set('e', 5); + m.set('f', 6); + m.set('g', 7); + assertEquals(5, m.getCount()); + + m.setMaxCount(4); + assertEquals(4, m.getCount()); + + m.setMaxCount(0); + m.set('h', 8); + m.set('i', 9); + m.set('j', 10); + assertEquals(7, m.getCount()); +} + +function testClear() { + var m = new goog.structs.LinkedMap(); + fillLinkedMap(m); + m.clear(); + assertTrue(m.isEmpty()); +} + +function testForEach() { + var m = new goog.structs.LinkedMap(); + fillLinkedMap(m); + + m.forEach(function(val, key, linkedMap) { + linkedMap.set(key, val * 2); + assertEquals('forEach should run in provided context.', someObj, this); + }, someObj); + + assertArrayEquals(['a', 'b', 'c', 'd'], m.getKeys()); + assertArrayEquals([0, 2, 4, 6], m.getValues()); +} + +function testMap() { + var m = new goog.structs.LinkedMap(); + fillLinkedMap(m); + + var result = m.map(function(val, key, linkedMap) { + assertEquals('The LinkedMap object should get passed in', m, linkedMap); + assertEquals('map should run in provided context', someObj, this); + return key + val; + }, someObj); + + assertArrayEquals(['a0', 'b1', 'c2', 'd3'], result); +} + +function testSome() { + var m = new goog.structs.LinkedMap(); + fillLinkedMap(m); + + var result = m.some(function(val, key, linkedMap) { + assertEquals('The LinkedMap object should get passed in', m, linkedMap); + assertEquals('map should run in provided context', someObj, this); + return val > 2; + }, someObj); + + assertTrue(result); + assertFalse(m.some(function(val) {return val > 3})); + + assertTrue(m.some(function(val, key) {return key == 'c';})); + assertFalse(m.some(function(val, key) {return key == 'e';})); +} + +function testEvery() { + var m = new goog.structs.LinkedMap(); + fillLinkedMap(m); + + var result = m.every(function(val, key, linkedMap) { + assertEquals('The LinkedMap object should get passed in', m, linkedMap); + assertEquals('map should run in provided context', someObj, this); + return val < 5; + }, someObj); + + assertTrue(result); + assertFalse(m.every(function(val) {return val < 2})); + + assertTrue(m.every(function(val, key) {return key.length == 1;})); + assertFalse(m.every(function(val, key) {return key == 'b';})); +} + +function testPeek() { + var m = new goog.structs.LinkedMap(); + assertEquals(undefined, m.peek()); + assertEquals(undefined, m.peekLast()); + + fillLinkedMap(m); + assertEquals(0, m.peek()); + + m.remove('a'); + assertEquals(1, m.peek()); + + assertEquals(3, m.peekLast()); + + assertEquals(3, m.peekValue('d')); + assertEquals(1, m.peek()); + + m.remove('d'); + assertEquals(2, m.peekLast()); +} + +function testPop() { + var m = new goog.structs.LinkedMap(); + assertEquals(undefined, m.shift()); + assertEquals(undefined, m.pop()); + + fillLinkedMap(m); + assertEquals(4, m.getCount()); + + assertEquals(0, m.shift()); + assertEquals(1, m.peek()); + + assertEquals(3, m.pop()); + assertEquals(2, m.peekLast()); + + assertEquals(2, m.getCount()); +} + +function testContains() { + var m = new goog.structs.LinkedMap(); + fillLinkedMap(m); + + assertTrue(m.contains(2)); + assertFalse(m.contains(4)); +} + +function testContainsKey() { + var m = new goog.structs.LinkedMap(); + fillLinkedMap(m); + + assertTrue(m.containsKey('b')); + assertFalse(m.containsKey('elephant')); + assertFalse(m.containsKey('undefined')); +} + +function testRemoveNodeCalls() { + var m = new goog.structs.LinkedMap(1); + m.removeNode = goog.testing.recordFunction(m.removeNode); + + m.set('1', 1); + assertEquals('removeNode not called after adding an element', 0, + m.removeNode.getCallCount()); + m.set('1', 2); + assertEquals('removeNode not called after updating an element', 0, + m.removeNode.getCallCount()); + m.set('2', 2); + assertEquals('removeNode called after adding an overflowing element', 1, + m.removeNode.getCallCount()); + + m.remove('3'); + assertEquals('removeNode not called after removing a non-existing element', 1, + m.removeNode.getCallCount()); + m.remove('2'); + assertEquals('removeNode called after removing an existing element', 2, + m.removeNode.getCallCount()); + + m.set('1', 1); + m.clear(); + assertEquals('removeNode called after clearing the map', 3, + m.removeNode.getCallCount()); + m.clear(); + assertEquals('removeNode not called after clearing an empty map', 3, + m.removeNode.getCallCount()); + + m.set('1', 1); + m.pop(); + assertEquals('removeNode called after calling pop', 4, + m.removeNode.getCallCount()); + m.pop(); + assertEquals('removeNode not called after calling pop on an empty map', 4, + m.removeNode.getCallCount()); + + m.set('1', 1); + m.shift(); + assertEquals('removeNode called after calling shift', 5, + m.removeNode.getCallCount()); + m.shift(); + assertEquals('removeNode not called after calling shift on an empty map', 5, + m.removeNode.getCallCount()); + + m.setMaxCount(2); + m.set('1', 1); + m.set('2', 2); + assertEquals('removeNode not called after increasing the maximum map size', 5, + m.removeNode.getCallCount()); + m.setMaxCount(1); + assertEquals('removeNode called after decreasing the maximum map size', 6, + m.removeNode.getCallCount()); +} + +</script> +</body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/map.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/map.js.svn-base new file mode 100644 index 0000000..f48d81b --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/map.js.svn-base @@ -0,0 +1,448 @@ +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Datastructure: Hash Map. + * + * @author arv@google.com (Erik Arvidsson) + * @author jonp@google.com (Jon Perlow) Optimized for IE6 + * + * This file contains an implementation of a Map structure. It implements a lot + * of the methods used in goog.structs so those functions work on hashes. For + * convenience with common usage the methods accept any type for the key, though + * internally they will be cast to strings. + */ + + +goog.provide('goog.structs.Map'); + +goog.require('goog.iter.Iterator'); +goog.require('goog.iter.StopIteration'); +goog.require('goog.object'); +goog.require('goog.structs'); + + + +/** + * Class for Hash Map datastructure. + * @param {*=} opt_map Map or Object to initialize the map with. + * @param {...*} var_args If 2 or more arguments are present then they + * will be used as key-value pairs. + * @constructor + */ +goog.structs.Map = function(opt_map, var_args) { + + /** + * Underlying JS object used to implement the map. + * @type {!Object} + * @private + */ + this.map_ = {}; + + /** + * An array of keys. This is necessary for two reasons: + * 1. Iterating the keys using for (var key in this.map_) allocates an + * object for every key in IE which is really bad for IE6 GC perf. + * 2. Without a side data structure, we would need to escape all the keys + * as that would be the only way we could tell during iteration if the + * key was an internal key or a property of the object. + * + * This array can contain deleted keys so it's necessary to check the map + * as well to see if the key is still in the map (this doesn't require a + * memory allocation in IE). + * @type {!Array.<string>} + * @private + */ + this.keys_ = []; + + var argLength = arguments.length; + + if (argLength > 1) { + if (argLength % 2) { + throw Error('Uneven number of arguments'); + } + for (var i = 0; i < argLength; i += 2) { + this.set(arguments[i], arguments[i + 1]); + } + } else if (opt_map) { + this.addAll(/** @type {Object} */ (opt_map)); + } +}; + + +/** + * The number of key value pairs in the map. + * @private + * @type {number} + */ +goog.structs.Map.prototype.count_ = 0; + + +/** + * Version used to detect changes while iterating. + * @private + * @type {number} + */ +goog.structs.Map.prototype.version_ = 0; + + +/** + * @return {number} The number of key-value pairs in the map. + */ +goog.structs.Map.prototype.getCount = function() { + return this.count_; +}; + + +/** + * Returns the values of the map. + * @return {!Array} The values in the map. + */ +goog.structs.Map.prototype.getValues = function() { + this.cleanupKeysArray_(); + + var rv = []; + for (var i = 0; i < this.keys_.length; i++) { + var key = this.keys_[i]; + rv.push(this.map_[key]); + } + return rv; +}; + + +/** + * Returns the keys of the map. + * @return {!Array.<string>} Array of string values. + */ +goog.structs.Map.prototype.getKeys = function() { + this.cleanupKeysArray_(); + return /** @type {!Array.<string>} */ (this.keys_.concat()); +}; + + +/** + * Whether the map contains the given key. + * @param {*} key The key to check for. + * @return {boolean} Whether the map contains the key. + */ +goog.structs.Map.prototype.containsKey = function(key) { + return goog.structs.Map.hasKey_(this.map_, key); +}; + + +/** + * Whether the map contains the given value. This is O(n). + * @param {*} val The value to check for. + * @return {boolean} Whether the map contains the value. + */ +goog.structs.Map.prototype.containsValue = function(val) { + for (var i = 0; i < this.keys_.length; i++) { + var key = this.keys_[i]; + if (goog.structs.Map.hasKey_(this.map_, key) && this.map_[key] == val) { + return true; + } + } + return false; +}; + + +/** + * Whether this map is equal to the argument map. + * @param {goog.structs.Map} otherMap The map against which to test equality. + * @param {function(*, *) : boolean=} opt_equalityFn Optional equality function + * to test equality of values. If not specified, this will test whether + * the values contained in each map are identical objects. + * @return {boolean} Whether the maps are equal. + */ +goog.structs.Map.prototype.equals = function(otherMap, opt_equalityFn) { + if (this === otherMap) { + return true; + } + + if (this.count_ != otherMap.getCount()) { + return false; + } + + var equalityFn = opt_equalityFn || goog.structs.Map.defaultEquals; + + this.cleanupKeysArray_(); + for (var key, i = 0; key = this.keys_[i]; i++) { + if (!equalityFn(this.get(key), otherMap.get(key))) { + return false; + } + } + + return true; +}; + + +/** + * Default equality test for values. + * @param {*} a The first value. + * @param {*} b The second value. + * @return {boolean} Whether a and b reference the same object. + */ +goog.structs.Map.defaultEquals = function(a, b) { + return a === b; +}; + + +/** + * @return {boolean} Whether the map is empty. + */ +goog.structs.Map.prototype.isEmpty = function() { + return this.count_ == 0; +}; + + +/** + * Removes all key-value pairs from the map. + */ +goog.structs.Map.prototype.clear = function() { + this.map_ = {}; + this.keys_.length = 0; + this.count_ = 0; + this.version_ = 0; +}; + + +/** + * Removes a key-value pair based on the key. This is O(logN) amortized due to + * updating the keys array whenever the count becomes half the size of the keys + * in the keys array. + * @param {*} key The key to remove. + * @return {boolean} Whether object was removed. + */ +goog.structs.Map.prototype.remove = function(key) { + if (goog.structs.Map.hasKey_(this.map_, key)) { + delete this.map_[key]; + this.count_--; + this.version_++; + + // clean up the keys array if the threshhold is hit + if (this.keys_.length > 2 * this.count_) { + this.cleanupKeysArray_(); + } + + return true; + } + return false; +}; + + +/** + * Cleans up the temp keys array by removing entries that are no longer in the + * map. + * @private + */ +goog.structs.Map.prototype.cleanupKeysArray_ = function() { + if (this.count_ != this.keys_.length) { + // First remove keys that are no longer in the map. + var srcIndex = 0; + var destIndex = 0; + while (srcIndex < this.keys_.length) { + var key = this.keys_[srcIndex]; + if (goog.structs.Map.hasKey_(this.map_, key)) { + this.keys_[destIndex++] = key; + } + srcIndex++; + } + this.keys_.length = destIndex; + } + + if (this.count_ != this.keys_.length) { + // If the count still isn't correct, that means we have duplicates. This can + // happen when the same key is added and removed multiple times. Now we have + // to allocate one extra Object to remove the duplicates. This could have + // been done in the first pass, but in the common case, we can avoid + // allocating an extra object by only doing this when necessary. + var seen = {}; + var srcIndex = 0; + var destIndex = 0; + while (srcIndex < this.keys_.length) { + var key = this.keys_[srcIndex]; + if (!(goog.structs.Map.hasKey_(seen, key))) { + this.keys_[destIndex++] = key; + seen[key] = 1; + } + srcIndex++; + } + this.keys_.length = destIndex; + } +}; + + +/** + * Returns the value for the given key. If the key is not found and the default + * value is not given this will return {@code undefined}. + * @param {*} key The key to get the value for. + * @param {*=} opt_val The value to return if no item is found for the given + * key, defaults to undefined. + * @return {*} The value for the given key. + */ +goog.structs.Map.prototype.get = function(key, opt_val) { + if (goog.structs.Map.hasKey_(this.map_, key)) { + return this.map_[key]; + } + return opt_val; +}; + + +/** + * Adds a key-value pair to the map. + * @param {*} key The key. + * @param {*} value The value to add. + */ +goog.structs.Map.prototype.set = function(key, value) { + if (!(goog.structs.Map.hasKey_(this.map_, key))) { + this.count_++; + this.keys_.push(key); + // Only change the version if we add a new key. + this.version_++; + } + this.map_[key] = value; +}; + + +/** + * Adds multiple key-value pairs from another goog.structs.Map or Object. + * @param {Object} map Object containing the data to add. + */ +goog.structs.Map.prototype.addAll = function(map) { + var keys, values; + if (map instanceof goog.structs.Map) { + keys = map.getKeys(); + values = map.getValues(); + } else { + keys = goog.object.getKeys(map); + values = goog.object.getValues(map); + } + // we could use goog.array.forEach here but I don't want to introduce that + // dependency just for this. + for (var i = 0; i < keys.length; i++) { + this.set(keys[i], values[i]); + } +}; + + +/** + * Clones a map and returns a new map. + * @return {!goog.structs.Map} A new map with the same key-value pairs. + */ +goog.structs.Map.prototype.clone = function() { + return new goog.structs.Map(this); +}; + + +/** + * Returns a new map in which all the keys and values are interchanged + * (keys become values and values become keys). If multiple keys map to the + * same value, the chosen transposed value is implementation-dependent. + * + * It acts very similarly to {goog.object.transpose(Object)}. + * + * @return {!goog.structs.Map} The transposed map. + */ +goog.structs.Map.prototype.transpose = function() { + var transposed = new goog.structs.Map(); + for (var i = 0; i < this.keys_.length; i++) { + var key = this.keys_[i]; + var value = this.map_[key]; + transposed.set(value, key); + } + + return transposed; +}; + + +/** + * @return {!Object} Object representation of the map. + */ +goog.structs.Map.prototype.toObject = function() { + this.cleanupKeysArray_(); + var obj = {}; + for (var i = 0; i < this.keys_.length; i++) { + var key = this.keys_[i]; + obj[key] = this.map_[key]; + } + return obj; +}; + + +/** + * Returns an iterator that iterates over the keys in the map. Removal of keys + * while iterating might have undesired side effects. + * @return {!goog.iter.Iterator} An iterator over the keys in the map. + */ +goog.structs.Map.prototype.getKeyIterator = function() { + return this.__iterator__(true); +}; + + +/** + * Returns an iterator that iterates over the values in the map. Removal of + * keys while iterating might have undesired side effects. + * @return {!goog.iter.Iterator} An iterator over the values in the map. + */ +goog.structs.Map.prototype.getValueIterator = function() { + return this.__iterator__(false); +}; + + +/** + * Returns an iterator that iterates over the values or the keys in the map. + * This throws an exception if the map was mutated since the iterator was + * created. + * @param {boolean=} opt_keys True to iterate over the keys. False to iterate + * over the values. The default value is false. + * @return {!goog.iter.Iterator} An iterator over the values or keys in the map. + */ +goog.structs.Map.prototype.__iterator__ = function(opt_keys) { + // Clean up keys to minimize the risk of iterating over dead keys. + this.cleanupKeysArray_(); + + var i = 0; + var keys = this.keys_; + var map = this.map_; + var version = this.version_; + var selfObj = this; + + var newIter = new goog.iter.Iterator; + newIter.next = function() { + while (true) { + if (version != selfObj.version_) { + throw Error('The map has changed since the iterator was created'); + } + if (i >= keys.length) { + throw goog.iter.StopIteration; + } + var key = keys[i++]; + return opt_keys ? key : map[key]; + } + }; + return newIter; +}; + + +/** + * Safe way to test for hasOwnProperty. It even allows testing for + * 'hasOwnProperty'. + * @param {Object} obj The object to test for presence of the given key. + * @param {*} key The key to check for. + * @return {boolean} Whether the object has the key. + * @private + */ +goog.structs.Map.hasKey_ = function(obj, key) { + return Object.prototype.hasOwnProperty.call(obj, key); +}; diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/map_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/map_test.html.svn-base new file mode 100644 index 0000000..a526a59 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/map_test.html.svn-base @@ -0,0 +1,430 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright 2006 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> +<head> +<meta http-equiv="X-UA-Compatible" content="IE=edge"> +<title>Closure Unit Tests - goog.structs.Map</title> +<script src="../base.js"></script> +<script> + goog.require('goog.iter'); + goog.require('goog.structs'); + goog.require('goog.structs.Map'); + goog.require('goog.testing.jsunit'); +</script> +</head> +<body> +<script> + +function stringifyMap(m) { + var keys = goog.structs.getKeys(m); + var s = ''; + for (var i = 0; i < keys.length; i++) { + s += keys[i] + m[keys[i]]; + } + return s; +} + +function getMap() { + var m = new goog.structs.Map; + m.set('a', 0); + m.set('b', 1); + m.set('c', 2); + m.set('d', 3); + return m; +} + +function testGetCount() { + var m = getMap(); + assertEquals('count, should be 4', m.getCount(), 4); + m.remove('d'); + assertEquals('count, should be 3', m.getCount(), 3); +} + +function testKeys() { + var m = getMap(); + assertEquals('getKeys, The keys should be a,b,c', m.getKeys().join(','), + 'a,b,c,d'); +} + +function testValues() { + var m = getMap(); + assertEquals('getValues, The values should be 0,1,2', + m.getValues().join(','), '0,1,2,3'); +} + +function testContainsKey() { + var m = getMap(); + assertTrue("containsKey, Should contain the 'a' key", m.containsKey('a')); + assertFalse("containsKey, Should not contain the 'e' key", + m.containsKey('e')); +} + +function testClear() { + var m = getMap(); + m.clear(); + assertTrue('cleared so it should be empty', m.isEmpty()); + assertTrue("cleared so it should not contain 'a' key", !m.containsKey('a')); +} + +function testAddAll() { + var m = new goog.structs.Map; + m.addAll({a:0,b:1,c:2,d:3}); + assertTrue('addAll so it should not be empty', !m.isEmpty()); + assertTrue("addAll so it should contain 'c' key", m.containsKey('c')); + + var m2 = new goog.structs.Map; + m2.addAll(m); + assertTrue('addAll so it should not be empty', !m2.isEmpty()); + assertTrue("addAll so it should contain 'c' key", m2.containsKey('c')); +} + +function testConstructor() { + var m = getMap(); + var m2 = new goog.structs.Map(m); + assertTrue('constr with Map so it should not be empty', !m2.isEmpty()); + assertTrue("constr with Map so it should contain 'c' key", + m2.containsKey('c')); +} + + +function testConstructorWithVarArgs() { + var m = new goog.structs.Map('a', 1); + assertTrue('constr with var_args so it should not be empty', !m.isEmpty()); + assertEquals('constr with var_args', 1, m.get('a')); + + m = new goog.structs.Map('a', 1, 'b', 2); + assertTrue('constr with var_args so it should not be empty', !m.isEmpty()); + assertEquals('constr with var_args', 1, m.get('a')); + assertEquals('constr with var_args', 2, m.get('b')); + + assertThrows('Odd number of arguments is not allowed', function() { + var m = new goog.structs.Map('a', 1, 'b'); + }); +} + +function testClone() { + var m = getMap(); + var m2 = m.clone(); + assertTrue('clone so it should not be empty', !m2.isEmpty()); + assertTrue("clone so it should contain 'c' key", m2.containsKey('c')); +} + + +function testRemove() { + var m = new goog.structs.Map(); + for (var i = 0; i < 1000; i++) { + m.set(i, 'foo'); + } + + for (var i = 0; i < 1000; i++) { + assertTrue(m.keys_.length <= 2 * m.getCount()); + m.remove(i); + } + assertTrue(m.isEmpty()); + assertEquals('', m.getKeys().join('')); +} + + +function testForEach() { + var m = getMap(); + var s = ''; + goog.structs.forEach(m, function(val, key, m2) { + assertNotUndefined(key); + assertEquals(m, m2); + s += key + val; + }); + assertEquals(s, 'a0b1c2d3'); +} + +function testFilter() { + var m = getMap(); + + var m2 = goog.structs.filter(m, function (val, key, m3) { + assertNotUndefined(key); + assertEquals(m, m3); + return val > 1; + }); + assertEquals(stringifyMap(m2), 'c2d3'); +} + + +function testMap() { + var m = getMap(); + var m2 = goog.structs.map(m, function (val, key, m3) { + assertNotUndefined(key); + assertEquals(m, m3); + return val * val; + }); + assertEquals(stringifyMap(m2), 'a0b1c4d9'); +} + +function testSome() { + var m = getMap(); + var b = goog.structs.some(m, function (val, key, m2) { + assertNotUndefined(key); + assertEquals(m, m2); + return val > 1; + }); + assertTrue(b); + var b = goog.structs.some(m, function (val, key, m2) { + assertNotUndefined(key); + assertEquals(m, m2); + return val > 100; + }); + assertFalse(b); +} + +function testEvery() { + var m = getMap(); + var b = goog.structs.every(m, function (val, key, m2) { + assertNotUndefined(key); + assertEquals(m, m2); + return val >= 0; + }); + assertTrue(b); + b = goog.structs.every(m, function (val, key, m2) { + assertNotUndefined(key); + assertEquals(m, m2); + return val > 1; + }); + assertFalse(b); +} + +function testContainsValue() { + var m = getMap(); + assertTrue(m.containsValue(3)); + assertFalse(m.containsValue(4)); +} + +function testObjectProperties() { + var m = new goog.structs.Map; + + assertEquals(m.get('toString'), undefined); + assertEquals(m.get('valueOf'), undefined); + assertEquals(m.get('eval'), undefined); + assertEquals(m.get('toSource'), undefined); + assertEquals(m.get('prototype'), undefined); + assertEquals(m.get(':foo'), undefined); + + m.set('toString', 'once'); + m.set('valueOf', 'upon'); + m.set('eval', 'a'); + m.set('toSource', 'midnight'); + m.set('prototype', 'dreary'); + m.set('hasOwnProperty', 'dark'); + m.set(':foo', 'happy'); + + assertEquals(m.get('toString'), 'once'); + assertEquals(m.get('valueOf'), 'upon'); + assertEquals(m.get('eval'), 'a'); + assertEquals(m.get('toSource'), 'midnight'); + assertEquals(m.get('prototype'), 'dreary'); + assertEquals(m.get('hasOwnProperty'), 'dark'); + assertEquals(m.get(':foo'), 'happy'); + + var keys = m.getKeys().join(','); + assertEquals(keys, + 'toString,valueOf,eval,toSource,prototype,hasOwnProperty,:foo'); + + var values = m.getValues().join(','); + assertEquals(values, 'once,upon,a,midnight,dreary,dark,happy'); +} + +function testDuplicateKeys() { + var m = new goog.structs.Map; + + m.set('a', 1); + m.set('b', 2); + m.set('c', 3); + m.set('d', 4); + m.set('e', 5); + m.set('f', 6); + assertEquals(6, m.getKeys().length); + m.set('foo', 1); + assertEquals(7, m.getKeys().length); + m.remove('foo'); + assertEquals(6, m.getKeys().length); + m.set('foo', 2); + assertEquals(7, m.getKeys().length); + m.remove('foo'); + m.set('foo', 3); + m.remove('foo'); + m.set('foo', 4); + assertEquals(7, m.getKeys().length); +} + +function testGetKeyIterator() { + var m = new goog.structs.Map; + m.set('a', 1); + m.set('b', 2); + m.set('c', 3); + m.set('d', 4); + m.set('e', 5); + + var iter = m.getKeyIterator(); + assertEquals('Should contain the keys', 'abcde', goog.iter.join(iter, '')); + + m.remove('b'); + m.remove('d'); + iter = m.getKeyIterator(); + assertEquals('Should not contain the removed keys', + 'ace', goog.iter.join(iter, '')); +} + +function testGetValueIterator() { + var m = new goog.structs.Map; + m.set('a', 1); + m.set('b', 2); + m.set('c', 3); + m.set('d', 4); + m.set('e', 5); + + var iter = m.getValueIterator(); + assertEquals('Should contain the values', '12345', goog.iter.join(iter, '')); + + m.remove('b'); + m.remove('d'); + iter = m.getValueIterator(); + assertEquals('Should not contain the removed keys', + '135', goog.iter.join(iter, '')); +} + +function testDefaultIterator() { + // The default iterator should behave like the value iterator + + var m = new goog.structs.Map; + m.set('a', 1); + m.set('b', 2); + m.set('c', 3); + m.set('d', 4); + m.set('e', 5); + + assertEquals('Should contain the values', '12345', goog.iter.join(m, '')); + + m.remove('b'); + m.remove('d'); + assertEquals('Should not contain the removed keys', + '135', goog.iter.join(m, '')); +} + +function testMutatedIterator() { + var message = 'The map has changed since the iterator was created'; + + var m = new goog.structs.Map; + m.set('a', 1); + m.set('b', 2); + m.set('c', 3); + m.set('d', 4); + + var iter = m.getValueIterator(); + m.set('e', 5); + var ex = assertThrows('Expected an exception since the map has changed', + function() { + iter.next(); + }); + assertEquals(message, ex.message); + + m = new goog.structs.Map; + m.set('a', 1); + m.set('b', 2); + m.set('c', 3); + m.set('d', 4); + + iter = m.getValueIterator(); + m.remove('d'); + var ex = assertThrows('Expected an exception since the map has changed', + function() { + iter.next(); + }); + assertEquals(message, ex.message); + + m = new goog.structs.Map; + m.set('a', 1); + m.set('b', 2); + m.set('c', 3); + m.set('d', 4); + + iter = m.getValueIterator(); + m.set('d', 5); + iter.next(); + // Changing an existing value is OK. + iter.next(); +}; + +function testTranspose() { + var m = new goog.structs.Map; + m.set('a', 1); + m.set('b', 2); + m.set('c', 3); + m.set('d', 4); + m.set('e', 5); + + var transposed = m.transpose(); + assertEquals('Should contain the keys', 'abcde', + goog.iter.join(transposed, '')); +} + +function testToObject() { + Object.prototype.b = 0; + try { + var map = new goog.structs.Map(); + map.set('a', 0); + var obj = map.toObject(); + assertTrue('object representation has key "a"', obj.hasOwnProperty('a')); + assertFalse('object representation does not have key "b"', + obj.hasOwnProperty('b')); + assertEquals('value for key "a"', 0, obj['a']); + } finally { + delete Object.prototype.b; + } +} + +function testEqualsWithSameObject() { + var map1 = getMap(); + assertTrue('maps are the same object', map1.equals(map1)); +} + +function testEqualsWithDifferentSizeMaps() { + var map1 = getMap(); + var map2 = new goog.structs.Map(); + + assertFalse('maps are different sizes', map1.equals(map2)); +} + +function testEqualsWithDefaultEqualityFn() { + var map1 = new goog.structs.Map(); + var map2 = new goog.structs.Map(); + + assertTrue('maps are both empty', map1.equals(map2)); + + map1 = getMap(); + map2 = getMap(); + assertTrue('maps are the same', map1.equals(map2)); + + map2.set('d', '3'); + assertFalse('maps have 3 and \'3\'', map1.equals(map2)); +} + +function testEqualsWithCustomEqualityFn() { + var map1 = new goog.structs.Map(); + var map2 = new goog.structs.Map(); + + map1.set('a', 0); + map1.set('b', 1); + + map2.set('a', '0'); + map2.set('b', '1'); + + var equalsFn = function(a, b) { return a == b }; + + assertTrue('maps are equal with ==', map1.equals(map2, equalsFn)); +} + +</script> +</body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/node.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/node.js.svn-base new file mode 100644 index 0000000..bc6a9fb --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/node.js.svn-base @@ -0,0 +1,74 @@ +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Generic immutable node object to be used in collections. + * + */ + + +goog.provide('goog.structs.Node'); + + + +/** + * A generic immutable node. This can be used in various collections that + * require a node object for its item (such as a heap). + * @param {*} key Key. + * @param {*} value Vaue. + * @constructor + */ +goog.structs.Node = function(key, value) { + /** + * The key. + * @type {*} + * @private + */ + this.key_ = key; + + /** + * The value. + * @type {*} + * @private + */ + this.value_ = value; +}; + + +/** + * Gets the key. + * @return {*} The key. + */ +goog.structs.Node.prototype.getKey = function() { + return this.key_; +}; + + +/** + * Gets the value. + * @return {*} The value. + */ +goog.structs.Node.prototype.getValue = function() { + return this.value_; +}; + + +/** + * Clones a node and returns a new node. + * @return {goog.structs.Node} A new goog.structs.Node with the same key value + * pair. + */ +goog.structs.Node.prototype.clone = function() { + return new goog.structs.Node(this.key_, this.value_); +}; diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/pool.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/pool.js.svn-base new file mode 100644 index 0000000..ba69dd0 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/pool.js.svn-base @@ -0,0 +1,381 @@ +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Datastructure: Pool. + * + * + * A generic class for handling pools of objects. + * When an object is released, it is attempted to be reused. + */ + + +goog.provide('goog.structs.Pool'); + +goog.require('goog.Disposable'); +goog.require('goog.structs.Queue'); +goog.require('goog.structs.Set'); + + + +/** + * A generic pool class. If min is greater than max, an error is thrown. + * @param {number=} opt_minCount Min. number of objects (Default: 1). + * @param {number=} opt_maxCount Max. number of objects (Default: 10). + * @constructor + * @extends {goog.Disposable} + */ +goog.structs.Pool = function(opt_minCount, opt_maxCount) { + goog.Disposable.call(this); + + /** + * Minimum number of objects allowed + * @type {number} + * @private + */ + this.minCount_ = opt_minCount || 0; + + /** + * Maximum number of objects allowed + * @type {number} + * @private + */ + this.maxCount_ = opt_maxCount || 10; + + // Make sure that the max and min constraints are valid. + if (this.minCount_ > this.maxCount_) { + throw Error(goog.structs.Pool.ERROR_MIN_MAX_); + } + + /** + * Set used to store objects that are currently in the pool and available + * to be used. + * @type {goog.structs.Queue} + * @private + */ + this.freeQueue_ = new goog.structs.Queue(); + + /** + * Set used to store objects that are currently in the pool and in use. + * @type {goog.structs.Set} + * @private + */ + this.inUseSet_ = new goog.structs.Set(); + + /** + * The minimum delay between objects being made available, in milliseconds. If + * this is 0, no minimum delay is enforced. + * @type {number} + * @protected + */ + this.delay = 0; + + /** + * The time of the last object being made available, in milliseconds since the + * epoch (i.e., the result of Date#toTime). If this is null, no access has + * occurred yet. + * @type {number?} + * @protected + */ + this.lastAccess = null; + + // Make sure that the minCount constraint is satisfied. + this.adjustForMinMax(); + + + // TODO(user): Remove once JSCompiler's undefined properties warnings + // don't error for guarded properties. + var magicProps = {canBeReused: 0}; +}; +goog.inherits(goog.structs.Pool, goog.Disposable); + + +/** + * Error to throw when the max/min constraint is attempted to be invalidated. + * I.e., when it is attempted for maxCount to be less than minCount. + * @type {string} + * @private + */ +goog.structs.Pool.ERROR_MIN_MAX_ = + '[goog.structs.Pool] Min can not be greater than max'; + + +/** + * Error to throw when the Pool is attempted to be disposed and it is asked to + * make sure that there are no objects that are in use (i.e., haven't been + * released). + * @type {string} + * @private + */ +goog.structs.Pool.ERROR_DISPOSE_UNRELEASED_OBJS_ = + '[goog.structs.Pool] Objects not released'; + + +/** + * Sets the minimum count of the pool. + * If min is greater than the max count of the pool, an error is thrown. + * @param {number} min The minimum count of the pool. + */ +goog.structs.Pool.prototype.setMinimumCount = function(min) { + // Check count constraints. + if (min > this.maxCount_) { + throw Error(goog.structs.Pool.ERROR_MIN_MAX_); + } + this.minCount_ = min; + + // Adjust the objects in the pool as needed. + this.adjustForMinMax(); +}; + + +/** + * Sets the maximum count of the pool. + * If max is less than the max count of the pool, an error is thrown. + * @param {number} max The maximium count of the pool. + */ +goog.structs.Pool.prototype.setMaximumCount = function(max) { + // Check count constraints. + if (max < this.minCount_) { + throw Error(goog.structs.Pool.ERROR_MIN_MAX_); + } + this.maxCount_ = max; + + // Adjust the objects in the pool as needed. + this.adjustForMinMax(); +}; + + +/** + * Sets the minimum delay between objects being returned by getObject, in + * milliseconds. This defaults to zero, meaning that no minimum delay is + * enforced and objects may be used as soon as they're available. + * @param {number} delay The minimum delay, in milliseconds. + */ +goog.structs.Pool.prototype.setDelay = function(delay) { + this.delay = delay; +}; + + +/** + * @return {Object|undefined} A new object from the pool if there is one + * available, otherwise undefined. + */ +goog.structs.Pool.prototype.getObject = function() { + var time = goog.now(); + if (goog.isDefAndNotNull(this.lastAccess) && + time - this.lastAccess < this.delay) { + return undefined; + } + + var obj = this.removeFreeObject_(); + if (obj) { + this.lastAccess = time; + this.inUseSet_.add(obj); + } + + return obj; +}; + + +/** + * Returns an object to the pool of available objects so that it can be reused. + * @param {Object} obj The object to return to the pool of free objects. + * @return {boolean} Whether the object was found in the Pool's set of in-use + * objects (in other words, whether any action was taken). + */ +goog.structs.Pool.prototype.releaseObject = function(obj) { + if (this.inUseSet_.remove(obj)) { + this.addFreeObject(obj); + return true; + } + return false; +}; + + +/** + * Removes a free object from the collection of objects that are free so that it + * can be used. + * + * NOTE: This method does not mark the returned object as in use. + * + * @return {Object|undefined} The object removed from the free collection, if + * there is one available. Otherwise, undefined. + * @private + */ +goog.structs.Pool.prototype.removeFreeObject_ = function() { + var obj; + while (this.getFreeCount() > 0) { + obj = /** @type {Object} */(this.freeQueue_.dequeue()); + + if (!this.objectCanBeReused(obj)) { + this.adjustForMinMax(); + } else { + break; + } + } + + if (!obj && this.getCount() < this.maxCount_) { + obj = this.createObject(); + } + + return obj; +}; + + +/** + * Adds an object to the collection of objects that are free. If the object can + * not be added, then it is disposed. + * + * @param {Object} obj The object to add to collection of free objects. + */ +goog.structs.Pool.prototype.addFreeObject = function(obj) { + this.inUseSet_.remove(obj); + if (this.objectCanBeReused(obj) && this.getCount() < this.maxCount_) { + this.freeQueue_.enqueue(obj); + } else { + this.disposeObject(obj); + } +}; + + +/** + * Adjusts the objects held in the pool to be within the min/max constraints. + * + * NOTE: It is possible that the number of objects in the pool will still be + * greater than the maximum count of objects allowed. This will be the case + * if no more free objects can be disposed of to get below the minimum count + * (i.e., all objects are in use). + */ +goog.structs.Pool.prototype.adjustForMinMax = function() { + var freeQueue = this.freeQueue_; + + // Make sure the at least the minimum number of objects are created. + while (this.getCount() < this.minCount_) { + freeQueue.enqueue(this.createObject()); + } + + // Make sure no more than the maximum number of objects are created. + while (this.getCount() > this.maxCount_ && this.getFreeCount() > 0) { + this.disposeObject(/** @type {Object} */(freeQueue.dequeue())); + } +}; + + +/** + * Should be overriden by sub-classes to return an instance of the object type + * that is expected in the pool. + * @return {Object} The created object. + */ +goog.structs.Pool.prototype.createObject = function() { + return {}; +}; + + +/** + * Should be overriden to dispose of an object. Default implementation is to + * remove all its members, which should render it useless. Calls the object's + * {@code dispose()} method, if available. + * @param {Object} obj The object to dispose. + */ +goog.structs.Pool.prototype.disposeObject = function(obj) { + if (typeof obj.dispose == 'function') { + obj.dispose(); + } else { + for (var i in obj) { + obj[i] = null; + } + } +}; + + +/** + * Should be overriden to determine whether an object has become unusable and + * should not be returned by getObject(). Calls the object's + * {@code canBeReused()} method, if available. + * @param {Object} obj The object to test. + * @return {boolean} Whether the object can be reused. + */ +goog.structs.Pool.prototype.objectCanBeReused = function(obj) { + if (typeof obj.canBeReused == 'function') { + return obj.canBeReused(); + } + return true; +}; + + +/** + * Returns true if the given object is in the pool. + * @param {Object} obj The object to check the pool for. + * @return {boolean} Whether the pool contains the object. + */ +goog.structs.Pool.prototype.contains = function(obj) { + return this.freeQueue_.contains(obj) || this.inUseSet_.contains(obj); +}; + + +/** + * Returns the number of objects currently in the pool. + * @return {number} Number of objects currently in the pool. + */ +goog.structs.Pool.prototype.getCount = function() { + return this.freeQueue_.getCount() + this.inUseSet_.getCount(); +}; + + +/** + * Returns the number of objects currently in use in the pool. + * @return {number} Number of objects currently in use in the pool. + */ +goog.structs.Pool.prototype.getInUseCount = function() { + return this.inUseSet_.getCount(); +}; + + +/** + * Returns the number of objects currently free in the pool. + * @return {number} Number of objects currently free in the pool. + */ +goog.structs.Pool.prototype.getFreeCount = function() { + return this.freeQueue_.getCount(); +}; + + +/** + * Determines if the pool contains no objects. + * @return {boolean} Whether the pool contains no objects. + */ +goog.structs.Pool.prototype.isEmpty = function() { + return this.freeQueue_.isEmpty() && this.inUseSet_.isEmpty(); +}; + + +/** + * Disposes of the pool and all objects currently held in the pool. + * @override + * @protected + */ +goog.structs.Pool.prototype.disposeInternal = function() { + goog.structs.Pool.superClass_.disposeInternal.call(this); + if (this.getInUseCount() > 0) { + throw Error(goog.structs.Pool.ERROR_DISPOSE_UNRELEASED_OBJS_); + } + delete this.inUseSet_; + + // Call disposeObject on each object held by the pool. + var freeQueue = this.freeQueue_; + while (!freeQueue.isEmpty()) { + this.disposeObject(/** @type {Object} */ (freeQueue.dequeue())); + } + delete this.freeQueue_; +}; diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/pool_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/pool_test.html.svn-base new file mode 100644 index 0000000..461e70f --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/pool_test.html.svn-base @@ -0,0 +1,291 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright 2006 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> +<head> +<meta http-equiv="X-UA-Compatible" content="IE=edge"> +<title>Closure Unit Tests - goog.structs.Pool</title> +<script src="../base.js"></script> +<script> + goog.require('goog.structs'); + goog.require('goog.structs.Pool'); + goog.require('goog.testing.MockClock'); + goog.require('goog.testing.jsunit'); +</script> +</head> +<body> +<script> + +// Implementation of the Pool class with isObjectDead() always returning TRUE, +// so that the the Pool will not reuse any objects. +function NoObjectReusePool(opt_min, opt_max) { + goog.structs.Pool.call(this, opt_min, opt_max); +}; +goog.inherits(NoObjectReusePool, goog.structs.Pool); + +NoObjectReusePool.prototype.objectCanBeReused = function(obj) { + return false; +}; + + +function testExceedMax1() { + var p = new goog.structs.Pool(0, 3); + var obj1 = p.getObject(); + var obj2 = p.getObject(); + var obj3 = p.getObject(); + var obj4 = p.getObject(); + var obj5 = p.getObject(); + + assertNotUndefined(obj1); + assertNotUndefined(obj2); + assertNotUndefined(obj3); + assertUndefined(obj4); + assertUndefined(obj5); +} + + +function testExceedMax2() { + var p = new goog.structs.Pool(0, 1); + var obj1 = p.getObject(); + var obj2 = p.getObject(); + var obj3 = p.getObject(); + var obj4 = p.getObject(); + var obj5 = p.getObject(); + + assertNotUndefined(obj1); + assertUndefined(obj2); + assertUndefined(obj3); + assertUndefined(obj4); + assertUndefined(obj5); +} + + +function testExceedMax3() { + var p = new goog.structs.Pool(); // default: 10 + var objs = []; + + for (var i = 0; i < 12; i++) { + objs[i] = p.getObject(); + } + + for (var i = 0; i < 10; i++) { + assertNotNull('First 10 should be not null', objs[i]); + } + + assertUndefined(objs[10]); + assertUndefined(objs[11]); +} + + +function testReleaseAndGet1() { + var p = new goog.structs.Pool(0, 10); + var o = p.getObject(); + assertEquals(1, p.getCount()); + assertEquals(1, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + assertTrue('Result should be true', p.releaseObject(o)); + assertEquals(1, p.getCount()); + assertEquals(0, p.getInUseCount()); + assertEquals(1, p.getFreeCount()); +} + + +function testReleaseAndGet2() { + var p = new NoObjectReusePool(0, 10); + var o = p.getObject(); + assertEquals(1, p.getCount()); + assertEquals(1, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + assertTrue('Result should be true', p.releaseObject(o)); + assertEquals(0, p.getCount()); + assertEquals(0, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); +} + + +function testReleaseAndGet3() { + var p = new goog.structs.Pool(0, 10); + var o1 = p.getObject(); + var o2 = p.getObject(); + var o3 = p.getObject(); + var o4 = {}; + assertEquals(3, p.getCount()); + assertEquals(3, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + assertTrue('Result should be true', p.releaseObject(o1)); + assertTrue('Result should be true', p.releaseObject(o2)); + assertFalse('Result should be false', p.releaseObject(o4)); + assertEquals(3, p.getCount()); + assertEquals(1, p.getInUseCount()); + assertEquals(2, p.getFreeCount()); +} + + +function testReleaseAndGet4() { + var p = new NoObjectReusePool(0, 10); + var o1 = p.getObject(); + var o2 = p.getObject(); + var o3 = p.getObject(); + var o4 = {}; + assertEquals(3, p.getCount()); + assertEquals(3, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + assertTrue('Result should be true', p.releaseObject(o1)); + assertTrue('Result should be true', p.releaseObject(o2)); + assertFalse('Result should be false', p.releaseObject(o4)); + assertEquals(1, p.getCount()); + assertEquals(1, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); +} + + +function testIsInPool1() { + var p = new goog.structs.Pool(); + var o1 = p.getObject(); + var o2 = p.getObject(); + var o3 = p.getObject(); + var o4 = {}; + var o5 = {}; + var o6 = o1; + + assertTrue(p.contains(o1)); + assertTrue(p.contains(o2)); + assertTrue(p.contains(o3)); + assertFalse(p.contains(o4)); + assertFalse(p.contains(o5)); + assertTrue(p.contains(o6)); +} + + +function testSetMin1() { + var p = new goog.structs.Pool(0, 10); + + assertEquals(0, p.getCount()); + assertEquals(0, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + + p.setMinimumCount(10); + + assertEquals(10, p.getCount()); + assertEquals(0, p.getInUseCount()); + assertEquals(10, p.getFreeCount()); +} + + +function testSetMin2() { + var p = new goog.structs.Pool(0, 10); + + assertEquals(0, p.getCount()); + assertEquals(0, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + + var o1 = p.getObject(); + + assertEquals(1, p.getCount()); + assertEquals(1, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + + p.setMinimumCount(10); + + assertEquals(10, p.getCount()); + assertEquals(1, p.getInUseCount()); + assertEquals(9, p.getFreeCount()); +} + + +function testSetMax1() { + var p = new goog.structs.Pool(0, 10); + + assertEquals(0, p.getCount()); + assertEquals(0, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + + var o1 = p.getObject(); + var o2 = p.getObject(); + var o3 = p.getObject(); + var o4 = p.getObject(); + var o5 = p.getObject(); + + assertEquals(5, p.getCount()); + assertEquals(5, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + + assertTrue('Result should be true', p.releaseObject(o5)); + + assertEquals(5, p.getCount()); + assertEquals(4, p.getInUseCount()); + assertEquals(1, p.getFreeCount()); + + p.setMaximumCount(4); + + assertEquals(4, p.getCount()); + assertEquals(4, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); +} + + +function testInvalidMinMax1() { + var p = new goog.structs.Pool(0, 10); + + assertEquals(0, p.getCount()); + assertEquals(0, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + + assertThrows(function() { + p.setMinimumCount(11); + }); +} + + +function testInvalidMinMax2() { + var p = new goog.structs.Pool(5, 10); + + assertEquals(5, p.getCount()); + assertEquals(0, p.getInUseCount()); + assertEquals(5, p.getFreeCount()); + + assertThrows(function() { + p.setMaximumCount(4); + }); +} + + +function testInvalidMinMax3() { + assertThrows(function() { + new goog.structs.Pool(10, 1); + }); +} + + +function testRateLimiting() { + var clock = new goog.testing.MockClock(); + clock.install(); + + var p = new goog.structs.Pool(0, 3); + p.setDelay(100); + + assertNotUndefined(p.getObject()); + assertUndefined(p.getObject()); + + clock.tick(100); + assertNotUndefined(p.getObject()); + assertUndefined(p.getObject()); + + clock.tick(100); + assertNotUndefined(p.getObject()); + assertUndefined(p.getObject()); + + clock.tick(100); + assertUndefined(p.getObject()); + + goog.dispose(clock); +} + + +</script> +</body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/prioritypool.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/prioritypool.js.svn-base new file mode 100644 index 0000000..ce2af7f --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/prioritypool.js.svn-base @@ -0,0 +1,179 @@ +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Datastructure: Priority Pool. + * + * + * An extending of Pool that handles queueing and prioritization. + */ + + +goog.provide('goog.structs.PriorityPool'); + +goog.require('goog.structs.Pool'); +goog.require('goog.structs.PriorityQueue'); + + + +/** + * A generic pool class. If max is greater than min, an error is thrown. + * @param {number=} opt_minCount Min. number of objects (Default: 1). + * @param {number=} opt_maxCount Max. number of objects (Default: 10). + * @constructor + * @extends {goog.structs.Pool} + */ +goog.structs.PriorityPool = function(opt_minCount, opt_maxCount) { + /** + * Queue of requests for pool objects. + * @type {goog.structs.PriorityQueue} + * @private + */ + this.requestQueue_ = new goog.structs.PriorityQueue(); + + // Must break convention of putting the super-class's constructor first. This + // is because the super-class constructor calls adjustForMinMax, which this + // class overrides. In this class's implementation, it assumes that there + // is a requestQueue_, and will error if not present. + goog.structs.Pool.call(this, opt_minCount, opt_maxCount); +}; +goog.inherits(goog.structs.PriorityPool, goog.structs.Pool); + + +/** + * The key for the most recent timeout created. + * @type {number|undefined} + * @private + */ +goog.structs.PriorityPool.prototype.delayTimeout_; + + +/** + * Default priority for pool objects requests. + * @type {number} + * @private + */ +goog.structs.PriorityPool.DEFAULT_PRIORITY_ = 100; + + +/** @override */ +goog.structs.PriorityPool.prototype.setDelay = function(delay) { + goog.base(this, 'setDelay', delay); + + // If the pool hasn't been accessed yet, no need to do anything. + if (!goog.isDefAndNotNull(this.lastAccess)) { + return; + } + + goog.global.clearTimeout(this.delayTimeout_); + this.delayTimeout_ = goog.global.setTimeout( + goog.bind(this.handleQueueRequests_, this), + this.delay + this.lastAccess - goog.now()); + + // Handle all requests. + this.handleQueueRequests_(); +}; + + +/** + * Get a new object from the the pool, if there is one available, otherwise + * return undefined. + * @param {Function=} opt_callback The function to callback when an object is + * available. This could be immediately. If this is not present, then an + * object is immediately returned if available, or undefined if not. + * @param {*=} opt_priority The priority of the request. + * @return {Object|undefined} The new object from the pool if there is one + * available and a callback is not given. Otherwise, undefined. + */ +goog.structs.PriorityPool.prototype.getObject = function(opt_callback, + opt_priority) { + if (!opt_callback) { + var result = goog.base(this, 'getObject'); + if (result && this.delay) { + this.delayTimeout_ = goog.global.setTimeout( + goog.bind(this.handleQueueRequests_, this), + this.delay); + } + return result; + } + + var priority = opt_priority || goog.structs.PriorityPool.DEFAULT_PRIORITY_; + this.requestQueue_.enqueue(priority, opt_callback); + + // Handle all requests. + this.handleQueueRequests_(); + + return undefined; +}; + + +/** + * Handles the request queue. Tries to fires off as many queued requests as + * possible. + * @private + */ +goog.structs.PriorityPool.prototype.handleQueueRequests_ = function() { + var requestQueue = this.requestQueue_; + while (requestQueue.getCount() > 0) { + var obj = this.getObject(); + + if (!obj) { + return; + } else { + var requestCallback = requestQueue.dequeue(); + requestCallback.apply(this, [obj]); + } + } +}; + + +/** + * Adds an object to the collection of objects that are free. If the object can + * not be added, then it is disposed. + * + * NOTE: This method does not remove the object from the in use collection. + * + * @param {Object} obj The object to add to the collection of free objects. + */ +goog.structs.PriorityPool.prototype.addFreeObject = function(obj) { + goog.structs.PriorityPool.superClass_.addFreeObject.call(this, obj); + + // Handle all requests. + this.handleQueueRequests_(); +}; + + +/** + * Adjusts the objects held in the pool to be within the min/max constraints. + * + * NOTE: It is possible that the number of objects in the pool will still be + * greater than the maximum count of objects allowed. This will be the case + * if no more free objects can be disposed of to get below the minimum count + * (i.e., all objects are in use). + */ +goog.structs.PriorityPool.prototype.adjustForMinMax = function() { + goog.structs.PriorityPool.superClass_.adjustForMinMax.call(this); + + // Handle all requests. + this.handleQueueRequests_(); +}; + + +/** @override */ +goog.structs.PriorityPool.prototype.disposeInternal = function() { + goog.structs.PriorityPool.superClass_.disposeInternal.call(this); + goog.global.clearTimeout(this.delayTimeout_); + this.requestQueue_.clear(); + this.requestQueue_ = null; +}; diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/prioritypool_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/prioritypool_test.html.svn-base new file mode 100644 index 0000000..7a0b367 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/prioritypool_test.html.svn-base @@ -0,0 +1,562 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright 2006 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> +<head> +<meta http-equiv="X-UA-Compatible" content="IE=edge"> +<title>Closure Unit Tests - goog.structs.PriorityPool</title> +<script src="../base.js"></script> +<script> + goog.require('goog.structs.PriorityPool'); + goog.require('goog.testing.MockClock'); + goog.require('goog.testing.jsunit'); + goog.require('goog.structs'); +</script> +</head> +<body> +<script> + +// Implementation of the Pool class with isObjectDead() always returning TRUE, +// so that the the Pool will not reuse any objects. +function NoObjectReusePriorityPool(opt_min, opt_max) { + goog.structs.PriorityPool.call(this, opt_min, opt_max); +}; +goog.inherits(NoObjectReusePriorityPool, goog.structs.PriorityPool); + +NoObjectReusePriorityPool.prototype.objectCanBeReused = function(obj) { + return false; +}; + + +function testExceedMax1() { + var p = new goog.structs.PriorityPool(0, 3); + + var getCount1 = 0; + var callback1 = function(obj) { + assertNotNull(obj); + getCount1++; + }; + + var getCount2 = 0; + var callback2 = function(obj) { + getCount2++; + }; + + p.getObject(callback1); + p.getObject(callback1); + p.getObject(callback1); + p.getObject(callback2); + p.getObject(callback2); + p.getObject(callback2); + + assertEquals('getCount for allocated, Should be 3', getCount1, 3); + assertEquals('getCount for unallocated, Should be 0', getCount2, 0); +} + + +function testExceedMax2() { + var p = new goog.structs.PriorityPool(0, 1); + + var getCount1 = 0; + var callback1 = function(obj) { + assertNotNull(obj); + getCount1++; + }; + + var getCount2 = 0; + var callback2 = function(obj) { + getCount2++; + }; + + p.getObject(callback1); + p.getObject(callback2); + p.getObject(callback2); + p.getObject(callback2); + p.getObject(callback2); + p.getObject(callback2); + + assertEquals('getCount for allocated, Should be 1', getCount1, 1); + assertEquals('getCount for unallocated, Should be 0', getCount2, 0); +} + +function testExceedMax3() { + var p = new goog.structs.PriorityPool(0, 2); + + var obj1 = null; + var callback1 = function(obj) { + obj1 = obj; + }; + + var obj2 = null; + var callback2 = function(obj) { + obj2 = obj; + }; + + var obj3 = null; + var callback3 = function(obj) { + obj3 = obj; + }; + + p.getObject(callback1); + p.getObject(callback2); + p.getObject(callback3); + + assertNotNull(obj1); + assertNotNull(obj2); + assertNull(obj3); +} + +function testExceedMax4() { + var p = new goog.structs.PriorityPool(); // default: 10 + var objs = []; + + var getCount1 = 0; + var callback1 = function(obj) { + assertNotNull(obj); + getCount1++; + }; + + var getCount2 = 0; + var callback2 = function(obj) { + getCount2++; + }; + + for (var i = 0; i < 12; i++) { + p.getObject(i < 10 ? callback1 : callback2); + } + + assertEquals('getCount for allocated, Should be 10', getCount1, 10); + assertEquals('getCount for unallocated, Should be 0', getCount2, 0); +} + + +function testReleaseAndGet1() { + var p = new goog.structs.PriorityPool(0, 10); + + var o = null; + var callback = function(obj) { + o = obj; + }; + + p.getObject(callback); + assertEquals(1, p.getCount()); + assertEquals(1, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + assertTrue('Result should be true', p.releaseObject(o)); + assertEquals(1, p.getCount()); + assertEquals(0, p.getInUseCount()); + assertEquals(1, p.getFreeCount()); +} + + +function testReleaseAndGet2() { + var p = new NoObjectReusePriorityPool(0, 10); + + var o = null; + var callback = function(obj) { + o = obj; + }; + + p.getObject(callback); + assertEquals(1, p.getCount()); + assertEquals(1, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + assertTrue('Result should be true', p.releaseObject(o)); + assertEquals(0, p.getCount()); + assertEquals(0, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); +} + + +function testReleaseAndGet3() { + var p = new goog.structs.PriorityPool(0, 10); + var o1 = null; + var callback1 = function(obj) { + o1 = obj; + }; + + var o2 = null; + var callback2 = function(obj) { + o2 = obj; + }; + + var o3 = null; + var callback3 = function(obj) { + o3 = obj; + }; + + var o4 = {}; + + p.getObject(callback1); + p.getObject(callback2); + p.getObject(callback3); + + assertEquals(3, p.getCount()); + assertEquals(3, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + assertTrue('Result should be true', p.releaseObject(o1)); + assertTrue('Result should be true', p.releaseObject(o2)); + assertFalse('Result should be false', p.releaseObject(o4)); + assertEquals(3, p.getCount()); + assertEquals(1, p.getInUseCount()); + assertEquals(2, p.getFreeCount()); +} + + +function testReleaseAndGet4() { + var p = new NoObjectReusePriorityPool(0, 10); + + var o1 = null; + var callback1 = function(obj) { + o1 = obj; + }; + + var o2 = null; + var callback2 = function(obj) { + o2 = obj; + }; + + var o3 = null; + var callback3 = function(obj) { + o3 = obj; + }; + + var o4 = {}; + + p.getObject(callback1); + p.getObject(callback2); + p.getObject(callback3); + assertEquals(3, p.getCount()); + assertEquals(3, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + assertTrue('Result should be true', p.releaseObject(o1)); + assertTrue('Result should be true', p.releaseObject(o2)); + assertFalse('Result should be false', p.releaseObject(o4)); + assertEquals(1, p.getCount()); + assertEquals(1, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); +} + + +function testIsInPool1() { + var p = new goog.structs.PriorityPool(); + var o1 = null; + var callback1 = function(obj) { + o1 = obj; + }; + + var o2 = null; + var callback2 = function(obj) { + o2 = obj; + }; + + var o3 = null; + var callback3 = function(obj) { + o3 = obj; + }; + + var o4 = {}; + var o5 = {}; + + p.getObject(callback1); + p.getObject(callback2); + p.getObject(callback3); + var o6 = o1; + + assertTrue(p.contains(o1)); + assertTrue(p.contains(o2)); + assertTrue(p.contains(o3)); + assertFalse(p.contains(o4)); + assertFalse(p.contains(o5)); + assertTrue(p.contains(o6)); +} + + +function testSetMin1() { + var p = new goog.structs.PriorityPool(0, 10); + + assertEquals(0, p.getCount()); + assertEquals(0, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + + p.setMinimumCount(10); + + assertEquals(10, p.getCount()); + assertEquals(0, p.getInUseCount()); + assertEquals(10, p.getFreeCount()); +} + + +function testSetMin2() { + var p = new goog.structs.PriorityPool(0, 10); + + assertEquals(0, p.getCount()); + assertEquals(0, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + + var o1 = null; + var callback1 = function(obj) { + o1 = obj; + }; + p.getObject(callback1); + + assertEquals(1, p.getCount()); + assertEquals(1, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + + p.setMinimumCount(10); + + assertEquals(10, p.getCount()); + assertEquals(1, p.getInUseCount()); + assertEquals(9, p.getFreeCount()); +} + + +function testSetMax1() { + var p = new goog.structs.PriorityPool(0, 10); + + assertEquals(0, p.getCount()); + assertEquals(0, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + + var o1 = null; + var callback1 = function(obj) { + o1 = obj; + }; + + var o2 = null; + var callback2 = function(obj) { + o2 = obj; + }; + + var o3 = null; + var callback3 = function(obj) { + o3 = obj; + }; + + var o4 = null; + var callback4 = function(obj) { + o4 = obj; + }; + + var o5 = null; + var callback5 = function(obj) { + o5 = obj; + }; + + p.getObject(callback1); + p.getObject(callback2); + p.getObject(callback3); + p.getObject(callback4); + p.getObject(callback5); + + assertEquals(5, p.getCount()); + assertEquals(5, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + + assertTrue('Result should be true', p.releaseObject(o5)); + + assertEquals(5, p.getCount()); + assertEquals(4, p.getInUseCount()); + assertEquals(1, p.getFreeCount()); + + p.setMaximumCount(4); + + assertEquals(4, p.getCount()); + assertEquals(4, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); +} + + +function testInvalidMinMax1() { + var p = new goog.structs.PriorityPool(0, 10); + + assertEquals(0, p.getCount()); + assertEquals(0, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + + assertThrows(function() { + p.setMinimumCount(11); + }); +} + + +function testInvalidMinMax2() { + var p = new goog.structs.PriorityPool(5, 10); + + assertEquals(5, p.getCount()); + assertEquals(0, p.getInUseCount()); + assertEquals(5, p.getFreeCount()); + + assertThrows(function() { + p.setMaximumCount(4); + }); +} + + +function testInvalidMinMax3() { + assertThrows(function() { + new goog.structs.PriorityPool(10, 1); + }); +} + +function testQueue1() { + var p = new goog.structs.PriorityPool(0, 2); + + var o1 = null; + var callback1 = function(obj) { + o1 = obj; + }; + + var o2 = null; + var callback2 = function(obj) { + o2 = obj; + }; + + var o3 = null; + var callback3 = function(obj) { + o3 = obj; + }; + + p.getObject(callback1); + p.getObject(callback2); + p.getObject(callback3); + + assertNotNull(o1); + assertNotNull(o2); + assertNull(o3); + + p.releaseObject(o1); + assertNotNull(o3); +} + + +function testPriority1() { + var p = new goog.structs.PriorityPool(0, 2); + + var o1 = null; + var callback1 = function(obj) { + o1 = obj; + }; + + var o2 = null; + var callback2 = function(obj) { + o2 = obj; + }; + + var o3 = null; + var callback3 = function(obj) { + o3 = obj; + }; + + var o4 = null; + var callback4 = function(obj) { + o4 = obj; + }; + + p.getObject(callback1); + p.getObject(callback2); + p.getObject(callback3, 10); + p.getObject(callback4, 5); + + assertNotNull(o1); + assertNotNull(o2); + assertNull(o3); + assertNull(o4); + + p.releaseObject(o1); + assertNull(o3); + assertNotNull(o4); +} + + +function testRateLimiting() { + var clock = new goog.testing.MockClock(); + clock.install(); + + var p = new goog.structs.PriorityPool(0, 4); + p.setDelay(100); + + var getCount = 0; + var callback = function(obj) { + assertNotNull(obj); + getCount++; + }; + + p.getObject(callback); + assertEquals(1, getCount); + + p.getObject(callback); + assertEquals(1, getCount); + + clock.tick(100); + assertEquals(2, getCount); + + p.getObject(callback); + p.getObject(callback); + assertEquals(2, getCount); + + clock.tick(100); + assertEquals(3, getCount); + + clock.tick(100); + assertEquals(4, getCount); + + p.getObject(callback); + assertEquals(4, getCount); + + clock.tick(100); + assertEquals(4, getCount); + + goog.dispose(clock); +} + + +function testRateLimitingWithChangingDelay() { + var clock = new goog.testing.MockClock(); + clock.install(); + + var p = new goog.structs.PriorityPool(0, 3); + p.setDelay(100); + + var getCount = 0; + var callback = function(obj) { + assertNotNull(obj); + getCount++; + }; + + p.getObject(callback); + assertEquals(1, getCount); + + p.getObject(callback); + assertEquals(1, getCount); + + clock.tick(50); + assertEquals(1, getCount); + + p.setDelay(50); + assertEquals(2, getCount); + + p.getObject(callback); + assertEquals(2, getCount); + + clock.tick(20); + assertEquals(2, getCount); + + p.setDelay(40); + assertEquals(2, getCount); + + clock.tick(20); + assertEquals(3, getCount); + + goog.dispose(clock); +} + + +</script> +</body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/priorityqueue.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/priorityqueue.js.svn-base new file mode 100644 index 0000000..07b2b28 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/priorityqueue.js.svn-base @@ -0,0 +1,64 @@ +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Datastructure: Priority Queue. + * + * + * This file provides the implementation of a Priority Queue. Smaller priorities + * move to the front of the queue. If two values have the same priority, + * it is arbitrary which value will come to the front of the queue first. + */ + +// TODO(user): Should this rely on natural ordering via some Comparable +// interface? + + +goog.provide('goog.structs.PriorityQueue'); + +goog.require('goog.structs'); +goog.require('goog.structs.Heap'); + + + +/** + * Class for Priority Queue datastructure. + * + * @constructor + * @extends {goog.structs.Heap} + */ +goog.structs.PriorityQueue = function() { + goog.structs.Heap.call(this); +}; +goog.inherits(goog.structs.PriorityQueue, goog.structs.Heap); + + +/** + * Puts the specified value in the queue. + * @param {*} priority The priority of the value. + * @param {*} value The value. + */ +goog.structs.PriorityQueue.prototype.enqueue = function(priority, value) { + this.insert(priority, value); +}; + + +/** + * Retrieves and removes the head of this queue. + * @return {*} The element at the head of this queue. Returns + * undefined if the queue is empty. + */ +goog.structs.PriorityQueue.prototype.dequeue = function() { + return this.remove(); +}; diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/priorityqueue_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/priorityqueue_test.html.svn-base new file mode 100644 index 0000000..ceae23c --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/priorityqueue_test.html.svn-base @@ -0,0 +1,179 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright 2006 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> +<head> +<meta http-equiv="X-UA-Compatible" content="IE=edge"> +<title>Closure Unit Tests - goog.structs.PriorityQueue</title> +<script src="../base.js"></script> +<script> + goog.require('goog.structs'); + goog.require('goog.structs.PriorityQueue'); + goog.require('goog.testing.jsunit'); +</script> +</head> +<body> +<script> + +function getPriorityQueue() { + var p = new goog.structs.PriorityQueue(); + p.enqueue(0, 'a'); + p.enqueue(1, 'b'); + p.enqueue(2, 'c'); + p.enqueue(3, 'd'); + return p; +} + + +function getPriorityQueue2() { + var p = new goog.structs.PriorityQueue(); + p.insert(1, 'b'); + p.insert(3, 'd'); + p.insert(0, 'a'); + p.insert(2, 'c'); + return p; +} + + +function testGetCount1() { + var p = getPriorityQueue(); + assertEquals('count, should be 4', p.getCount(), 4); + p.dequeue(); + assertEquals('count, should be 3', p.getCount(), 3); +} + + +function testGetCount2() { + var p = getPriorityQueue(); + assertEquals('count, should be 4', p.getCount(), 4); + p.dequeue(); + assertEquals('count, should be 3', p.getCount(), 3); +} + + +function testGetCount3() { + var p = getPriorityQueue(); + p.dequeue(); + p.dequeue(); + p.dequeue(); + p.dequeue(); + assertEquals('count, should be 0', p.getCount(), 0); +} + + +function testKeys() { + var p = getPriorityQueue(); + var keys = p.getKeys(); + for (var i = 0; i < 4; i++) { + assertTrue('getKeys, key ' + i + ' found', goog.structs.contains(keys, i)); + } + assertEquals('getKeys, Should be 4 keys', goog.structs.getCount(keys), 4); +} + + +function testValues() { + var p = getPriorityQueue(); + var values = p.getValues(); + + assertTrue('getKeys, value "a" found', goog.structs.contains(values, 'a')); + assertTrue('getKeys, value "b" found', goog.structs.contains(values, 'b')); + assertTrue('getKeys, value "c" found', goog.structs.contains(values, 'c')); + assertTrue('getKeys, value "d" found', goog.structs.contains(values, 'd')); + assertEquals('getKeys, Should be 4 keys', goog.structs.getCount(values), 4); +} + + +function testClear() { + var p = getPriorityQueue(); + p.clear(); + assertTrue('cleared so it should be empty', p.isEmpty()); +} + + +function testIsEmpty() { + var p = getPriorityQueue(); + assertFalse('4 values so should not be empty', p.isEmpty()); + + p.dequeue(); + p.dequeue(); + p.dequeue(); + assertFalse('1 values so should not be empty', p.isEmpty()); + + p.dequeue(); + assertTrue('0 values so should be empty', p.isEmpty()); +} + + +function testPeek1() { + var p = getPriorityQueue(); + assertEquals('peek, Should be "a"', p.peek(), 'a'); +} + + +function testPeek2() { + var p = getPriorityQueue2(); + assertEquals('peek, Should be "a"', p.peek(), 'a'); +} + + +function testPeek3() { + var p = getPriorityQueue(); + p.clear(); + assertEquals('peek, Should be "a"', p.peek(), undefined); +} + + +function testDequeue1() { + var p = getPriorityQueue(); + + assertEquals('dequeue, Should be "a"', p.dequeue(), 'a'); + assertEquals('dequeue, Should be "b"', p.dequeue(), 'b'); + assertEquals('dequeue, Should be "c"', p.dequeue(), 'c'); + assertEquals('dequeue, Should be "d"', p.dequeue(), 'd'); +} + + +function testDequeue2() { + var p = getPriorityQueue2(); + + assertEquals('dequeue, Should be "a"', p.dequeue(), 'a'); + assertEquals('dequeue, Should be "b"', p.dequeue(), 'b'); + assertEquals('dequeue, Should be "c"', p.dequeue(), 'c'); + assertEquals('dequeue, Should be "d"', p.dequeue(), 'd'); +} + + +function testEnqueuePeek1() { + var p = new goog.structs.PriorityQueue(); + + p.enqueue(3, 'd'); + assertEquals('peak, Should be "d"', p.peek(), 'd'); + p.enqueue(2, 'c'); + assertEquals('peak, Should be "c"', p.peek(), 'c'); + p.enqueue(1, 'b'); + assertEquals('peak, Should be "b"', p.peek(), 'b'); + p.enqueue(0, 'a'); + assertEquals('peak, Should be "a"', p.peek(), 'a'); +} + + +function testEnqueuePeek2() { + var p = new goog.structs.PriorityQueue(); + + p.enqueue(1, 'b'); + assertEquals('peak, Should be "b"', p.peek(), 'b'); + p.enqueue(3, 'd'); + assertEquals('peak, Should be "b"', p.peek(), 'b'); + p.enqueue(0, 'a'); + assertEquals('peak, Should be "a"', p.peek(), 'a'); + p.enqueue(2, 'c'); + assertEquals('peak, Should be "a"', p.peek(), 'a'); +} + +</script> +</body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/quadtree.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/quadtree.js.svn-base new file mode 100644 index 0000000..db52476 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/quadtree.js.svn-base @@ -0,0 +1,571 @@ +// Copyright 2008 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Datastructure: A point Quad Tree for representing 2D data. Each + * region has the same ratio as the bounds for the tree. + * + * The implementation currently requires pre-determined bounds for data as it + * can not rebalance itself to that degree. + * + * @see ../demos/quadtree.html + */ + + +goog.provide('goog.structs.QuadTree'); +goog.provide('goog.structs.QuadTree.Node'); +goog.provide('goog.structs.QuadTree.Point'); + +goog.require('goog.math.Coordinate'); + + + +/** + * Constructs a new quad tree. + * @param {number} minX Minimum x-value that can be held in tree. + * @param {number} minY Minimum y-value that can be held in tree. + * @param {number} maxX Maximum x-value that can be held in tree. + * @param {number} maxY Maximum y-value that can be held in tree. + * @constructor + */ +goog.structs.QuadTree = function(minX, minY, maxX, maxY) { + + /** + * The root node for the quad tree. + * @type {goog.structs.QuadTree.Node} + * @private + */ + this.root_ = new goog.structs.QuadTree.Node( + minX, minY, maxX - minX, maxY - minY); +}; + + +/** + * Count of the number of items in the tree. + * @type {number} + * @private + */ +goog.structs.QuadTree.prototype.count_ = 0; + + +/** + * Returns a reference to the tree's root node. Callers shouldn't modify nodes, + * directly. This is a convenience for visualization and debugging purposes. + * @return {goog.structs.QuadTree.Node} The root node. + */ +goog.structs.QuadTree.prototype.getRootNode = function() { + return this.root_; +}; + + +/** + * Sets the value of an (x, y) point within the quad-tree. + * @param {number} x The x-coordinate. + * @param {number} y The y-coordinate. + * @param {*} value The value associated with the point. + */ +goog.structs.QuadTree.prototype.set = function(x, y, value) { + var root = this.root_; + if (x < root.x || y < root.y || x > root.x + root.w || y > root.y + root.h) { + throw Error('Out of bounds : (' + x + ', ' + y + ')'); + } + if (this.insert_(root, new goog.structs.QuadTree.Point(x, y, value))) { + this.count_++; + } +}; + + +/** + * Gets the value of the point at (x, y) or null if the point is empty. + * @param {number} x The x-coordinate. + * @param {number} y The y-coordinate. + * @param {*=} opt_default The default value to return if the node doesn't + * exist. + * @return {*} The value of the node, the default value if the node + * doesn't exist, or undefined if the node doesn't exist and no default + * has been provided. + */ +goog.structs.QuadTree.prototype.get = function(x, y, opt_default) { + var node = this.find_(this.root_, x, y); + return node ? node.point.value : opt_default; +}; + + +/** + * Removes a point from (x, y) if it exists. + * @param {number} x The x-coordinate. + * @param {number} y The y-coordinate. + * @return {*} The value of the node that was removed, or null if the + * node doesn't exist. + */ +goog.structs.QuadTree.prototype.remove = function(x, y) { + var node = this.find_(this.root_, x, y); + if (node) { + var value = node.point.value; + node.point = null; + node.nodeType = goog.structs.QuadTree.NodeType.EMPTY; + this.balance_(node); + this.count_--; + return value; + } else { + return null; + } +}; + + +/** + * Returns true if the point at (x, y) exists in the tree. + * @param {number} x The x-coordinate. + * @param {number} y The y-coordinate. + * @return {boolean} Whether the tree contains a point at (x, y). + */ +goog.structs.QuadTree.prototype.contains = function(x, y) { + return this.get(x, y) != null; +}; + + +/** + * @return {boolean} Whether the tree is empty. + */ +goog.structs.QuadTree.prototype.isEmpty = function() { + return this.root_.nodeType == goog.structs.QuadTree.NodeType.EMPTY; +}; + + +/** + * @return {number} The number of items in the tree. + */ +goog.structs.QuadTree.prototype.getCount = function() { + return this.count_; +}; + + +/** + * Removes all items from the tree. + */ +goog.structs.QuadTree.prototype.clear = function() { + this.root_.nw = this.root_.ne = this.root_.sw = this.root_.se = null; + this.root_.nodeType = goog.structs.QuadTree.NodeType.EMPTY; + this.root_.point = null; + this.count_ = 0; +}; + + +/** + * Returns an array containing the coordinates of each point stored in the tree. + * @return {Array.<goog.math.Coordinate?>} Array of coordinates. + */ +goog.structs.QuadTree.prototype.getKeys = function() { + var arr = []; + this.traverse_(this.root_, function(node) { + arr.push(new goog.math.Coordinate(node.point.x, node.point.y)); + }); + return arr; +}; + + +/** + * Returns an array containing all values stored within the tree. + * @return {Array.<Object>} The values stored within the tree. + */ +goog.structs.QuadTree.prototype.getValues = function() { + var arr = []; + this.traverse_(this.root_, function(node) { + // Must have a point because it's a leaf. + arr.push(node.point.value); + }); + return arr; +}; + + +/** + * Clones the quad-tree and returns the new instance. + * @return {goog.structs.QuadTree} A clone of the tree. + */ +goog.structs.QuadTree.prototype.clone = function() { + var x1 = this.root_.x; + var y1 = this.root_.y; + var x2 = x1 + this.root_.w; + var y2 = y1 + this.root_.h; + var clone = new goog.structs.QuadTree(x1, y1, x2, y2); + // This is inefficient as the clone needs to recalculate the structure of the + // tree, even though we know it already. But this is easier and can be + // optimized when/if needed. + this.traverse_(this.root_, function(node) { + clone.set(node.point.x, node.point.y, node.point.value); + }); + return clone; +}; + + +/** + * Traverses the tree and calls a function on each node. + * @param {function(Object, goog.math.Coordinate, goog.structs.QuadTree)} fn + * The function to call for every value. This function takes 3 arguments + * (the value, the coordinate, and the tree itself) and the return value is + * irrelevant. + * @param {Object=} opt_obj The object to be used as the value of 'this' + * within {@ code fn}. + */ +goog.structs.QuadTree.prototype.forEach = function(fn, opt_obj) { + this.traverse_(this.root_, function(node) { + var coord = new goog.math.Coordinate(node.point.x, node.point.y); + fn.call(opt_obj, node.point.value, coord, this); + }); +}; + + +/** + * Traverses the tree depth-first, with quadrants being traversed in clockwise + * order (NE, SE, SW, NW). The provided function will be called for each + * leaf node that is encountered. + * @param {goog.structs.QuadTree.Node} node The current node. + * @param {function(goog.structs.QuadTree.Node)} fn The function to call + * for each leaf node. This function takes the node as an argument, and its + * return value is irrelevant. + * @private + */ +goog.structs.QuadTree.prototype.traverse_ = function(node, fn) { + switch (node.nodeType) { + case goog.structs.QuadTree.NodeType.LEAF: + fn.call(this, node); + break; + + case goog.structs.QuadTree.NodeType.POINTER: + this.traverse_(node.ne, fn); + this.traverse_(node.se, fn); + this.traverse_(node.sw, fn); + this.traverse_(node.nw, fn); + break; + } +}; + + +/** + * Finds a leaf node with the same (x, y) coordinates as the target point, or + * null if no point exists. + * @param {goog.structs.QuadTree.Node} node The node to search in. + * @param {number} x The x-coordinate of the point to search for. + * @param {number} y The y-coordinate of the point to search for. + * @return {goog.structs.QuadTree.Node} The leaf node that matches the target, + * or null if it doesn't exist. + * @private + */ +goog.structs.QuadTree.prototype.find_ = function(node, x, y) { + switch (node.nodeType) { + case goog.structs.QuadTree.NodeType.EMPTY: + return null; + + case goog.structs.QuadTree.NodeType.LEAF: + return node.point.x == x && node.point.y == y ? node : null; + + case goog.structs.QuadTree.NodeType.POINTER: + return this.find_(this.getQuadrantForPoint_(node, x, y), x, y); + + default: + throw Error('Invalid nodeType'); + } +}; + + +/** + * Inserts a point into the tree, updating the tree's structure if necessary. + * @param {goog.structs.QuadTree.Node} parent The parent to insert the point + * into. + * @param {goog.structs.QuadTree.Point} point The point to insert. + * @return {boolean} True if a new node was added to the tree; False if a node + * already existed with the correpsonding coordinates and had its value + * reset. + * @private + */ +goog.structs.QuadTree.prototype.insert_ = function(parent, point) { + switch (parent.nodeType) { + case goog.structs.QuadTree.NodeType.EMPTY: + this.setPointForNode_(parent, point); + return true; + + case goog.structs.QuadTree.NodeType.LEAF: + if (parent.point.x == point.x && parent.point.y == point.y) { + this.setPointForNode_(parent, point); + return false; + } else { + this.split_(parent); + return this.insert_(parent, point); + } + + case goog.structs.QuadTree.NodeType.POINTER: + return this.insert_( + this.getQuadrantForPoint_(parent, point.x, point.y), point); + + default: + throw Error('Invalid nodeType in parent'); + } +}; + + +/** + * Converts a leaf node to a pointer node and reinserts the node's point into + * the correct child. + * @param {goog.structs.QuadTree.Node} node The node to split. + * @private + */ +goog.structs.QuadTree.prototype.split_ = function(node) { + var oldPoint = node.point; + node.point = null; + + node.nodeType = goog.structs.QuadTree.NodeType.POINTER; + + var x = node.x; + var y = node.y; + var hw = node.w / 2; + var hh = node.h / 2; + + node.nw = new goog.structs.QuadTree.Node(x, y, hw, hh, node); + node.ne = new goog.structs.QuadTree.Node(x + hw, y, hw, hh, node); + node.sw = new goog.structs.QuadTree.Node(x, y + hh, hw, hh, node); + node.se = new goog.structs.QuadTree.Node(x + hw, y + hh, hw, hh, node); + + this.insert_(node, oldPoint); +}; + + +/** + * Attempts to balance a node. A node will need balancing if all its children + * are empty or it contains just one leaf. + * @param {goog.structs.QuadTree.Node} node The node to balance. + * @private + */ +goog.structs.QuadTree.prototype.balance_ = function(node) { + switch (node.nodeType) { + case goog.structs.QuadTree.NodeType.EMPTY: + case goog.structs.QuadTree.NodeType.LEAF: + if (node.parent) { + this.balance_(node.parent); + } + break; + + case goog.structs.QuadTree.NodeType.POINTER: + var nw = node.nw, ne = node.ne, sw = node.sw, se = node.se; + var firstLeaf = null; + + // Look for the first non-empty child, if there is more than one then we + // break as this node can't be balanced. + if (nw.nodeType != goog.structs.QuadTree.NodeType.EMPTY) { + firstLeaf = nw; + } + if (ne.nodeType != goog.structs.QuadTree.NodeType.EMPTY) { + if (firstLeaf) { + break; + } + firstLeaf = ne; + } + if (sw.nodeType != goog.structs.QuadTree.NodeType.EMPTY) { + if (firstLeaf) { + break; + } + firstLeaf = sw; + } + if (se.nodeType != goog.structs.QuadTree.NodeType.EMPTY) { + if (firstLeaf) { + break; + } + firstLeaf = se; + } + + if (!firstLeaf) { + // All child nodes are empty: so make this node empty. + node.nodeType = goog.structs.QuadTree.NodeType.EMPTY; + node.nw = node.ne = node.sw = node.se = null; + + } else if (firstLeaf.nodeType == goog.structs.QuadTree.NodeType.POINTER) { + // Only child was a pointer, therefore we can't rebalance. + break; + + } else { + // Only child was a leaf: so update node's point and make it a leaf. + node.nodeType = goog.structs.QuadTree.NodeType.LEAF; + node.nw = node.ne = node.sw = node.se = null; + node.point = firstLeaf.point; + } + + // Try and balance the parent as well. + if (node.parent) { + this.balance_(node.parent); + } + + break; + } +}; + + +/** + * Returns the child quadrant within a node that contains the given (x, y) + * coordinate. + * @param {goog.structs.QuadTree.Node} parent The node. + * @param {number} x The x-coordinate to look for. + * @param {number} y The y-coordinate to look for. + * @return {goog.structs.QuadTree.Node} The child quadrant that contains the + * point. + * @private + */ +goog.structs.QuadTree.prototype.getQuadrantForPoint_ = function(parent, x, y) { + var mx = parent.x + parent.w / 2; + var my = parent.y + parent.h / 2; + if (x < mx) { + return y < my ? parent.nw : parent.sw; + } else { + return y < my ? parent.ne : parent.se; + } +}; + + +/** + * Sets the point for a node, as long as the node is a leaf or empty. + * @param {goog.structs.QuadTree.Node} node The node to set the point for. + * @param {goog.structs.QuadTree.Point} point The point to set. + * @private + */ +goog.structs.QuadTree.prototype.setPointForNode_ = function(node, point) { + if (node.nodeType == goog.structs.QuadTree.NodeType.POINTER) { + throw Error('Can not set point for node of type POINTER'); + } + node.nodeType = goog.structs.QuadTree.NodeType.LEAF; + node.point = point; +}; + + +/** + * Enumeration of node types. + * @enum {number} + */ +goog.structs.QuadTree.NodeType = { + EMPTY: 0, + LEAF: 1, + POINTER: 2 +}; + + + +/** + * Constructs a new quad tree node. + * @param {number} x X-coordiate of node. + * @param {number} y Y-coordinate of node. + * @param {number} w Width of node. + * @param {number} h Height of node. + * @param {goog.structs.QuadTree.Node=} opt_parent Optional parent node. + * @constructor + */ +goog.structs.QuadTree.Node = function(x, y, w, h, opt_parent) { + /** + * The x-coordinate of the node. + * @type {number} + */ + this.x = x; + + /** + * The y-coordinate of the node. + * @type {number} + */ + this.y = y; + + /** + * The width of the node. + * @type {number} + */ + this.w = w; + + /** + * The height of the node. + * @type {number} + */ + this.h = h; + + /** + * The parent node. + * @type {goog.structs.QuadTree.Node?} + */ + this.parent = opt_parent || null; +}; + + +/** + * The node's type. + * @type {goog.structs.QuadTree.NodeType} + */ +goog.structs.QuadTree.Node.prototype.nodeType = + goog.structs.QuadTree.NodeType.EMPTY; + + +/** + * The child node in the North-West quadrant. + * @type {goog.structs.QuadTree.Node?} + */ +goog.structs.QuadTree.Node.prototype.nw = null; + + +/** + * The child node in the North-East quadrant. + * @type {goog.structs.QuadTree.Node?} + */ +goog.structs.QuadTree.Node.prototype.ne = null; + + +/** + * The child node in the South-West quadrant. + * @type {goog.structs.QuadTree.Node?} + */ +goog.structs.QuadTree.Node.prototype.sw = null; + + +/** + * The child node in the South-East quadrant. + * @type {goog.structs.QuadTree.Node?} + */ +goog.structs.QuadTree.Node.prototype.se = null; + + +/** + * The point for the node, if it is a leaf node. + * @type {goog.structs.QuadTree.Point?} + */ +goog.structs.QuadTree.Node.prototype.point = null; + + + +/** + * Creates a new point object. + * @param {number} x The x-coordinate of the point. + * @param {number} y The y-coordinate of the point. + * @param {*=} opt_value Optional value associated with the point. + * @constructor + */ +goog.structs.QuadTree.Point = function(x, y, opt_value) { + /** + * The x-coordinate for the point. + * @type {number} + */ + this.x = x; + + /** + * The y-coordinate for the point. + * @type {number} + */ + this.y = y; + + /** + * Optional value associated with the point. + * @type {*} + */ + this.value = goog.isDef(opt_value) ? opt_value : null; +}; diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/quadtree_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/quadtree_test.html.svn-base new file mode 100644 index 0000000..c51e144 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/quadtree_test.html.svn-base @@ -0,0 +1,179 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright 2008 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> +<head> +<meta http-equiv="X-UA-Compatible" content="IE=edge"> +<title>Closure Unit Tests - goog.structs.QuadTree</title> +<script src="../base.js"></script> +<script> + goog.require('goog.array'); + goog.require('goog.structs'); + goog.require('goog.structs.QuadTree'); + goog.require('goog.testing.jsunit'); +</script> +</head> +<body> +<script> + + function getTree() { + var qt = new goog.structs.QuadTree(0, 0, 100, 100); + qt.set(5, 20, 'Foo'); + qt.set(50, 32, 'Bar'); + qt.set(47, 96, 'Baz'); + qt.set(50, 50, 'Bing'); + qt.set(12, 0, 'Bong'); + return qt; + } + + function testGetCount() { + var qt = getTree(); + assertEquals('Count should be 5', 5, qt.getCount()); + qt.remove(50, 32); + assertEquals('Count should be 4', 4, qt.getCount()); + } + + function testGetKeys() { + var keys = getTree().getKeys(); + var keyString = keys.sort().join(' '); + var expected = '(12, 0) (47, 96) (5, 20) (50, 32) (50, 50)'; + assertEquals('Sorted keys should be ' + expected, expected, keyString); + } + + function testGetValues() { + var values = getTree().getValues(); + var valueString = values.sort().join(','); + assertEquals('Sorted values should be Bar,Baz,Bing,Bong,Foo', + 'Bar,Baz,Bing,Bong,Foo', valueString); + } + + function testContains() { + var qt = getTree(); + assertTrue('Should contain (5, 20)', qt.contains(5, 20)); + assertFalse('Should not contain (13, 13)', qt.contains(13, 13)); + } + + function testClear() { + var qt = getTree(); + qt.clear(); + assertTrue('Tree should be empty', qt.isEmpty()); + assertFalse('Tree should not contain (5, 20)', qt.contains(5, 20)); + } + + function testConstructor() { + var qt = new goog.structs.QuadTree(-10, -5, 6, 12); + var root = qt.getRootNode(); + assertEquals('X of root should be -10', -10, root.x); + assertEquals('Y of root should be -5', -5, root.y); + assertEquals('Width of root should be 16', 16, root.w); + assertEquals('Height of root should be 17', 17, root.h); + assertTrue('Tree should be empty', qt.isEmpty()); + } + + function testClone() { + var qt = getTree().clone(); + assertFalse('Clone should not be empty', qt.isEmpty()); + assertTrue('Should contain (47, 96)', qt.contains(47, 96)); + } + + function testRemove() { + var qt = getTree(); + assertEquals('(5, 20) should be removed', 'Foo', qt.remove(5, 20)); + assertEquals('(5, 20) should be removed', 'Bar', qt.remove(50, 32)); + assertEquals('(5, 20) should be removed', 'Baz', qt.remove(47, 96)); + assertEquals('(5, 20) should be removed', 'Bing', qt.remove(50, 50)); + assertEquals('(5, 20) should be removed', 'Bong', qt.remove(12, 0)); + assertNull('(6, 6) wasn\'t there to remove', qt.remove(6, 6)); + assertTrue('Tree should be empty', qt.isEmpty()); + assertTreesChildrenAreNull(qt) + } + + function testIsEmpty() { + var qt = getTree(); + qt.clear(); + assertTrue(qt.isEmpty()); + assertEquals('Root should be empty node', + goog.structs.QuadTree.NodeType.EMPTY, qt.getRootNode().nodeType); + assertTreesChildrenAreNull(qt); + } + + function testForEach() { + var qt = getTree(); + var s = ''; + goog.structs.forEach(qt, function(val, key, qt2) { + assertNotUndefined(key); + assertEquals(qt, qt2); + s += key.x + ',' + key.y + '=' + val + ' '; + }); + assertEquals('50,32=Bar 50,50=Bing 47,96=Baz 5,20=Foo 12,0=Bong ', s); + } + + function testBalancing() { + var qt = new goog.structs.QuadTree(0, 0, 100, 100); + var root = qt.getRootNode(); + + // Add a point to the NW quadrant. + qt.set(25, 25, 'first'); + + assertEquals('Root should be a leaf node.', + goog.structs.QuadTree.NodeType.LEAF, root.nodeType); + assertTreesChildrenAreNull(qt); + + assertEquals('first', root.point.value); + + // Add another point in the NW quadrant + qt.set(25, 30, 'second'); + + assertEquals('Root should now be a pointer.', + goog.structs.QuadTree.NodeType.POINTER, root.nodeType); + assertNotNull('NE should be not be null', root.ne); + assertNotNull('NW should be not be null', root.nw); + assertNotNull('SE should be not be null', root.se); + assertNotNull('SW should be not be null', root.sw); + assertNull(root.point); + + // Delete the second point. + qt.remove(25, 30); + + assertEquals('Root should have been rebalanced and be a leaf node.', + goog.structs.QuadTree.NodeType.LEAF, root.nodeType); + assertTreesChildrenAreNull(qt); + assertEquals('first', root.point.value); + } + + function testTreeBounds() { + var qt = getTree(); + assertFails(qt, qt.set, [-10, -10, 1]); + assertFails(qt, qt.set, [-10, 10, 2]); + assertFails(qt, qt.set, [10, -10, 3]); + assertFails(qt, qt.set, [-10, 110, 4]); + assertFails(qt, qt.set, [10, 130, 5]); + assertFails(qt, qt.set, [110, -10, 6]); + assertFails(qt, qt.set, [150, 14, 7]); + } + + // Helper functions + + function assertFails(context, fn, args) { + assertThrows('Exception expected from ' + fn.toString() + + ' with arguments ' + args, + function() { + fn.apply(context, args); + }); + } + + function assertTreesChildrenAreNull(qt) { + var root = qt.getRootNode(); + assertNull('NE should be null', root.ne); + assertNull('NW should be null', root.nw); + assertNull('SE should be null', root.se); + assertNull('SW should be null', root.sw); + } + +</script> +</body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/queue.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/queue.js.svn-base new file mode 100644 index 0000000..3be02f5 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/queue.js.svn-base @@ -0,0 +1,157 @@ +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Datastructure: Queue. + * + * + * This file provides the implementation of a FIFO Queue structure. + * API is similar to that of com.google.common.collect.IntQueue + */ + +goog.provide('goog.structs.Queue'); + +goog.require('goog.array'); + + + +/** + * Class for FIFO Queue data structure. + * + * @constructor + */ +goog.structs.Queue = function() { + this.elements_ = []; +}; + + +/** + * The index of the next element to be removed from the queue. + * @private + * @type {number} + */ +goog.structs.Queue.prototype.head_ = 0; + + +/** + * The index at which the next element would be added to the queue. + * @private + * @type {number} + */ +goog.structs.Queue.prototype.tail_ = 0; + + +/** + * Puts the specified element on this queue. + * @param {*} element The element to be added to the queue. + */ +goog.structs.Queue.prototype.enqueue = function(element) { + this.elements_[this.tail_++] = element; +}; + + +/** + * Retrieves and removes the head of this queue. + * @return {*} The element at the head of this queue. Returns undefined if the + * queue is empty. + */ +goog.structs.Queue.prototype.dequeue = function() { + if (this.head_ == this.tail_) { + return undefined; + } + var result = this.elements_[this.head_]; + delete this.elements_[this.head_]; + this.head_++; + return result; +}; + + +/** + * Retrieves but does not remove the head of this queue. + * @return {*} The element at the head of this queue. Returns undefined if the + * queue is empty. + */ +goog.structs.Queue.prototype.peek = function() { + if (this.head_ == this.tail_) { + return undefined; + } + return this.elements_[this.head_]; +}; + + +/** + * Returns the number of elements in this queue. + * @return {number} The number of elements in this queue. + */ +goog.structs.Queue.prototype.getCount = function() { + return this.tail_ - this.head_; +}; + + +/** + * Returns true if this queue contains no elements. + * @return {boolean} true if this queue contains no elements. + */ +goog.structs.Queue.prototype.isEmpty = function() { + return this.tail_ - this.head_ == 0; +}; + + +/** + * Removes all elements from the queue. + */ +goog.structs.Queue.prototype.clear = function() { + this.elements_.length = 0; + this.head_ = 0; + this.tail_ = 0; +}; + + +/** + * Returns true if the given value is in the queue. + * @param {*} obj The value to look for. + * @return {boolean} Whether the object is in the queue. + */ +goog.structs.Queue.prototype.contains = function(obj) { + return goog.array.contains(this.elements_, obj); +}; + + +/** + * Removes the first occurrence of a particular value from the queue. + * @param {*} obj Object to remove. + * @return {boolean} True if an element was removed. + */ +goog.structs.Queue.prototype.remove = function(obj) { + var index = goog.array.indexOf(this.elements_, obj); + if (index < 0) { + return false; + } + if (index == this.head_) { + this.dequeue(); + } else { + goog.array.removeAt(this.elements_, index); + this.tail_--; + } + return true; +}; + + +/** + * Returns all the values in the queue. + * @return {Array} An array of the values in the queue. + */ +goog.structs.Queue.prototype.getValues = function() { + return this.elements_.slice(this.head_, this.tail_); +}; diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/queue_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/queue_test.html.svn-base new file mode 100644 index 0000000..bbfae75 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/queue_test.html.svn-base @@ -0,0 +1,140 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright 2006 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> +<head> +<meta http-equiv="X-UA-Compatible" content="IE=edge"> +<title>Closure Unit Tests - goog.structs.Queue</title> +<script src="../base.js"></script> +<script> + goog.require('goog.structs.Queue'); + goog.require('goog.testing.jsunit'); +</script> +</head> +<body> +<script> + +function stringifyQueue(q) { + var values = q.getValues(); + var s = ''; + for (var i = 0; i < values.length; i++) { + s += values[i]; + } + return s; +} + +function createQueue() { + var q = new goog.structs.Queue(); + q.enqueue('a'); + q.enqueue('b'); + q.enqueue('c'); + return q; +} + +function testConstructor() { + var q = new goog.structs.Queue(); + assertTrue('testConstructor(), queue should be empty initially', q.isEmpty()); + assertEquals('testConstructor(), count should be 0', q.getCount(), 0); + assertEquals('testConstructor(), head element should be undefined', q.peek(), + undefined); +} + +function testCount() { + var q = createQueue(); + assertEquals('testCount(), count should be 3', q.getCount(), 3); + q.enqueue('d'); + assertEquals('testCount(), count should be 4', q.getCount(), 4); + q.dequeue(); + assertEquals('testCount(), count should be 3', q.getCount(), 3); + q.clear(); + assertEquals('testCount(), count should be 0', q.getCount(), 0); +} + +function testEnqueue() { + var q = new goog.structs.Queue(); + q.enqueue('a'); + assertEquals('testEnqueue(), count should be 1', q.getCount(), 1); + q.enqueue('b'); + assertEquals('testEnqueue(), count should be 2', q.getCount(), 2); + assertEquals('testEnqueue(), head element should be a', q.peek(), 'a'); + q.dequeue(); + assertEquals('testEnqueue(), count should be 1', q.getCount(), 1); + assertEquals('testEnqueue(), head element should be b', q.peek(), 'b'); +} + +function testDequeue() { + var q = createQueue(); + var head = q.dequeue(); + assertEquals('testDequeue(), should return a', head, 'a'); + q.dequeue(); + head = q.dequeue(); + assertEquals('testDequeue(), should return c', head, 'c'); + assertTrue('testDequeue(), queue should be empty', q.isEmpty()); + head = q.dequeue(); + assertEquals('testDequeue(), should return undefined for empty queue', head, + undefined); +} + +function testPeek() { + var q = createQueue(); + var head = q.peek(); + assertEquals('testPeek(), should return a', head, 'a'); + var head2 = q.dequeue(); + assertEquals('testPeek(), dequeue should return peek() result', head, head2); + head = q.peek(); + assertEquals('testPeek(), should return b', head, 'b'); + q.clear(); + head = q.peek(); + assertEquals('testPeek(), should return undefined for empty queue', head, + undefined); +} + +function testClear() { + var q = createQueue(); + q.clear(); + assertTrue('testClear(), queue should be empty', q.isEmpty()); +} + +function testQueue() { + var q = createQueue(); + assertEquals('testQueue(), contents must be abc', stringifyQueue(q), 'abc'); +} + +function testRemove() { + var q = createQueue(); + assertEquals('testRemove(), contents must be abc', stringifyQueue(q), 'abc'); + + q.dequeue(); + assertEquals('testRemove(), contents must be bc', stringifyQueue(q), 'bc'); + + q.enqueue('a'); + assertEquals('testRemove(), contents must be bca', stringifyQueue(q), 'bca'); + + assertTrue('testRemove(), remove should have returned true', q.remove('c')); + assertEquals('testRemove(), contents must be ba', stringifyQueue(q), 'ba'); + + assertTrue('testRemove(), remove should have returned true', q.remove('b')); + assertEquals('testRemove(), contents must be a', stringifyQueue(q), 'a'); + + assertFalse('testRemove(), remove should have returned false', q.remove('b')); + assertEquals('testRemove(), contents must be a', stringifyQueue(q), 'a'); + + assertTrue('testRemove(), remove should have returned true', q.remove('a')); + assertEquals('testRemove(), contents must be empty', stringifyQueue(q), ''); +} + +function testContains() { + var q = createQueue(); + assertTrue('testContains(), contains should have returned true', + q.contains('a')); + assertFalse('testContains(), contains should have returned false', + q.contains('foobar')); +} + +</script> +</body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/set.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/set.js.svn-base new file mode 100644 index 0000000..4719f6a --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/set.js.svn-base @@ -0,0 +1,255 @@ +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Datastructure: Set. + * + * @author arv@google.com (Erik Arvidsson) + * @author pallosp@google.com (Peter Pallos) + * + * This class implements a set data structure. Adding and removing is O(1). It + * supports both object and primitive values. Be careful because you can add + * both 1 and new Number(1), because these are not the same. You can even add + * multiple new Number(1) because these are not equal. + */ + + +goog.provide('goog.structs.Set'); + +goog.require('goog.structs'); +goog.require('goog.structs.Collection'); +goog.require('goog.structs.Map'); + + + +/** + * A set that can contain both primitives and objects. Adding and removing + * elements is O(1). Primitives are treated as identical if they have the same + * type and convert to the same string. Objects are treated as identical only + * if they are references to the same object. WARNING: A goog.structs.Set can + * contain both 1 and (new Number(1)), because they are not the same. WARNING: + * Adding (new Number(1)) twice will yield two distinct elements, because they + * are two different objects. WARNING: Any object that is added to a + * goog.structs.Set will be modified! Because goog.getUid() is used to + * identify objects, every object in the set will be mutated. + * @param {Array|Object=} opt_values Initial values to start with. + * @constructor + * @implements {goog.structs.Collection} + */ +goog.structs.Set = function(opt_values) { + this.map_ = new goog.structs.Map; + if (opt_values) { + this.addAll(opt_values); + } +}; + + +/** + * Obtains a unique key for an element of the set. Primitives will yield the + * same key if they have the same type and convert to the same string. Object + * references will yield the same key only if they refer to the same object. + * @param {*} val Object or primitive value to get a key for. + * @return {string} A unique key for this value/object. + * @private + */ +goog.structs.Set.getKey_ = function(val) { + var type = typeof val; + if (type == 'object' && val || type == 'function') { + return 'o' + goog.getUid(/** @type {Object} */ (val)); + } else { + return type.substr(0, 1) + val; + } +}; + + +/** + * @return {number} The number of elements in the set. + */ +goog.structs.Set.prototype.getCount = function() { + return this.map_.getCount(); +}; + + +/** + * Add a primitive or an object to the set. + * @param {*} element The primitive or object to add. + */ +goog.structs.Set.prototype.add = function(element) { + this.map_.set(goog.structs.Set.getKey_(element), element); +}; + + +/** + * Adds all the values in the given collection to this set. + * @param {Array|Object} col A collection containing the elements to add. + */ +goog.structs.Set.prototype.addAll = function(col) { + var values = goog.structs.getValues(col); + var l = values.length; + for (var i = 0; i < l; i++) { + this.add(values[i]); + } +}; + + +/** + * Removes all values in the given collection from this set. + * @param {Array|Object} col A collection containing the elements to remove. + */ +goog.structs.Set.prototype.removeAll = function(col) { + var values = goog.structs.getValues(col); + var l = values.length; + for (var i = 0; i < l; i++) { + this.remove(values[i]); + } +}; + + +/** + * Removes the given element from this set. + * @param {*} element The primitive or object to remove. + * @return {boolean} Whether the element was found and removed. + */ +goog.structs.Set.prototype.remove = function(element) { + return this.map_.remove(goog.structs.Set.getKey_(element)); +}; + + +/** + * Removes all elements from this set. + */ +goog.structs.Set.prototype.clear = function() { + this.map_.clear(); +}; + + +/** + * Tests whether this set is empty. + * @return {boolean} True if there are no elements in this set. + */ +goog.structs.Set.prototype.isEmpty = function() { + return this.map_.isEmpty(); +}; + + +/** + * Tests whether this set contains the given element. + * @param {*} element The primitive or object to test for. + * @return {boolean} True if this set contains the given element. + */ +goog.structs.Set.prototype.contains = function(element) { + return this.map_.containsKey(goog.structs.Set.getKey_(element)); +}; + + +/** + * Tests whether this set contains all the values in a given collection. + * Repeated elements in the collection are ignored, e.g. (new + * goog.structs.Set([1, 2])).containsAll([1, 1]) is True. + * @param {Object} col A collection-like object. + * @return {boolean} True if the set contains all elements. + */ +goog.structs.Set.prototype.containsAll = function(col) { + return goog.structs.every(col, this.contains, this); +}; + + +/** + * Finds all values that are present in both this set and the given collection. + * @param {Array|Object} col A collection. + * @return {!goog.structs.Set} A new set containing all the values (primitives + * or objects) present in both this set and the given collection. + */ +goog.structs.Set.prototype.intersection = function(col) { + var result = new goog.structs.Set(); + + var values = goog.structs.getValues(col); + for (var i = 0; i < values.length; i++) { + var value = values[i]; + if (this.contains(value)) { + result.add(value); + } + } + + return result; +}; + + +/** + * Returns an array containing all the elements in this set. + * @return {!Array} An array containing all the elements in this set. + */ +goog.structs.Set.prototype.getValues = function() { + return this.map_.getValues(); +}; + + +/** + * Creates a shallow clone of this set. + * @return {!goog.structs.Set} A new set containing all the same elements as + * this set. + */ +goog.structs.Set.prototype.clone = function() { + return new goog.structs.Set(this); +}; + + +/** + * Tests whether the given collection consists of the same elements as this set, + * regardless of order, without repetition. Primitives are treated as equal if + * they have the same type and convert to the same string; objects are treated + * as equal if they are references to the same object. This operation is O(n). + * @param {Object} col A collection. + * @return {boolean} True if the given collection consists of the same elements + * as this set, regardless of order, without repetition. + */ +goog.structs.Set.prototype.equals = function(col) { + return this.getCount() == goog.structs.getCount(col) && this.isSubsetOf(col); +}; + + +/** + * Tests whether the given collection contains all the elements in this set. + * Primitives are treated as equal if they have the same type and convert to the + * same string; objects are treated as equal if they are references to the same + * object. This operation is O(n). + * @param {Object} col A collection. + * @return {boolean} True if this set is a subset of the given collection. + */ +goog.structs.Set.prototype.isSubsetOf = function(col) { + var colCount = goog.structs.getCount(col); + if (this.getCount() > colCount) { + return false; + } + // TODO(user) Find the minimal collection size where the conversion makes + // the contains() method faster. + if (!(col instanceof goog.structs.Set) && colCount > 5) { + // Convert to a goog.structs.Set so that goog.structs.contains runs in + // O(1) time instead of O(n) time. + col = new goog.structs.Set(col); + } + return goog.structs.every(this, function(value) { + return goog.structs.contains(col, value); + }); +}; + + +/** + * Returns an iterator that iterates over the elements in this set. + * @param {boolean=} opt_keys This argument is ignored. + * @return {!goog.iter.Iterator} An iterator over the elements in this set. + */ +goog.structs.Set.prototype.__iterator__ = function(opt_keys) { + return this.map_.__iterator__(false); +}; diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/set_perf.html.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/set_perf.html.svn-base new file mode 100644 index 0000000..1b784bd --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/set_perf.html.svn-base @@ -0,0 +1,237 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright 2009 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> +<!-- +--> +<head> +<meta http-equiv="X-UA-Compatible" content="IE=edge"> + <title>Closure Performance Tests - goog.ui.Set vs goog.ui.StringSet</title> + <link rel="stylesheet" type="text/css" href="../testing/performancetable.css"/> + <script src="../base.js"></script> + <script> + goog.require('goog.functions'); + goog.require('goog.string'); + goog.require('goog.structs.Set'); + goog.require('goog.structs.StringSet'); + goog.require('goog.testing.PerformanceTable'); + goog.require('goog.testing.PropertyReplacer'); + goog.require('goog.testing.jsunit'); + </script> +</head> +<body> + <h1>goog.ui.Set and goog.ui.StringSet Performance Tests</h1> + <p> + <strong>User-agent:</strong> + <script>document.write(navigator.userAgent);</script> + </p> + <div id="perfTable"></div> + <hr> + + <script> + var table = new goog.testing.PerformanceTable( + goog.dom.getElement('perfTable')); + + // Number of operations to measure in each table line. + var OPS_COUNT = 20000; + + var stubs = new goog.testing.PropertyReplacer(); + + function tearDown() { + stubs.reset(); + } + + function testCreateSetFromArrayWithoutRepetition() { + var values = [] + for (var i = 0; i < OPS_COUNT; i++) { + values.push(i); + } + + table.run(function() { + var s = new goog.structs.StringSet(values); + }, 'Create string set from number array without repetition'); + + values = [] + for (var i = 0; i < OPS_COUNT; i++) { + values.push(String(i)); + } + + table.run(function() { + var s = new goog.structs.StringSet(values); + }, 'Create string set from string array without repetition'); + } + + function testCreateSetWithoutRepetition() { + table.run(function() { + var s = new goog.structs.Set(); + for (var i = 0; i < OPS_COUNT; i++) { + s.add(i); + } + }, 'Add elements to set without repetition'); + + table.run(function() { + var s = new goog.structs.StringSet(); + for (var i = 0; i < OPS_COUNT; i++) { + s.add(i); + } + }, 'Add elements to string set without repetition'); + + stubs.set(goog.structs.StringSet.prototype, 'encode', + goog.functions.identity); + stubs.set(goog.structs.StringSet.prototype, 'decode', + goog.functions.identity); + + table.run(function() { + var s = new goog.structs.StringSet(); + for (var i = 0; i < OPS_COUNT; i++) { + s.add(i); + } + }, 'Add elements to string set without repetition and escaping'); + } + + function testCreateSetWithRepetition() { + table.run(function() { + var s = new goog.structs.Set(); + for (var n = 0; n < 10 ; n++) { + for (var i = 0; i < OPS_COUNT / 10; i++) { + s.add(i); + } + } + }, 'Add elements to set with repetition'); + + table.run(function() { + var s = new goog.structs.StringSet(); + for (var n = 0; n < 10; n++) { + for (var i = 0; i < OPS_COUNT / 10; i++) { + s.add(i); + } + } + }, 'Add elements to string set with repetition'); + } + + function testForEach() { + var bigSet = new goog.structs.Set; + var bigStringSet = new goog.structs.StringSet; + for (var i = 0; i < OPS_COUNT; i++) { + bigSet.add(i); + bigStringSet.add(i); + } + + table.run(function() { + goog.structs.forEach(bigSet, goog.nullFunction); + }, 'Iterate over set with forEach'); + + table.run(function() { + goog.structs.forEach(bigStringSet, goog.nullFunction); + }, 'Iterate over string set with forEach'); + } + + function testForEachWithLargeKeys() { + var bigSet = new goog.structs.Set; + var bigStringSet = new goog.structs.StringSet; + for (var i = 0; i < OPS_COUNT / 100; i++) { + bigSet.add(goog.string.repeat(String(i), 1000)); + bigStringSet.add(goog.string.repeat(String(i), 1000)); + } + + table.run(function() { + for (var i = 0; i < 100; i++) { + goog.structs.forEach(bigSet, goog.nullFunction); + } + }, 'Iterate over set of large strings with forEach'); + + table.run(function() { + for (var i = 0; i < 100; i++) { + goog.structs.forEach(bigStringSet, goog.nullFunction); + } + }, 'Iterate over string set of large strings with forEach'); + } + + function testAddRemove() { + table.run(function() { + var s = new goog.structs.Set(); + for (var i = 0; i < OPS_COUNT / 2; i++) { + s.add(i); + } + for (var i = 0; i < OPS_COUNT / 2; i++) { + s.remove(i); + } + }, 'Add then remove elements from set'); + + table.run(function() { + var s = new goog.structs.StringSet(); + for (var i = 0; i < OPS_COUNT / 2; i++) { + s.add(i); + } + for (var i = 0; i < OPS_COUNT / 2; i++) { + s.remove(i); + } + }, 'Add then remove elements from string set'); + } + + function testContains() { + var bigSet = new goog.structs.Set; + var bigStringSet = new goog.structs.StringSet; + var arr = []; + for (var i = 0; i < OPS_COUNT; i++) { + bigSet.add(i); + bigStringSet.add(i); + arr.push(i); + } + + table.run(function() { + for (var i = 0; i < OPS_COUNT; i++) { + bigSet.contains(i); + } + }, 'Membership check for each element of set'); + + table.run(function() { + for (var i = 0; i < OPS_COUNT; i++) { + bigStringSet.contains(i); + } + }, 'Membership check for each element of string set with contains'); + + table.run(function() { + bigStringSet.containsArray(arr); + }, 'Membership check for each element of string set with containsArray'); + + stubs.set(goog.structs.StringSet.prototype, 'encode', + goog.functions.identity); + stubs.set(goog.structs.StringSet.prototype, 'decode', + goog.functions.identity); + + table.run(function() { + for (var i = 0; i < OPS_COUNT; i++) { + bigStringSet.contains(i); + } + }, 'Membership check for each element of string set without escaping'); + } + + function testEquals() { + table.run(function() { + var s1 = new goog.structs.Set(); + var s2 = new goog.structs.Set(); + for (var i = 0; i < OPS_COUNT / 4; i++) { + s1.add(i); + s2.add(i); + } + s1.equals(s2); + }, 'Create then compare two sets'); + + table.run(function() { + var s1 = new goog.structs.StringSet(); + var s2 = new goog.structs.StringSet(); + for (var i = 0; i < OPS_COUNT / 4; i++) { + s1.add(i); + s2.add(i); + } + s1.equals(s2); + }, 'Create then compare two string sets'); + } + </script> +</body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/set_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/set_test.html.svn-base new file mode 100644 index 0000000..aa3f587 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/set_test.html.svn-base @@ -0,0 +1,551 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright 2006 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> +<head> +<meta http-equiv="X-UA-Compatible" content="IE=edge"> +<title>Closure Unit Tests - goog.structs.Set</title> +<script src="../base.js"></script> +<script> + goog.require('goog.iter'); + goog.require('goog.structs'); + goog.require('goog.structs.Set'); + goog.require('goog.testing.jsunit'); +</script> +</head> +<body> +<script> + +var Set = goog.structs.Set; + +function stringifySet(s) { + return goog.structs.getValues(s).join(''); +} + +function testGetCount() { + var s = new Set; + var a = new String('a'); s.add(a); + var b = new String('b'); s.add(b); + var c = new String('c'); s.add(c); + assertEquals('count, should be 3', s.getCount(), 3); + var d = new String('d'); s.add(d); + assertEquals('count, should be 4', s.getCount(), 4); + s.remove(d); + assertEquals('count, should be 3', s.getCount(), 3); + + s = new Set; + s.add('a'); + s.add('b'); + s.add('c'); + assertEquals('count, should be 3', s.getCount(), 3); + s.add('d'); + assertEquals('count, should be 4', s.getCount(), 4); + s.remove('d'); + assertEquals('count, should be 3', s.getCount(), 3); +} + +function testGetValues() { + var s = new Set; + var a = new String('a'); s.add(a); + var b = new String('b'); s.add(b); + var c = new String('c'); s.add(c); + var d = new String('d'); s.add(d); + assertEquals(s.getValues().join(''), 'abcd'); + + var s = new Set; + s.add('a'); + s.add('b'); + s.add('c'); + s.add('d'); + assertEquals(s.getValues().join(''), 'abcd'); +} + +function testContains() { + var s = new Set; + var a = new String('a'); s.add(a); + var b = new String('b'); s.add(b); + var c = new String('c'); s.add(c); + var d = new String('d'); s.add(d); + var e = new String('e');; + + assertTrue("contains, Should contain 'a'", s.contains(a)); + assertFalse("contains, Should not contain 'e'", s.contains(e)); + + s = new Set; + s.add('a'); + s.add('b'); + s.add('c'); + s.add('d'); + + assertTrue("contains, Should contain 'a'", s.contains('a')); + assertFalse("contains, Should not contain 'e'", s.contains('e')); +} + +function testContainsFunctionValue() { + var s = new Set; + + var fn1 = function() {}; + + assertFalse(s.contains(fn1)); + s.add(fn1); + assertTrue(s.contains(fn1)); + + var fn2 = function() {}; + + assertFalse(s.contains(fn2)); + s.add(fn2); + assertTrue(s.contains(fn2)); + + assertEquals(s.getCount(), 2); +} + +function testContainsAll() { + var set = new Set([1, 2, 3]); + + assertTrue("{1, 2, 3} contains []", set.containsAll([])); + assertTrue("{1, 2, 3} contains [1]", set.containsAll([1])); + assertTrue("{1, 2, 3} contains [1, 1]", set.containsAll([1, 1])); + assertTrue("{1, 2, 3} contains [3, 2, 1]", set.containsAll([3, 2, 1])); + assertFalse("{1, 2, 3} doesn't contain [4]", set.containsAll([4])); + assertFalse("{1, 2, 3} doesn't contain [1, 4]", set.containsAll([1, 4])); + + assertTrue("{1, 2, 3} contains {a: 1}", set.containsAll({a: 1})); + assertFalse("{1, 2, 3} doesn't contain {a: 4}", set.containsAll({a: 4})); + + assertTrue("{1, 2, 3} contains {1}", set.containsAll(new Set([1]))); + assertFalse("{1, 2, 3} doesn't contain {4}", set.containsAll(new Set([4]))); +} + +function testIntersection() { + var emptySet = new Set; + + assertTrue('intersection of empty set and [] should be empty', + emptySet.intersection([]).isEmpty()); + assertIntersection('intersection of 2 empty sets should be empty', + emptySet, new Set(), new Set()); + + var abcdSet = new Set(); + abcdSet.add('a'); + abcdSet.add('b'); + abcdSet.add('c'); + abcdSet.add('d'); + + assertTrue('intersection of populated set and [] should be empty', + abcdSet.intersection([]).isEmpty()); + assertIntersection('intersection of 2 empty sets should be empty', + abcdSet, new Set(), new Set()); + + var bcSet = new Set(['b', 'c']); + assertIntersection('intersection of [a,b,c,d] and [b,c]', + abcdSet, bcSet, bcSet); + + var bceSet = new Set(['b', 'c', 'e']); + assertIntersection('intersection of [a,b,c,d] and [b,c,e]', + abcdSet, bceSet, bcSet); +} + +/** + * Helper function to assert intersection is commutative. + */ +function assertIntersection(msg, set1, set2, expectedIntersection) { + assertTrue(msg + ': set1->set2', + set1.intersection(set2).equals(expectedIntersection)); + assertTrue(msg + ': set2->set1', + set2.intersection(set1).equals(expectedIntersection)); +} + +function testRemoveAll() { + assertRemoveAll('removeAll of empty set from empty set', [], [], []); + assertRemoveAll('removeAll of empty set from populated set', + ['a', 'b', 'c', 'd'], [], ['a', 'b', 'c', 'd']); + assertRemoveAll('removeAll of [a,d] from [a,b,c,d]', + ['a', 'b', 'c', 'd'], ['a', 'd'], ['b', 'c']); + assertRemoveAll('removeAll of [b,c] from [a,b,c,d]', + ['a', 'b', 'c', 'd'], ['b', 'c'], ['a', 'd']); + assertRemoveAll('removeAll of [b,c,e] from [a,b,c,d]', + ['a', 'b', 'c', 'd'], ['b', 'c', 'e'], ['a', 'd']); + assertRemoveAll('removeAll of [a,b,c,d] from [a,d]', + ['a', 'd'], ['a', 'b', 'c', 'd'], []); + assertRemoveAll('removeAll of [a,b,c,d] from [b,c]', + ['b', 'c'], ['a', 'b', 'c', 'd'], []); + assertRemoveAll('removeAll of [a,b,c,d] from [b,c,e]', + ['b', 'c', 'e'], ['a', 'b', 'c', 'd'], ['e']); +} + +/** + * Helper function to test removeAll. + */ +function assertRemoveAll(msg, elements1, elements2, expectedResult) { + var set1 = new Set(elements1); + var set2 = new Set(elements2); + set1.removeAll(set2); + + assertTrue(msg + ': set1 count increased after removeAll', + elements1.length >= set1.getCount()); + assertEquals(msg + ': set2 count changed after removeAll', + elements2.length, set2.getCount()); + assertTrue(msg + ': wrong set1 after removeAll', set1.equals(expectedResult)); + assertIntersection(msg + ': non-empty intersection after removeAll', + set1, set2, []); +} + +function testAdd() { + var s = new Set; + var a = new String('a'); + var b = new String('b'); + s.add(a); + assertTrue(s.contains(a)); + s.add(b) + assertTrue(s.contains(b)); + + s = new Set; + s.add('a') + assertTrue(s.contains('a')); + s.add('b') + assertTrue(s.contains('b')); + s.add(null); + assertTrue('contains null', s.contains(null)); + assertFalse('does not contain "null"', s.contains('null')); +} + + +function testClear() { + var s = new Set; + var a = new String('a'); s.add(a); + var b = new String('b'); s.add(b); + var c = new String('c'); s.add(c); + var d = new String('d'); s.add(d); + s.clear(); + assertTrue('cleared so it should be empty', s.isEmpty()); + assertTrue("cleared so it should not contain 'a' key", !s.contains(a)); + + s = new Set; + s.add('a'); + s.add('b'); + s.add('c'); + s.add('d'); + s.clear(); + assertTrue('cleared so it should be empty', s.isEmpty()); + assertTrue("cleared so it should not contain 'a' key", !s.contains('a')); +} + + +function testAddAll() { + var s = new Set; + var a = new String('a'); + var b = new String('b'); + var c = new String('c'); + var d = new String('d'); + s.addAll([a, b, c, d]); + assertTrue('addAll so it should not be empty', !s.isEmpty()); + assertTrue("addAll so it should contain 'c' key", s.contains(c)); + + var s2 = new Set; + s2.addAll(s); + assertTrue('addAll so it should not be empty', !s2.isEmpty()); + assertTrue("addAll so it should contain 'c' key", s2.contains(c)); + + + s = new Set; + s.addAll(['a', 'b', 'c', 'd']); + assertTrue('addAll so it should not be empty', !s.isEmpty()); + assertTrue("addAll so it should contain 'c' key", s.contains('c')); + + s2 = new Set; + s2.addAll(s); + assertTrue('addAll so it should not be empty', !s2.isEmpty()); + assertTrue("addAll so it should contain 'c' key", s2.contains('c')); +} + + +function testConstructor() { + var s = new Set; + var a = new String('a'); s.add(a); + var b = new String('b'); s.add(b); + var c = new String('c'); s.add(c); + var d = new String('d'); s.add(d); + var s2 = new Set(s); + assertFalse('constr with Set so it should not be empty', s2.isEmpty()); + assertTrue('constr with Set so it should contain c', s2.contains(c)); + + s = new Set; + s.add('a'); + s.add('b'); + s.add('c'); + s.add('d'); + s2 = new Set(s); + assertFalse('constr with Set so it should not be empty', s2.isEmpty()); + assertTrue('constr with Set so it should contain c', s2.contains('c')); +} + + +function testClone() { + var s = new Set; + var a = new String('a'); s.add(a); + var b = new String('b'); s.add(b); + var c = new String('c'); s.add(c); + var d = new String('d'); s.add(d); + + var s2 = s.clone(); + assertFalse('clone so it should not be empty', s2.isEmpty()); + assertTrue("clone so it should contain 'c' key", s2.contains(c)); + + var s = new Set; + s.add('a'); + s.add('b'); + s.add('c'); + s.add('d'); + + s2 = s.clone(); + assertFalse('clone so it should not be empty', s2.isEmpty()); + assertTrue("clone so it should contain 'c' key", s2.contains('c')); +} + + +/** + * Helper method for testEquals(). + * @param {Object} a First element to use in the tests. + * @param {Object} b Second element to use in the tests. + * @param {Object} c Third element to use in the tests. + * @param {Object} d Fourth element to use in the tests. + */ +function helperForTestEquals(a, b, c, d) { + var s = new Set([a, b, c]); + + assertTrue("set == itself", s.equals(s)); + assertTrue("set == same set", s.equals(new Set([a, b, c]))); + assertTrue("set == its clone", s.equals(s.clone())); + assertTrue("set == array of same elements", s.equals([a, b, c])); + assertTrue("set == array of same elements in different order", + s.equals([c, b, a])); + + assertFalse("set != empty set", s.equals(new Set)); + assertFalse("set != its subset", s.equals(new Set([a, c]))); + assertFalse("set != its superset", + s.equals(new Set([a, b, c, d]))); + assertFalse("set != different set", + s.equals(new Set([b, c, d]))); + assertFalse("set != its subset as array", s.equals([a, c])); + assertFalse("set != its superset as array", s.equals([a, b, c, d])); + assertFalse("set != different set as array", s.equals([b, c, d])); + assertFalse("set != [a, b, c, c]", s.equals([a, b, c, c])); + assertFalse("set != [a, b, b]", s.equals([a, b, b])); + assertFalse("set != [a, a]", s.equals([a, a])); +} + + +function testEquals() { + helperForTestEquals(1, 2, 3, 4); + helperForTestEquals('a', 'b', 'c', 'd'); + helperForTestEquals(new String('a'), new String('b'), + new String('c'), new String('d')); +} + + +/** + * Helper method for testIsSubsetOf(). + * @param {Object} a First element to use in the tests. + * @param {Object} b Second element to use in the tests. + * @param {Object} c Third element to use in the tests. + * @param {Object} d Fourth element to use in the tests. + */ +function helperForTestIsSubsetOf(a, b, c, d) { + var s = new Set([a, b, c]); + + assertTrue("set <= itself", s.isSubsetOf(s)); + assertTrue("set <= same set", + s.isSubsetOf(new Set([a, b, c]))); + assertTrue("set <= its clone", s.isSubsetOf(s.clone())); + assertTrue("set <= array of same elements", s.isSubsetOf([a, b, c])); + assertTrue("set <= array of same elements in different order", + s.equals([c, b, a])); + + assertTrue("set <= Set([a, b, c, d])", + s.isSubsetOf(new Set([a, b, c, d]))); + assertTrue("set <= [a, b, c, d]", s.isSubsetOf([a, b, c, d])); + assertTrue("set <= [a, b, c, c]", s.isSubsetOf([a, b, c, c])); + + assertFalse("set !<= Set([a, b])", + s.isSubsetOf(new Set([a, b]))); + assertFalse("set !<= [a, b]", s.isSubsetOf([a, b])); + assertFalse("set !<= Set([c, d])", + s.isSubsetOf(new Set([c, d]))); + assertFalse("set !<= [c, d]", s.isSubsetOf([c, d])); + assertFalse("set !<= Set([a, c, d])", + s.isSubsetOf(new Set([a, c, d]))); + assertFalse("set !<= [a, c, d]", s.isSubsetOf([a, c, d])); + assertFalse("set !<= [a, a, b]", s.isSubsetOf([a, a, b])); + assertFalse("set !<= [a, a, b, b]", s.isSubsetOf([a, a, b, b])); +} + + +function testIsSubsetOf() { + helperForTestIsSubsetOf(1, 2, 3, 4); + helperForTestIsSubsetOf('a', 'b', 'c', 'd'); + helperForTestIsSubsetOf(new String('a'), new String('b'), + new String('c'), new String('d')); +} + + +function testForEach() { + var s = new Set; + var a = new String('a'); s.add(a); + var b = new String('b'); s.add(b); + var c = new String('c'); s.add(c); + var d = new String('d'); s.add(d); + var str = ''; + goog.structs.forEach(s, function(val, key, set) { + assertUndefined(key); + assertEquals(s, set); + str += val; + }); + assertEquals(str, 'abcd'); + + s = new Set; + s.add('a'); + s.add('b'); + s.add('c'); + s.add('d'); + str = ''; + goog.structs.forEach(s, function(val, key, set) { + assertUndefined(key); + assertEquals(s, set); + str += val; + }); + assertEquals(str, 'abcd'); +} + + +function testFilter() { + var s = new Set; + var a = new Number(0); s.add(a); + var b = new Number(1); s.add(b); + var c = new Number(2); s.add(c); + var d = new Number(3); s.add(d); + + var s2 = goog.structs.filter(s, function (val, key, set) { + assertUndefined(key); + assertEquals(s, set); + return val > 1; + }); + assertEquals(stringifySet(s2), '23'); + + s = new Set; + s.add(0); + s.add(1); + s.add(2); + s.add(3); + + s2 = goog.structs.filter(s, function (val, key, set) { + assertUndefined(key); + assertEquals(s, set); + return val > 1; + }); + assertEquals(stringifySet(s2), '23'); +} + + +function testSome() { + var s = new Set; + var a = new Number(0); s.add(a); + var b = new Number(1); s.add(b); + var c = new Number(2); s.add(c); + var d = new Number(3); s.add(d); + + var b = goog.structs.some(s, function (val, key, s2) { + assertUndefined(key); + assertEquals(s, s2); + return val > 1; + }); + assertTrue(b); + var b = goog.structs.some(s, function (val, key, s2) { + assertUndefined(key); + assertEquals(s, s2); + return val > 100; + }); + assertFalse(b); + + s = new Set; + s.add(0); + s.add(1); + s.add(2); + s.add(3); + + b = goog.structs.some(s, function (val, key, s2) { + assertUndefined(key); + assertEquals(s, s2); + return val > 1; + }); + assertTrue(b); + b = goog.structs.some(s, function (val, key, s2) { + assertUndefined(key); + assertEquals(s, s2); + return val > 100; + }); + assertFalse(b); +} + + +function testEvery() { + var s = new Set; + var a = new Number(0); s.add(a); + var b = new Number(1); s.add(b); + var c = new Number(2); s.add(c); + var d = new Number(3); s.add(d); + + var b = goog.structs.every(s, function (val, key, s2) { + assertUndefined(key); + assertEquals(s, s2); + return val >= 0; + }); + assertTrue(b); + b = goog.structs.every(s, function (val, key, s2) { + assertUndefined(key); + assertEquals(s, s2); + return val > 1; + }); + assertFalse(b); + + s = new Set; + s.add(0); + s.add(1); + s.add(2); + s.add(3); + + b = goog.structs.every(s, function (val, key, s2) { + assertUndefined(key); + assertEquals(s, s2); + return val >= 0; + }); + assertTrue(b); + b = goog.structs.every(s, function (val, key, s2) { + assertUndefined(key); + assertEquals(s, s2); + return val > 1; + }); + assertFalse(b); +} + +function testIterator() { + var s = new Set; + s.add(0); + s.add(1); + s.add(2); + s.add(3); + s.add(4); + + assertEquals('01234', goog.iter.join(s, '')); + + s.remove(1); + s.remove(3); + + assertEquals('024', goog.iter.join(s, '')); +} + +</script> +</body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/simplepool.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/simplepool.js.svn-base new file mode 100644 index 0000000..3c13e0a --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/simplepool.js.svn-base @@ -0,0 +1,205 @@ +// Copyright 2007 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Datastructure: Pool. + * + * + * A generic class for handling pools of objects that is more efficient than + * goog.structs.Pool because it doesn't maintain a list of objects that are in + * use. See constructor comment. + */ + + +goog.provide('goog.structs.SimplePool'); + +goog.require('goog.Disposable'); + + + +/** + * A generic pool class. Simpler and more efficient than goog.structs.Pool + * because it doesn't maintain a list of objects that are in use. This class + * has constant overhead and doesn't create any additional objects as part of + * the pool management after construction time. + * + * IMPORTANT: If the objects being pooled are arrays or maps that can have + * unlimited number of properties, they need to be cleaned before being + * returned to the pool. + * + * Also note that {@see goog.object.clean} actually allocates an array to clean + * the object passed to it, so simply using this function would defy the + * purpose of using the pool. + * + * @param {number} initialCount Initial number of objects to populate the + * free pool at construction time. + * @param {number} maxCount Maximum number of objects to keep in the free pool. + * @constructor + * @extends {goog.Disposable} + */ +goog.structs.SimplePool = function(initialCount, maxCount) { + goog.Disposable.call(this); + + /** + * Maximum number of objects allowed + * @type {number} + * @private + */ + this.maxCount_ = maxCount; + + /** + * Queue used to store objects that are currently in the pool and available + * to be used. + * @type {Array} + * @private + */ + this.freeQueue_ = []; + + this.createInitial_(initialCount); +}; +goog.inherits(goog.structs.SimplePool, goog.Disposable); + + +/** + * Function for overriding createObject. The avoids a common case requiring + * subclassing this class. + * @type {Function} + * @private + */ +goog.structs.SimplePool.prototype.createObjectFn_ = null; + + +/** + * Function for overriding disposeObject. The avoids a common case requiring + * subclassing this class. + * @type {Function} + * @private + */ +goog.structs.SimplePool.prototype.disposeObjectFn_ = null; + + +/** + * Sets the {@code createObject} function which is used for creating a new + * object in the pool. + * @param {Function} createObjectFn Create object function which returns the + * newly createrd object. + */ +goog.structs.SimplePool.prototype.setCreateObjectFn = function(createObjectFn) { + this.createObjectFn_ = createObjectFn; +}; + + +/** + * Sets the {@code disposeObject} function which is used for disposing of an + * object in the pool. + * @param {Function} disposeObjectFn Dispose object function which takes the + * object to dispose as a parameter. + */ +goog.structs.SimplePool.prototype.setDisposeObjectFn = function( + disposeObjectFn) { + this.disposeObjectFn_ = disposeObjectFn; +}; + + +/** + * Gets an unused object from the the pool, if there is one available, + * otherwise creates a new one. + * @return {*} An object from the pool or a new one if necessary. + */ +goog.structs.SimplePool.prototype.getObject = function() { + if (this.freeQueue_.length) { + return this.freeQueue_.pop(); + } + return this.createObject(); +}; + + +/** + * Returns an object to the pool so that it can be reused. If the pool is + * already full, the object is disposed instead. + * @param {*} obj The object to release. + */ +goog.structs.SimplePool.prototype.releaseObject = function(obj) { + if (this.freeQueue_.length < this.maxCount_) { + this.freeQueue_.push(obj); + } else { + this.disposeObject(obj); + } +}; + + +/** + * Populates the pool with initialCount objects. + * @param {number} initialCount The number of objects to add to the pool. + * @private + */ +goog.structs.SimplePool.prototype.createInitial_ = function(initialCount) { + if (initialCount > this.maxCount_) { + throw Error('[goog.structs.SimplePool] Initial cannot be greater than max'); + } + for (var i = 0; i < initialCount; i++) { + this.freeQueue_.push(this.createObject()); + } +}; + + +/** + * Should be overriden by sub-classes to return an instance of the object type + * that is expected in the pool. + * @return {*} The created object. + */ +goog.structs.SimplePool.prototype.createObject = function() { + if (this.createObjectFn_) { + return this.createObjectFn_(); + } else { + return {}; + } +}; + + +/** + * Should be overriden to dispose of an object. Default implementation is to + * remove all of the object's members, which should render it useless. Calls the + * object's dispose method, if available. + * @param {*} obj The object to dispose. + */ +goog.structs.SimplePool.prototype.disposeObject = function(obj) { + if (this.disposeObjectFn_) { + this.disposeObjectFn_(obj); + } else if (goog.isObject(obj)) { + if (goog.isFunction(obj.dispose)) { + obj.dispose(); + } else { + for (var i in obj) { + delete obj[i]; + } + } + } +}; + + +/** + * Disposes of the pool and all objects currently held in the pool. + * @override + * @protected + */ +goog.structs.SimplePool.prototype.disposeInternal = function() { + goog.structs.SimplePool.superClass_.disposeInternal.call(this); + // Call disposeObject on each object held by the pool. + var freeQueue = this.freeQueue_; + while (freeQueue.length) { + this.disposeObject(freeQueue.pop()); + } + delete this.freeQueue_; +}; diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/stringset.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/stringset.js.svn-base new file mode 100644 index 0000000..c95ad8c --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/stringset.js.svn-base @@ -0,0 +1,404 @@ +// Copyright 2009 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Data structure for set of strings. + * + * + * This class implements a set data structure for strings. Adding and removing + * is O(1). It doesn't contain any bloat from {@link goog.structs.Set}, i.e. + * it isn't optimized for IE6 garbage collector (see the description of + * {@link goog.structs.Map#keys_} for details), and it distinguishes its + * elements by their string value not by hash code. + */ + +goog.provide('goog.structs.StringSet'); + +goog.require('goog.iter'); + + + +/** + * Creates a set of strings. + * @param {!Array=} opt_elements Elements to add to the set. The non-string + * items will be converted to strings, so 15 and '15' will mean the same. + * @constructor + */ +goog.structs.StringSet = function(opt_elements) { + /** + * An object storing the escaped elements of the set in its keys. + * @type {!Object} + * @private + */ + this.elements_ = {}; + + if (opt_elements) { + for (var i = 0; i < opt_elements.length; i++) { + this.elements_[this.encode(opt_elements[i])] = null; + } + } +}; + + +/** + * Empty object. Referring to it is faster than creating a new empty object in + * {@link #encode}. + * @type {Object} + * @private + */ +goog.structs.StringSet.EMPTY_OBJECT_ = {}; + + +/** + * The '__proto__' and the '__count__' keys aren't enumerable in Firefox, and + * 'toString', 'valueOf', 'constructor', etc. aren't enumerable in IE so they + * have to be escaped before they are added to the internal object. + * NOTE: When a new set is created, 50-80% of the CPU time is spent in encode. + * @param {*} element The element to escape. + * @return {*} The escaped element or the element itself if it doesn't have to + * be escaped. + * @protected + */ +goog.structs.StringSet.prototype.encode = function(element) { + return element in goog.structs.StringSet.EMPTY_OBJECT_ || + String(element).charCodeAt(0) == 32 ? ' ' + element : element; +}; + + +/** + * Inverse function of {@link #encode}. + * NOTE: forEach would be 30% faster in FF if the compiler inlined decode. + * @param {string} key The escaped element used as the key of the internal + * object. + * @return {string} The unescaped element. + * @protected + */ +goog.structs.StringSet.prototype.decode = function(key) { + return key.charCodeAt(0) == 32 ? key.substr(1) : key; +}; + + +/** + * Adds a single element to the set. + * @param {*} element The element to add. It will be converted to string. + */ +goog.structs.StringSet.prototype.add = function(element) { + this.elements_[this.encode(element)] = null; +}; + + +/** + * Adds a the elements of an array to this set. + * @param {!Array} arr The array to add the elements of. + */ +goog.structs.StringSet.prototype.addArray = function(arr) { + for (var i = 0; i < arr.length; i++) { + this.elements_[this.encode(arr[i])] = null; + } +}; + + +/** + * Adds the elements which are in {@code set1} but not in {@code set2} to this + * set. + * @param {!goog.structs.StringSet} set1 First set. + * @param {!goog.structs.StringSet} set2 Second set. + * @private + */ +goog.structs.StringSet.prototype.addDifference_ = function(set1, set2) { + for (var key in set1.elements_) { + if (set1.elements_.hasOwnProperty(key) && + !set2.elements_.hasOwnProperty(key)) { + this.elements_[key] = null; + } + } +}; + + +/** + * Adds a the elements of a set to this set. + * @param {!goog.structs.StringSet} stringSet The set to add the elements of. + */ +goog.structs.StringSet.prototype.addSet = function(stringSet) { + for (var key in stringSet.elements_) { + if (stringSet.elements_.hasOwnProperty(key)) { + this.elements_[key] = null; + } + } +}; + + +/** + * Removes all elements of the set. + */ +goog.structs.StringSet.prototype.clear = function() { + this.elements_ = {}; +}; + + +/** + * @return {!goog.structs.StringSet} Clone of the set. + */ +goog.structs.StringSet.prototype.clone = function() { + var ret = new goog.structs.StringSet; + ret.addSet(this); + return ret; +}; + + +/** + * Tells if the set contains the given element. + * @param {*} element The element to check. + * @return {boolean} Whether it is in the set. + */ +goog.structs.StringSet.prototype.contains = function(element) { + return this.elements_.hasOwnProperty(this.encode(element)); +}; + + +/** + * Tells if the set contains all elements of the array. + * @param {!Array} arr The elements to check. + * @return {boolean} Whether they are in the set. + */ +goog.structs.StringSet.prototype.containsArray = function(arr) { + for (var i = 0; i < arr.length; i++) { + if (!this.elements_.hasOwnProperty(this.encode(arr[i]))) { + return false; + } + } + return true; +}; + + +/** + * Tells if this set has the same elements as the given set. + * @param {!goog.structs.StringSet} stringSet The other set. + * @return {boolean} Whether they have the same elements. + */ +goog.structs.StringSet.prototype.equals = function(stringSet) { + return this.isSubsetOf(stringSet) && stringSet.isSubsetOf(this); +}; + + +/** + * Calls a function for each element in the set. + * @param {function(string, undefined, !goog.structs.StringSet)} f The function + * to call for every element. It takes the element, undefined (because sets + * have no notion of keys), and the set. + * @param {Object=} opt_obj The object to be used as the value of 'this' + * within {@code f}. + */ +goog.structs.StringSet.prototype.forEach = function(f, opt_obj) { + for (var key in this.elements_) { + if (this.elements_.hasOwnProperty(key)) { + f.call(opt_obj, this.decode(key), undefined, this); + } + } +}; + + +/** + * Counts the number of elements in the set in linear time. + * NOTE: getCount is always called at most once per set instance in google3. + * If this usage pattern won't change, the linear getCount implementation is + * better, because + * <li>populating a set and getting the number of elements in it takes the same + * amount of time as keeping a count_ member up to date and getting its value; + * <li>if getCount is not called, adding and removing elements have no overhead. + * @return {number} The number of elements in the set. + */ +goog.structs.StringSet.prototype.getCount = function() { + var count = 0; + for (var key in this.elements_) { + if (this.elements_.hasOwnProperty(key)) { + count++; + } + } + return count; +}; + + +/** + * Calculates the difference of two sets. + * @param {!goog.structs.StringSet} stringSet The set to subtract from this set. + * @return {!goog.structs.StringSet} {@code this} minus {@code stringSet}. + */ +goog.structs.StringSet.prototype.getDifference = function(stringSet) { + var ret = new goog.structs.StringSet; + ret.addDifference_(this, stringSet); + return ret; +}; + + +/** + * Calculates the intersection of this set with another set. + * @param {!goog.structs.StringSet} stringSet The set to take the intersection + * with. + * @return {!goog.structs.StringSet} A new set with the common elements. + */ +goog.structs.StringSet.prototype.getIntersection = function(stringSet) { + var ret = new goog.structs.StringSet; + for (var key in this.elements_) { + if (stringSet.elements_.hasOwnProperty(key) && + this.elements_.hasOwnProperty(key)) { + ret.elements_[key] = null; + } + } + return ret; +}; + + +/** + * Calculates the symmetric difference of two sets. + * @param {!goog.structs.StringSet} stringSet The other set. + * @return {!goog.structs.StringSet} A new set with the elements in exactly one + * of {@code this} and {@code stringSet}. + */ +goog.structs.StringSet.prototype.getSymmetricDifference = function(stringSet) { + var ret = new goog.structs.StringSet; + ret.addDifference_(this, stringSet); + ret.addDifference_(stringSet, this); + return ret; +}; + + +/** + * Calculates the union of this set and another set. + * @param {!goog.structs.StringSet} stringSet The set to take the union with. + * @return {!goog.structs.StringSet} A new set with the union of elements. + */ +goog.structs.StringSet.prototype.getUnion = function(stringSet) { + var ret = this.clone(); + ret.addSet(stringSet); + return ret; +}; + + +/** + * @return {!Array.<string>} The elements of the set. + */ +goog.structs.StringSet.prototype.getValues = function() { + var ret = []; + for (var key in this.elements_) { + if (this.elements_.hasOwnProperty(key)) { + ret.push(this.decode(key)); + } + } + return ret; +}; + + +/** + * Tells if this set and the given set are disjoint. + * @param {!goog.structs.StringSet} stringSet The other set. + * @return {boolean} True iff they don't have common elements. + */ +goog.structs.StringSet.prototype.isDisjoint = function(stringSet) { + for (var key in this.elements_) { + if (stringSet.elements_.hasOwnProperty(key) && + this.elements_.hasOwnProperty(key)) { + return false; + } + } + return true; +}; + + +/** + * @return {boolean} Whether the set is empty. + */ +goog.structs.StringSet.prototype.isEmpty = function() { + for (var key in this.elements_) { + if (this.elements_.hasOwnProperty(key)) { + return false; + } + } + return true; +}; + + +/** + * Tells if this set is the subset of the given set. + * @param {!goog.structs.StringSet} stringSet The other set. + * @return {boolean} Whether this set if the subset of that. + */ +goog.structs.StringSet.prototype.isSubsetOf = function(stringSet) { + for (var key in this.elements_) { + if (!stringSet.elements_.hasOwnProperty(key) && + this.elements_.hasOwnProperty(key)) { + return false; + } + } + return true; +}; + + +/** + * Tells if this set is the superset of the given set. + * @param {!goog.structs.StringSet} stringSet The other set. + * @return {boolean} Whether this set if the superset of that. + */ +goog.structs.StringSet.prototype.isSupersetOf = function(stringSet) { + return this.isSubsetOf.call(stringSet, this); +}; + + +/** + * Removes a single element from the set. + * @param {*} element The element to remove. + * @return {boolean} Whether the element was in the set. + */ +goog.structs.StringSet.prototype.remove = function(element) { + var key = this.encode(element); + if (this.elements_.hasOwnProperty(key)) { + delete this.elements_[key]; + return true; + } + return false; +}; + + +/** + * Removes all elements of the given array from this set. + * @param {!Array} arr The elements to remove. + */ +goog.structs.StringSet.prototype.removeArray = function(arr) { + for (var i = 0; i < arr.length; i++) { + delete this.elements_[this.encode(arr[i])]; + } +}; + + +/** + * Removes all elements of the given set from this set. + * @param {!goog.structs.StringSet} stringSet The set of elements to remove. + */ +goog.structs.StringSet.prototype.removeSet = function(stringSet) { + for (var key in stringSet.elements_) { + delete this.elements_[key]; + } +}; + + +/** + * Returns an iterator that iterates over the elements in the set. + * NOTE: creating the iterator copies the whole set so use {@link #forEach} when + * possible. + * @param {boolean=} opt_keys Ignored for sets. + * @return {!goog.iter.Iterator} An iterator over the elements in the set. + */ +goog.structs.StringSet.prototype.__iterator__ = function(opt_keys) { + return goog.iter.toIterator(this.getValues()); +}; diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/stringset_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/stringset_test.html.svn-base new file mode 100644 index 0000000..804e5eb --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/stringset_test.html.svn-base @@ -0,0 +1,251 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright 2009 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> +<!-- +--> +<head> +<meta http-equiv="X-UA-Compatible" content="IE=edge"> +<title>Closure Unit Tests - goog.structs.StringSet</title> +<script src="../base.js"></script> +<script> + goog.require('goog.array'); + goog.require('goog.iter'); + goog.require('goog.structs.StringSet'); + goog.require('goog.testing.asserts'); + goog.require('goog.testing.jsunit'); +</script> +</head> +<body> +<script> + +// Test how overwritten object prototype affects StringSet. +Object.prototype.evil1 = null; +Object.prototype.evil2 = null; + +var TEST_VALUES = [ + '', ' ', ' ', 'true', 'null', 'undefined', '0', 'new', 'constructor', + 'prototype', '__proto__', 'set', 'hasOwnProperty', 'toString', 'valueOf', + 'evil1' +]; + +var TEST_VALUES_WITH_DUPLICATES = [ + '', '', ' ', ' ', 'true', true, 'null', null, 'undefined', undefined, '0', 0, + 'new', 'constructor', 'prototype', '__proto__', 'set', 'hasOwnProperty', + 'toString', 'valueOf', 'evil1' +]; + +function testConstructor() { + var empty = new goog.structs.StringSet; + assertSameElements('elements in empty set', [], empty.getValues()); + + var s = new goog.structs.StringSet(TEST_VALUES_WITH_DUPLICATES); + assertSameElements('duplicates are filtered out by their string value', + TEST_VALUES, s.getValues()); +} + +function testAdd() { + var s = new goog.structs.StringSet; + goog.array.forEach(TEST_VALUES_WITH_DUPLICATES, s.add, s); + assertSameElements(TEST_VALUES, s.getValues()); +} + +function testAddArray() { + var s = new goog.structs.StringSet; + s.addArray(TEST_VALUES_WITH_DUPLICATES); + assertSameElements('added elements from array', TEST_VALUES, s.getValues()); +} + +function testAddSet() { + var s = new goog.structs.StringSet; + s.addSet(new goog.structs.StringSet([1, 2])); + assertSameElements('empty set + {1, 2}', ['1', '2'], s.getValues()); + s.addSet(new goog.structs.StringSet([2, 3])); + assertSameElements('{1, 2} + {2, 3}', ['1', '2', '3'], s.getValues()); +} + +function testClear() { + var s = new goog.structs.StringSet([1, 2]); + s.clear(); + assertSameElements('cleared set', [], s.getValues()); +} + +function testClone() { + var s = new goog.structs.StringSet([1, 2]); + var c = s.clone(); + assertSameElements('elements in clone', ['1', '2'], c.getValues()); + s.add(3); + assertSameElements('changing the original set does not affect the clone', + ['1', '2'], c.getValues()); +} + +function testContains() { + var e = new goog.structs.StringSet; + goog.array.forEach(TEST_VALUES, function(element) { + assertFalse('empty set does not contain ' + element, e.contains(element)); + }); + + var s = new goog.structs.StringSet(TEST_VALUES); + goog.array.forEach(TEST_VALUES_WITH_DUPLICATES, function(element) { + assertTrue('s contains ' + element, s.contains(element)); + }); + assertFalse('s does not contain 42', s.contains(42)); + + Object.prototype[' a'] = 'a'; + Object.prototype[' a'] = 'a'; + assertFalse('empty set does not contain elements defined in Object.prototype', + new goog.structs.StringSet().contains(' a')); +} + +function testContainsArray() { + var s = new goog.structs.StringSet(TEST_VALUES); + assertTrue('set contains empty array', s.containsArray([])); + assertTrue('set contains all elements of itself with some duplication', + s.containsArray(TEST_VALUES_WITH_DUPLICATES)); + assertFalse('set does not contain 42', s.containsArray([42])); +} + +function testEquals() { + var s = new goog.structs.StringSet([1, 2]); + assertTrue('set equals to itself', s.equals(s)); + assertTrue('set equals to its clone', s.equals(s.clone())); + assertFalse('set does not equal to its subset', + s.equals(new goog.structs.StringSet([1]))); + assertFalse('set does not equal to its superset', + s.equals(new goog.structs.StringSet([1, 2, 3]))); +} + +function testForEach() { + var s = new goog.structs.StringSet(TEST_VALUES); + var values = []; + var context = {}; + s.forEach(function(value, key, stringSet) { + assertEquals('context of forEach callback', context, this); + values.push(value); + assertUndefined('key argument of forEach callback', key); + assertEquals('set argument of forEach callback', s, stringSet); + }, context); + assertSameElements('values passed to forEach callback', TEST_VALUES, values); +} + +function testGetCount() { + var empty = new goog.structs.StringSet; + assertEquals('count(empty set)', 0, empty.getCount()); + + var s = new goog.structs.StringSet(TEST_VALUES); + assertEquals('count(non-empty set)', TEST_VALUES.length, s.getCount()); +} + +function testGetDifference() { + var s1 = new goog.structs.StringSet([1, 2]); + var s2 = new goog.structs.StringSet([2, 3]); + assertSameElements('{1, 2} - {2, 3}', ['1'], + s1.getDifference(s2).getValues()); +} + +function testGetIntersection() { + var s1 = new goog.structs.StringSet([1, 2]); + var s2 = new goog.structs.StringSet([2, 3]); + assertSameElements('{1, 2} * {2, 3}', ['2'], + s1.getIntersection(s2).getValues()); +} + +function testGetSymmetricDifference() { + var s1 = new goog.structs.StringSet([1, 2]); + var s2 = new goog.structs.StringSet([2, 3]); + assertSameElements('{1, 2} sym.diff. {2, 3}', ['1', '3'], + s1.getSymmetricDifference(s2).getValues()); +} + +function testGetUnion() { + var s1 = new goog.structs.StringSet([1, 2]); + var s2 = new goog.structs.StringSet([2, 3]); + assertSameElements('{1, 2} + {2, 3}', ['1', '2', '3'], + s1.getUnion(s2).getValues()); +} + +function testIsDisjoint() { + var s = new goog.structs.StringSet; + var s12 = new goog.structs.StringSet([1, 2]); + var s23 = new goog.structs.StringSet([2, 3]); + var s34 = new goog.structs.StringSet([3, 4]); + + assertTrue('{} and {1, 2} are disjoint', s.isDisjoint(s12)); + assertTrue('{1, 2} and {3, 4} are disjoint', s12.isDisjoint(s34)); + assertFalse('{1, 2} and {2, 3} are not disjoint', s12.isDisjoint(s23)); +} + +function testIsEmpty() { + assertTrue('empty set', new goog.structs.StringSet().isEmpty()); + assertFalse('non-empty set', new goog.structs.StringSet(['']).isEmpty()); +} + +function testIsSubsetOf() { + var s1 = new goog.structs.StringSet([1]); + var s12 = new goog.structs.StringSet([1, 2]); + var s123 = new goog.structs.StringSet([1, 2, 3]); + var s23 = new goog.structs.StringSet([2, 3]); + + assertTrue('{1, 2} is subset of {1, 2}', s12.isSubsetOf(s12)); + assertTrue('{1, 2} is subset of {1, 2, 3}', s12.isSubsetOf(s123)); + assertFalse('{1, 2} is not subset of {1}', s12.isSubsetOf(s1)); + assertFalse('{1, 2} is not subset of {2, 3}', s12.isSubsetOf(s23)); +} + +function testIsSupersetOf() { + var s1 = new goog.structs.StringSet([1]); + var s12 = new goog.structs.StringSet([1, 2]); + var s123 = new goog.structs.StringSet([1, 2, 3]); + var s23 = new goog.structs.StringSet([2, 3]); + + assertTrue('{1, 2} is superset of {1}', s12.isSupersetOf(s1)); + assertTrue('{1, 2} is superset of {1, 2}', s12.isSupersetOf(s12)); + assertFalse('{1, 2} is not superset of {1, 2, 3}', s12.isSupersetOf(s123)); + assertFalse('{1, 2} is not superset of {2, 3}', s12.isSupersetOf(s23)); +} + +function testRemove() { + var n = new goog.structs.StringSet([1, 2]); + assertFalse('3 not removed from {1, 2}', n.remove(3)); + assertSameElements('set == {1, 2}', ['1', '2'], n.getValues()); + assertTrue('2 removed from {1, 2}', n.remove(2)); + assertSameElements('set == {1}', ['1'], n.getValues()); + assertTrue('"1" removed from {1}', n.remove('1')); + assertSameElements('set == {}', [], n.getValues()); + + var s = new goog.structs.StringSet(TEST_VALUES); + goog.array.forEach(TEST_VALUES, s.remove, s); + assertSameElements('all special values have been removed', [], s.getValues()); +} + +function testRemoveArray() { + var s = new goog.structs.StringSet(TEST_VALUES); + s.removeArray(TEST_VALUES.slice(0, TEST_VALUES.length - 2)); + assertSameElements('removed elements from array', + TEST_VALUES.slice(TEST_VALUES.length - 2), s.getValues()); +} + +function testRemoveSet() { + var s1 = new goog.structs.StringSet([1, 2]); + var s2 = new goog.structs.StringSet([2, 3]); + s1.removeSet(s2); + assertSameElements('{1, 2} - {2, 3}', ['1'], s1.getValues()); +} + +function testIterator() { + var s = new goog.structs.StringSet(TEST_VALUES_WITH_DUPLICATES); + var values = [] + goog.iter.forEach(s, function(value) { + values.push(value); + }); + assertSameElements('__iterator__ takes all elements once', + TEST_VALUES, values); +} + +</script> +</body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/structs.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/structs.js.svn-base new file mode 100644 index 0000000..ec39582 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/structs.js.svn-base @@ -0,0 +1,342 @@ +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Generics method for collection-like classes and objects. + * + * @author arv@google.com (Erik Arvidsson) + * + * This file contains functions to work with collections. It supports using + * Map, Set, Array and Object and other classes that implement collection-like + * methods. + */ + + +goog.provide('goog.structs'); + +goog.require('goog.array'); +goog.require('goog.object'); + + +// We treat an object as a dictionary if it has getKeys or it is an object that +// isn't arrayLike. + + +/** + * Returns the number of values in the collection-like object. + * @param {Object} col The collection-like object. + * @return {number} The number of values in the collection-like object. + */ +goog.structs.getCount = function(col) { + if (typeof col.getCount == 'function') { + return col.getCount(); + } + if (goog.isArrayLike(col) || goog.isString(col)) { + return col.length; + } + return goog.object.getCount(col); +}; + + +/** + * Returns the values of the collection-like object. + * @param {Object} col The collection-like object. + * @return {!Array} The values in the collection-like object. + */ +goog.structs.getValues = function(col) { + if (typeof col.getValues == 'function') { + return col.getValues(); + } + if (goog.isString(col)) { + return col.split(''); + } + if (goog.isArrayLike(col)) { + var rv = []; + var l = col.length; + for (var i = 0; i < l; i++) { + rv.push(col[i]); + } + return rv; + } + return goog.object.getValues(col); +}; + + +/** + * Returns the keys of the collection. Some collections have no notion of + * keys/indexes and this function will return undefined in those cases. + * @param {Object} col The collection-like object. + * @return {!Array|undefined} The keys in the collection. + */ +goog.structs.getKeys = function(col) { + if (typeof col.getKeys == 'function') { + return col.getKeys(); + } + // if we have getValues but no getKeys we know this is a key-less collection + if (typeof col.getValues == 'function') { + return undefined; + } + if (goog.isArrayLike(col) || goog.isString(col)) { + var rv = []; + var l = col.length; + for (var i = 0; i < l; i++) { + rv.push(i); + } + return rv; + } + + return goog.object.getKeys(col); +}; + + +/** + * Whether the collection contains the given value. This is O(n) and uses + * equals (==) to test the existence. + * @param {Object} col The collection-like object. + * @param {*} val The value to check for. + * @return {boolean} True if the map contains the value. + */ +goog.structs.contains = function(col, val) { + if (typeof col.contains == 'function') { + return col.contains(val); + } + if (typeof col.containsValue == 'function') { + return col.containsValue(val); + } + if (goog.isArrayLike(col) || goog.isString(col)) { + return goog.array.contains(/** @type {Array} */ (col), val); + } + return goog.object.containsValue(col, val); +}; + + +/** + * Whether the collection is empty. + * @param {Object} col The collection-like object. + * @return {boolean} True if empty. + */ +goog.structs.isEmpty = function(col) { + if (typeof col.isEmpty == 'function') { + return col.isEmpty(); + } + + // We do not use goog.string.isEmpty because here we treat the string as + // collection and as such even whitespace matters + + if (goog.isArrayLike(col) || goog.isString(col)) { + return goog.array.isEmpty(/** @type {Array} */ (col)); + } + return goog.object.isEmpty(col); +}; + + +/** + * Removes all the elements from the collection. + * @param {Object} col The collection-like object. + */ +goog.structs.clear = function(col) { + // NOTE(arv): This should not contain strings because strings are immutable + if (typeof col.clear == 'function') { + col.clear(); + } else if (goog.isArrayLike(col)) { + goog.array.clear((/** @type {goog.array.ArrayLike} */ col)); + } else { + goog.object.clear(col); + } +}; + + +/** + * Calls a function for each value in a collection. The function takes + * three arguments; the value, the key and the collection. + * + * @param {Object} col The collection-like object. + * @param {Function} f The function to call for every value. This function takes + * 3 arguments (the value, the key or undefined if the collection has no + * notion of keys, and the collection) and the return value is irrelevant. + * @param {Object=} opt_obj The object to be used as the value of 'this' + * within {@code f}. + */ +goog.structs.forEach = function(col, f, opt_obj) { + if (typeof col.forEach == 'function') { + col.forEach(f, opt_obj); + } else if (goog.isArrayLike(col) || goog.isString(col)) { + goog.array.forEach(/** @type {Array} */ (col), f, opt_obj); + } else { + var keys = goog.structs.getKeys(col); + var values = goog.structs.getValues(col); + var l = values.length; + for (var i = 0; i < l; i++) { + f.call(opt_obj, values[i], keys && keys[i], col); + } + } +}; + + +/** + * Calls a function for every value in the collection. When a call returns true, + * adds the value to a new collection (Array is returned by default). + * + * @param {Object} col The collection-like object. + * @param {Function} f The function to call for every value. This function takes + * 3 arguments (the value, the key or undefined if the collection has no + * notion of keys, and the collection) and should return a Boolean. If the + * return value is true the value is added to the result collection. If it + * is false the value is not included. + * @param {Object=} opt_obj The object to be used as the value of 'this' + * within {@code f}. + * @return {!Object|!Array} A new collection where the passed values are + * present. If col is a key-less collection an array is returned. If col + * has keys and values a plain old JS object is returned. + */ +goog.structs.filter = function(col, f, opt_obj) { + if (typeof col.filter == 'function') { + return col.filter(f, opt_obj); + } + if (goog.isArrayLike(col) || goog.isString(col)) { + return goog.array.filter(/** @type {!Array} */ (col), f, opt_obj); + } + + var rv; + var keys = goog.structs.getKeys(col); + var values = goog.structs.getValues(col); + var l = values.length; + if (keys) { + rv = {}; + for (var i = 0; i < l; i++) { + if (f.call(opt_obj, values[i], keys[i], col)) { + rv[keys[i]] = values[i]; + } + } + } else { + // We should not use goog.array.filter here since we want to make sure that + // the index is undefined as well as make sure that col is passed to the + // function. + rv = []; + for (var i = 0; i < l; i++) { + if (f.call(opt_obj, values[i], undefined, col)) { + rv.push(values[i]); + } + } + } + return rv; +}; + + +/** + * Calls a function for every value in the collection and adds the result into a + * new collection (defaults to creating a new Array). + * + * @param {Object} col The collection-like object. + * @param {Function} f The function to call for every value. This function + * takes 3 arguments (the value, the key or undefined if the collection has + * no notion of keys, and the collection) and should return something. The + * result will be used as the value in the new collection. + * @param {Object=} opt_obj The object to be used as the value of 'this' + * within {@code f}. + * @return {!Object|!Array} A new collection with the new values. If col is a + * key-less collection an array is returned. If col has keys and values a + * plain old JS object is returned. + */ +goog.structs.map = function(col, f, opt_obj) { + if (typeof col.map == 'function') { + return col.map(f, opt_obj); + } + if (goog.isArrayLike(col) || goog.isString(col)) { + return goog.array.map(/** @type {!Array} */ (col), f, opt_obj); + } + + var rv; + var keys = goog.structs.getKeys(col); + var values = goog.structs.getValues(col); + var l = values.length; + if (keys) { + rv = {}; + for (var i = 0; i < l; i++) { + rv[keys[i]] = f.call(opt_obj, values[i], keys[i], col); + } + } else { + // We should not use goog.array.map here since we want to make sure that + // the index is undefined as well as make sure that col is passed to the + // function. + rv = []; + for (var i = 0; i < l; i++) { + rv[i] = f.call(opt_obj, values[i], undefined, col); + } + } + return rv; +}; + + +/** + * Calls f for each value in a collection. If any call returns true this returns + * true (without checking the rest). If all returns false this returns false. + * + * @param {Object|Array|string} col The collection-like object. + * @param {Function} f The function to call for every value. This function takes + * 3 arguments (the value, the key or undefined if the collection has no + * notion of keys, and the collection) and should return a Boolean. + * @param {Object=} opt_obj The object to be used as the value of 'this' + * within {@code f}. + * @return {boolean} True if any value passes the test. + */ +goog.structs.some = function(col, f, opt_obj) { + if (typeof col.some == 'function') { + return col.some(f, opt_obj); + } + if (goog.isArrayLike(col) || goog.isString(col)) { + return goog.array.some(/** @type {!Array} */ (col), f, opt_obj); + } + var keys = goog.structs.getKeys(col); + var values = goog.structs.getValues(col); + var l = values.length; + for (var i = 0; i < l; i++) { + if (f.call(opt_obj, values[i], keys && keys[i], col)) { + return true; + } + } + return false; +}; + + +/** + * Calls f for each value in a collection. If all calls return true this return + * true this returns true. If any returns false this returns false at this point + * and does not continue to check the remaining values. + * + * @param {Object} col The collection-like object. + * @param {Function} f The function to call for every value. This function takes + * 3 arguments (the value, the key or undefined if the collection has no + * notion of keys, and the collection) and should return a Boolean. + * @param {Object=} opt_obj The object to be used as the value of 'this' + * within {@code f}. + * @return {boolean} True if all key-value pairs pass the test. + */ +goog.structs.every = function(col, f, opt_obj) { + if (typeof col.every == 'function') { + return col.every(f, opt_obj); + } + if (goog.isArrayLike(col) || goog.isString(col)) { + return goog.array.every(/** @type {!Array} */ (col), f, opt_obj); + } + var keys = goog.structs.getKeys(col); + var values = goog.structs.getValues(col); + var l = values.length; + for (var i = 0; i < l; i++) { + if (!f.call(opt_obj, values[i], keys && keys[i], col)) { + return false; + } + } + return true; +}; diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/structs_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/structs_test.html.svn-base new file mode 100644 index 0000000..fb9fe78 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/structs_test.html.svn-base @@ -0,0 +1,1050 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright 2006 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> +<head> +<meta http-equiv="X-UA-Compatible" content="IE=edge"> +<title>Closure Unit Tests - goog.structs</title> +<script src="../base.js"></script> +<script> + goog.require('goog.array'); + goog.require('goog.object'); + goog.require('goog.structs'); + goog.require('goog.structs.Set'); // needed for filter + goog.require('goog.structs.Map'); + goog.require('goog.testing.jsunit'); +</script> +</head> +<body> +<!-- test container with 10 elements inside, 1 hr and 1 h1 with id h1 --> +<div id="test"> + <hr> + <p>Paragraph 0</p> + <p>Paragraph 1</p> + <p>Paragraph 2</p> + <p>Paragraph 3</p> + <p>Paragraph 4</p> + <p>Paragraph 5</p> + <p>Paragraph 6</p> + <p>Paragraph 7</p> + <h1 id="h1">Header</h1> +</div> + + +<script> + +/* + + This one does not test Map or Set + It tests Array, Object, String and a NodeList + +*/ + + + +function stringifyObject(obj) { + var sb = []; + for (var key in obj) { + sb.push(key + obj[key]); + } + return sb.join(''); +} + + +function getTestElement() { + return document.getElementById('test'); +} + + +function getAll() { + return getTestElement().getElementsByTagName('*') +} + + +var node; + + +function addNode() { + node = document.createElement('span'); + getTestElement().appendChild(node); +} + + +function removeNode() { + getTestElement().removeChild(node); +} + + +function nodeNames(nl) { + var sb = []; + for (var i = 0, n; n = nl[i]; i++) { + sb.push(n.nodeName.toLowerCase()); + } + return sb.join(','); +} + + +var allTagNames1 = 'hr,p,p,p,p,p,p,p,p,h1'; +var allTagNames2 = allTagNames1 + ',span'; + + +function testGetCount() { + var arr = ['a', 'b', 'c']; + assertEquals('count, should be 3', 3, goog.structs.getCount(arr)); + arr.push('d'); + assertEquals('count, should be 4', 4, goog.structs.getCount(arr)); + goog.array.remove(arr, 'd'); + assertEquals('count, should be 3', 3, goog.structs.getCount(arr)); + + var obj = {a: 0, b: 1, c: 2}; + assertEquals('count, should be 3', 3, goog.structs.getCount(obj)); + obj.d = 3; + assertEquals('count, should be 4', 4, goog.structs.getCount(obj)); + delete obj.d; + assertEquals('count, should be 3', 3, goog.structs.getCount(obj)); + + var s = 'abc'; + assertEquals('count, should be 3', 3, goog.structs.getCount(s)); + s += 'd'; + assertEquals('count, should be 4', 4, goog.structs.getCount(s)); + + var all = getAll(); + assertEquals('count, should be 10', 10, goog.structs.getCount(all)); + addNode(); + assertEquals('count, should be 11', 11, goog.structs.getCount(all)); + removeNode(); + assertEquals('count, should be 10', 10, goog.structs.getCount(all)); + + var aMap = new goog.structs.Map({a: 0, b: 1, c: 2}); + assertEquals('count, should be 3', 3, goog.structs.getCount(aMap)); + aMap.set('d', 3); + assertEquals('count, should be 4', 4, goog.structs.getCount(aMap)); + aMap.remove('a'); + assertEquals('count, should be 3', 3, goog.structs.getCount(aMap)); + + var aSet = new goog.structs.Set('abc'); + assertEquals('count, should be 3', 3, goog.structs.getCount(aSet)); + aSet.add('d'); + assertEquals('count, should be 4', 4, goog.structs.getCount(aSet)); + aSet.remove('a'); + assertEquals('count, should be 3', 3, goog.structs.getCount(aSet)); +} + + +function testGetValues() { + var arr = ['a', 'b', 'c', 'd']; + assertEquals('abcd', goog.structs.getValues(arr).join('')); + + var obj = {a: 0, b: 1, c: 2, d: 3}; + assertEquals('0123', goog.structs.getValues(obj).join('')); + + var s = 'abc'; + assertEquals('abc', goog.structs.getValues(s).join('')); + s += 'd'; + assertEquals('abcd', goog.structs.getValues(s).join('')); + + var all = getAll(); + assertEquals(allTagNames1, nodeNames(goog.structs.getValues(all))); + addNode(); + assertEquals(allTagNames2, nodeNames(goog.structs.getValues(all))); + removeNode(); + assertEquals(allTagNames1, nodeNames(goog.structs.getValues(all))); + + var aMap = new goog.structs.Map({a: 1, b: 2, c: 3}); + assertEquals('123', goog.structs.getValues(aMap).join('')); + + var aSet = new goog.structs.Set([1, 2, 3]); + assertEquals('123', goog.structs.getValues(aMap).join('')); +} + + +function testGetKeys() { + var arr = ['a', 'b', 'c', 'd']; + assertEquals('0123', goog.structs.getKeys(arr).join('')); + + var obj = {a: 0, b: 1, c: 2, d: 3}; + assertEquals('abcd', goog.structs.getKeys(obj).join('')); + + var s = 'abc'; + assertEquals('012', goog.structs.getKeys(s).join('')); + s += 'd'; + assertEquals('0123', goog.structs.getKeys(s).join('')); + + var all = getAll(); + assertEquals('0123456789', goog.structs.getKeys(all).join('')); + addNode(); + assertEquals('012345678910', goog.structs.getKeys(all).join('')); + removeNode(); + assertEquals('0123456789', goog.structs.getKeys(all).join('')); + + var aMap = new goog.structs.Map({a: 1, b: 2, c: 3}); + assertEquals('abc', goog.structs.getKeys(aMap).join('')); + + var aSet = new goog.structs.Set([1, 2, 3]); + assertUndefined(goog.structs.getKeys(aSet)); +} + +function testContains() { + var arr = ['a', 'b', 'c', 'd']; + assertTrue("contains, Should contain 'a'", goog.structs.contains(arr, 'a')); + assertFalse("contains, Should not contain 'e'", goog.structs.contains(arr, 'e')); + + var obj = {a: 0, b: 1, c: 2, d: 3}; + assertTrue("contains, Should contain '0'", goog.structs.contains(obj, 0)); + assertFalse("contains, Should not contain '4'", goog.structs.contains(obj, 4)); + + var s = 'abc'; + assertTrue("contains, Should contain 'a'", goog.structs.contains(s, 'a')); + assertFalse("contains, Should not contain 'd'", goog.structs.contains(s, 'd')); + + var all = getAll(); + assertTrue("contains, Should contain 'h1'", + goog.structs.contains(all, document.getElementById('h1'))); + assertFalse("contains, Should not contain 'document.body'", + goog.structs.contains(all, document.body)); + + var aMap = new goog.structs.Map({a: 1, b: 2, c: 3}); + assertTrue("contains, Should contain '1'", goog.structs.contains(aMap, 1)); + assertFalse("contains, Should not contain '4'", goog.structs.contains(aMap, 4)); + + var aSet = new goog.structs.Set([1, 2, 3]); + assertTrue("contains, Should contain '1'", goog.structs.contains(aSet, 1)); + assertFalse("contains, Should not contain '4'", goog.structs.contains(aSet, 4)); +} + + +function testClear() { + var arr = ['a', 'b', 'c', 'd']; + goog.structs.clear(arr); + assertTrue('cleared so it should be empty', goog.structs.isEmpty(arr)); + assertFalse("cleared so it should not contain 'a'", goog.structs.contains(arr, 'a')); + + var obj = {a: 0, b: 1, c: 2, d: 3}; + goog.structs.clear(obj); + assertTrue('cleared so it should be empty', goog.structs.isEmpty(obj)); + assertFalse("cleared so it should not contain 'a' key", goog.structs.contains(obj, 0)); + + var aMap = new goog.structs.Map({a: 1, b: 2, c: 3}); + goog.structs.clear(aMap); + assertTrue('cleared map so it should be empty', goog.structs.isEmpty(aMap)); + assertFalse("cleared map so it should not contain '1' value", + goog.structs.contains(aMap, 1)); + + var aSet = new goog.structs.Set([1, 2, 3]); + goog.structs.clear(aSet); + assertTrue('cleared set so it should be empty', goog.structs.isEmpty(aSet)); + assertFalse("cleared set so it should not contain '1'", goog.structs.contains(aSet, 1)); + + // cannot clear a string or a NodeList +} + + + +// Map + +function testMap() { + var RV = {}; + var obj = { + map: function(g) { + assertEquals(f, g); + assertEquals(this, obj); + return RV; + } + }; + function f() {} + assertEquals(RV, goog.structs.map(obj, f)); +} + +function testMap2() { + var THIS_OBJ = {}; + var RV = {}; + var obj = { + map: function(g, obj2) { + assertEquals(f, g); + assertEquals(this, obj); + assertEquals(THIS_OBJ, obj2); + return RV; + } + }; + function f() {} + assertEquals(RV, goog.structs.map(obj, f, THIS_OBJ)); +} + +function testMapArrayLike() { + var col = [0, 1, 2]; + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + return v * v; + } + assertArrayEquals([0, 1, 4], goog.structs.map(col, f)); +} + +function testMapArrayLike2() { + var THIS_OBJ = {}; + var col = [0, 1, 2]; + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + assertEquals(THIS_OBJ, this); + return v * v; + } + assertArrayEquals([0, 1, 4], goog.structs.map(col, f, THIS_OBJ)); +} + +function testMapString() { + var col = '012'; + function f(v, i, col2) { + // Teh SpiderMonkey Array.map for strings turns the string into a String + // so we cannot use assertEquals because it uses ===. + assertTrue(col == col2); + assertEquals('number', typeof i); + return Number(v) * Number(v); + } + assertArrayEquals([0, 1, 4], goog.structs.map(col, f)); +} + +function testMapString2() { + var THIS_OBJ = {}; + var col = '012'; + function f(v, i, col2) { + // for some reason the strings are equal but identical??? + assertEquals(String(col), String(col2)); + assertEquals('number', typeof i); + assertEquals(THIS_OBJ, this); + return Number(v) * Number(v); + } + assertArrayEquals([0, 1, 4], goog.structs.map(col, f, THIS_OBJ)); +} + +function testMapMap() { + var col = new goog.structs.Map({a: 0, b: 1, c: 2}); + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('string', typeof key); + return v * v; + } + assertObjectEquals({a: 0, b: 1, c: 4}, goog.structs.map(col, f)); +} + +function testMapMap2() { + var THIS_OBJ = {}; + var col = new goog.structs.Map({a: 0, b: 1, c: 2}); + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('string', typeof key); + assertEquals(THIS_OBJ, this); + return v * v; + } + assertObjectEquals({a: 0, b: 1, c: 4}, goog.structs.map(col, f, THIS_OBJ)); +} + +function testMapSet() { + var col = new goog.structs.Set([0, 1, 2]); + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('undefined', typeof key); + return v * v; + } + assertArrayEquals([0, 1, 4], goog.structs.map(col, f)); +} + +function testMapSet2() { + var THIS_OBJ = {}; + var col = new goog.structs.Set([0, 1, 2]); + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('undefined', typeof key); + assertEquals(THIS_OBJ, this); + return v * v; + } + assertArrayEquals([0, 1, 4], goog.structs.map(col, f, THIS_OBJ)); +} + +function testMapNodeList() { + var col = getAll(); + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + return v.tagName; + } + assertEquals('HRPPPPPPPPH1', goog.structs.map(col, f).join('')); +} + +function testMapNodeList2() { + var THIS_OBJ = {}; + var col = getAll(); + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + assertEquals(THIS_OBJ, this); + return v.tagName; + } + assertEquals('HRPPPPPPPPH1', goog.structs.map(col, f, THIS_OBJ).join('')); +} + +// Filter + +function testFilter() { + var RV = {}; + var obj = { + filter: function(g) { + assertEquals(f, g); + assertEquals(this, obj); + return RV; + } + }; + function f() {} + assertEquals(RV, goog.structs.filter(obj, f)); +} + +function testFilter2() { + var THIS_OBJ = {}; + var RV = {}; + var obj = { + filter: function(g, obj2) { + assertEquals(f, g); + assertEquals(this, obj); + assertEquals(THIS_OBJ, obj2); + return RV; + } + }; + function f() {} + assertEquals(RV, goog.structs.filter(obj, f, THIS_OBJ)); +} + +function testFilterArrayLike() { + var col = [0, 1, 2]; + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + return v > 0; + } + assertArrayEquals([1, 2], goog.structs.filter(col, f)); +} + +function testFilterArrayLike2() { + var THIS_OBJ = {}; + var col = [0, 1, 2]; + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + assertEquals(THIS_OBJ, this); + return v > 0; + } + assertArrayEquals([1, 2], goog.structs.filter(col, f, THIS_OBJ)); +} + +function testFilterString() { + var col = '012'; + function f(v, i, col2) { + // for some reason the strings are equal but identical??? + assertEquals(String(col), String(col2)); + assertEquals('number', typeof i); + return Number(v) > 0; + } + assertArrayEquals(['1', '2'], goog.structs.filter(col, f)); +} + +function testFilterString2() { + var THIS_OBJ = {}; + var col = '012'; + function f(v, i, col2) { + // for some reason the strings are equal but identical??? + assertEquals(String(col), String(col2)); + assertEquals('number', typeof i); + assertEquals(THIS_OBJ, this); + return Number(v) > 0; + } + assertArrayEquals(['1', '2'], goog.structs.filter(col, f, THIS_OBJ)); +} + +function testFilterMap() { + var col = new goog.structs.Map({a: 0, b: 1, c: 2}); + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('string', typeof key); + return v > 0; + } + assertObjectEquals({b: 1, c: 2}, goog.structs.filter(col, f)); +} + +function testFilterMap2() { + var THIS_OBJ = {}; + var col = new goog.structs.Map({a: 0, b: 1, c: 2}); + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('string', typeof key); + assertEquals(THIS_OBJ, this); + return v > 0; + } + assertObjectEquals({b: 1, c: 2}, goog.structs.filter(col, f, THIS_OBJ)); +} + +function testFilterSet() { + var col = new goog.structs.Set([0, 1, 2]); + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('undefined', typeof key); + return v > 0; + } + assertArrayEquals([1, 2], goog.structs.filter(col, f)); +} + +function testFilterSet2() { + var THIS_OBJ = {}; + var col = new goog.structs.Set([0, 1, 2]); + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('undefined', typeof key); + assertEquals(THIS_OBJ, this); + return v > 0; + } + assertArrayEquals([1, 2], goog.structs.filter(col, f, THIS_OBJ)); +} + +function testFilterNodeList() { + var col = getAll(); + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + return v.tagName == 'P'; + } + assertEquals('p,p,p,p,p,p,p,p', + nodeNames(goog.structs.filter(col, f))); +} + +function testFilterNodeList2() { + var THIS_OBJ = {}; + var col = getAll(); + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + assertEquals(THIS_OBJ, this); + return v.tagName == 'P'; + } + assertEquals('p,p,p,p,p,p,p,p', + nodeNames(goog.structs.filter(col, f, THIS_OBJ))); +} + +// Some + +function testSome() { + var RV = {}; + var obj = { + some: function(g) { + assertEquals(f, g); + assertEquals(this, obj); + return RV; + } + }; + function f() {} + assertEquals(RV, goog.structs.some(obj, f)); +} + +function testSome2() { + var THIS_OBJ = {}; + var RV = {}; + var obj = { + some: function(g, obj2) { + assertEquals(f, g); + assertEquals(this, obj); + assertEquals(THIS_OBJ, obj2); + return RV; + } + }; + function f() {} + assertEquals(RV, goog.structs.some(obj, f, THIS_OBJ)); +} + +function testSomeArrayLike() { + var limit = 0; + var col = [0, 1, 2]; + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + return v > limit; + } + assertTrue(goog.structs.some(col, f)); + limit = 2; + assertFalse(goog.structs.some(col, f)); +} + +function testSomeArrayLike2() { + var THIS_OBJ = {}; + var limit = 0; + var col = [0, 1, 2]; + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + assertEquals(THIS_OBJ, this); + return v > limit; + } + assertTrue(goog.structs.some(col, f, THIS_OBJ)); + limit = 2; + assertFalse(goog.structs.some(col, f, THIS_OBJ)); +} + +function testSomeString() { + var limit = 0; + var col = '012'; + function f(v, i, col2) { + // for some reason the strings are equal but identical??? + assertEquals(String(col), String(col2)); + assertEquals('number', typeof i); + return Number(v) > limit; + } + assertTrue(goog.structs.some(col, f)); + limit = 2; + assertFalse(goog.structs.some(col, f)); +} + +function testSomeString2() { + var THIS_OBJ = {}; + var limit = 0; + var col = '012'; + function f(v, i, col2) { + // for some reason the strings are equal but identical??? + assertEquals(String(col), String(col2)); + assertEquals('number', typeof i); + assertEquals(THIS_OBJ, this); + return Number(v) > limit; + } + assertTrue(goog.structs.some(col, f, THIS_OBJ)); + limit = 2; + assertFalse(goog.structs.some(col, f, THIS_OBJ)); +} + +function testSomeMap() { + var limit = 0; + var col = new goog.structs.Map({a: 0, b: 1, c: 2}); + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('string', typeof key); + return v > limit; + } + assertObjectEquals(true, goog.structs.some(col, f)); + limit = 2; + assertFalse(goog.structs.some(col, f)); +} + +function testSomeMap2() { + var THIS_OBJ = {}; + var limit = 0; + var col = new goog.structs.Map({a: 0, b: 1, c: 2}); + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('string', typeof key); + assertEquals(THIS_OBJ, this); + return v > limit; + } + assertObjectEquals(true, goog.structs.some(col, f, THIS_OBJ)); + limit = 2; + assertFalse(goog.structs.some(col, f, THIS_OBJ)); +} + +function testSomeSet() { + var limit = 0; + var col = new goog.structs.Set([0, 1, 2]); + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('undefined', typeof key); + return v > limit; + } + assertTrue(goog.structs.some(col, f)); + limit = 2; + assertFalse(goog.structs.some(col, f)); +} + +function testSomeSet2() { + var THIS_OBJ = {}; + var limit = 0; + var col = new goog.structs.Set([0, 1, 2]); + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('undefined', typeof key); + assertEquals(THIS_OBJ, this); + return v > limit; + } + assertTrue(goog.structs.some(col, f, THIS_OBJ)); + limit = 2; + assertFalse(goog.structs.some(col, f, THIS_OBJ)); +} + +function testSomeNodeList() { + var tagName = 'P'; + var col = getAll(); + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + return v.tagName == tagName; + } + assertTrue(goog.structs.some(col, f)); + tagName = 'MARQUEE'; + assertFalse(goog.structs.some(col, f)); +} + +function testSomeNodeList2() { + var THIS_OBJ = {}; + var tagName = 'P'; + var col = getAll(); + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + assertEquals(THIS_OBJ, this); + return v.tagName == tagName; + } + assertTrue(goog.structs.some(col, f, THIS_OBJ)); + tagName = 'MARQUEE'; + assertFalse(goog.structs.some(col, f, THIS_OBJ)); +} + +// Every + +function testEvery() { + var RV = {}; + var obj = { + every: function(g) { + assertEquals(f, g); + assertEquals(this, obj); + return RV; + } + }; + function f() {} + assertEquals(RV, goog.structs.every(obj, f)); +} + +function testEvery2() { + var THIS_OBJ = {}; + var RV = {}; + var obj = { + every: function(g, obj2) { + assertEquals(f, g); + assertEquals(this, obj); + assertEquals(THIS_OBJ, obj2); + return RV; + } + }; + function f() {} + assertEquals(RV, goog.structs.every(obj, f, THIS_OBJ)); +} + +function testEveryArrayLike() { + var limit = -1; + var col = [0, 1, 2]; + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + return v > limit; + } + assertTrue(goog.structs.every(col, f)); + limit = 1; + assertFalse(goog.structs.every(col, f)); +} + +function testEveryArrayLike2() { + var THIS_OBJ = {}; + var limit = -1; + var col = [0, 1, 2]; + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + assertEquals(THIS_OBJ, this); + return v > limit; + } + assertTrue(goog.structs.every(col, f, THIS_OBJ)); + limit = 1; + assertFalse(goog.structs.every(col, f, THIS_OBJ)); +} + +function testEveryString() { + var limit = -1; + var col = '012'; + function f(v, i, col2) { + // for some reason the strings are equal but identical??? + assertEquals(String(col), String(col2)); + assertEquals('number', typeof i); + return Number(v) > limit; + } + assertTrue(goog.structs.every(col, f)); + limit = 1; + assertFalse(goog.structs.every(col, f)); +} + +function testEveryString2() { + var THIS_OBJ = {}; + var limit = -1; + var col = '012'; + function f(v, i, col2) { + // for some reason the strings are equal but identical??? + assertEquals(String(col), String(col2)); + assertEquals('number', typeof i); + assertEquals(THIS_OBJ, this); + return Number(v) > limit; + } + assertTrue(goog.structs.every(col, f, THIS_OBJ)); + limit = 1; + assertFalse(goog.structs.every(col, f, THIS_OBJ)); +} + +function testEveryMap() { + var limit = -1; + var col = new goog.structs.Map({a: 0, b: 1, c: 2}); + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('string', typeof key); + return v > limit; + } + assertObjectEquals(true, goog.structs.every(col, f)); + limit = 1; + assertFalse(goog.structs.every(col, f)); +} + +function testEveryMap2() { + var THIS_OBJ = {}; + var limit = -1; + var col = new goog.structs.Map({a: 0, b: 1, c: 2}); + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('string', typeof key); + assertEquals(THIS_OBJ, this); + return v > limit; + } + assertObjectEquals(true, goog.structs.every(col, f, THIS_OBJ)); + limit = 1; + assertFalse(goog.structs.every(col, f, THIS_OBJ)); +} + +function testEverySet() { + var limit = -1; + var col = new goog.structs.Set([0, 1, 2]); + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('undefined', typeof key); + return v > limit; + } + assertTrue(goog.structs.every(col, f)); + limit = 1; + assertFalse(goog.structs.every(col, f)); +} + +function testEverySet2() { + var THIS_OBJ = {}; + var limit = -1; + var col = new goog.structs.Set([0, 1, 2]); + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('undefined', typeof key); + assertEquals(THIS_OBJ, this); + return v > limit; + } + assertTrue(goog.structs.every(col, f, THIS_OBJ)); + limit = 1; + assertFalse(goog.structs.every(col, f, THIS_OBJ)); +} + +function testEveryNodeList() { + var nodeType = 1; // ELEMENT + var col = getAll(); + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + return v.nodeType == nodeType; + } + assertTrue(goog.structs.every(col, f)); + nodeType = 3; // TEXT + assertFalse(goog.structs.every(col, f)); +} + +function testEveryNodeList2() { + var THIS_OBJ = {}; + var nodeType = 1; // ELEMENT + var col = getAll(); + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + assertEquals(THIS_OBJ, this); + return v.nodeType == nodeType; + } + assertTrue(goog.structs.every(col, f, THIS_OBJ)); + nodeType = 3; // TEXT + assertFalse(goog.structs.every(col, f, THIS_OBJ)); +} + +// For each + +function testForEach() { + var called = false; + var obj = { + forEach: function(g) { + assertEquals(f, g); + assertEquals(this, obj); + called = true; + } + }; + function f() {} + goog.structs.forEach(obj, f); + assertTrue(called); +} + +function testForEach2() { + var called = false; + var THIS_OBJ = {}; + var obj = { + forEach: function(g, obj2) { + assertEquals(f, g); + assertEquals(this, obj); + assertEquals(THIS_OBJ, obj2); + called = true; + } + }; + function f() {} + goog.structs.forEach(obj, f, THIS_OBJ); + assertTrue(called); +} + +function testForEachArrayLike() { + var col = [0, 1, 2]; + var values = []; + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + values.push(v * v); + } + goog.structs.forEach(col, f) + assertArrayEquals([0, 1, 4], values); +} + +function testForEachArrayLike2() { + var THIS_OBJ = {}; + var col = [0, 1, 2]; + var values = []; + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + assertEquals(THIS_OBJ, this); + values.push(v * v); + } + goog.structs.forEach(col, f, THIS_OBJ); + assertArrayEquals([0, 1, 4], values); +} + +function testForEachString() { + var col = '012'; + var values = []; + function f(v, i, col2) { + // for some reason the strings are equal but identical??? + assertEquals(String(col), String(col2)); + assertEquals('number', typeof i); + values.push(Number(v) * Number(v)); + } + goog.structs.forEach(col, f); + assertArrayEquals([0, 1, 4], values); +} + +function testForEachString2() { + var THIS_OBJ = {}; + var col = '012'; + var values = []; + function f(v, i, col2) { + // for some reason the strings are equal but identical??? + assertEquals(String(col), String(col2)); + assertEquals('number', typeof i); + assertEquals(THIS_OBJ, this); + values.push(Number(v) * Number(v)); + } + goog.structs.forEach(col, f, THIS_OBJ); + assertArrayEquals([0, 1, 4], values); +} + +function testForEachMap() { + var col = new goog.structs.Map({a: 0, b: 1, c: 2}); + var values = []; + var keys = []; + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('string', typeof key); + values.push(v * v); + keys.push(key); + } + goog.structs.forEach(col, f); + assertArrayEquals([0, 1, 4], values); + assertArrayEquals(['a', 'b', 'c'], keys); +} + +function testForEachMap2() { + var THIS_OBJ = {}; + var col = new goog.structs.Map({a: 0, b: 1, c: 2}); + var values = []; + var keys = []; + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('string', typeof key); + assertEquals(THIS_OBJ, this); + values.push(v * v); + keys.push(key); + } + goog.structs.forEach(col, f, THIS_OBJ); + assertArrayEquals([0, 1, 4], values); + assertArrayEquals(['a', 'b', 'c'], keys); +} + +function testForEachSet() { + var col = new goog.structs.Set([0, 1, 2]); + var values = []; + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('undefined', typeof key); + values.push(v * v); + } + goog.structs.forEach(col, f); + assertArrayEquals([0, 1, 4], values); +} + +function testForEachSet2() { + var THIS_OBJ = {}; + var col = new goog.structs.Set([0, 1, 2]); + var values = []; + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('undefined', typeof key); + assertEquals(THIS_OBJ, this); + values.push(v * v); + } + goog.structs.forEach(col, f, THIS_OBJ); + assertArrayEquals([0, 1, 4], values); +} + +function testForEachNodeList() { + var values = []; + var col = getAll(); + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + values.push(v.tagName); + } + goog.structs.forEach(col, f); + assertEquals('HRPPPPPPPPH1', values.join('')); +} + +function testForEachNodeList2() { + var THIS_OBJ = {}; + var values = []; + var col = getAll(); + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + assertEquals(THIS_OBJ, this); + values.push(v.tagName); + } + goog.structs.forEach(col, f, THIS_OBJ); + assertEquals('HRPPPPPPPPH1', values.join('')); +} + +</script> +</body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/treenode.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/treenode.js.svn-base new file mode 100644 index 0000000..4d67ed4 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/treenode.js.svn-base @@ -0,0 +1,427 @@ +// Copyright 2010 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Generic tree node data structure with arbitrary number of child + * nodes. + * + */ + +goog.provide('goog.structs.TreeNode'); + +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.structs.Node'); + + + +/** + * Generic tree node data structure with arbitrary number of child nodes. + * It is possible to create a dynamic tree structure by overriding + * {@link #getParent} and {@link #getChildren} in a subclass. All other getters + * will automatically work. + * + * @param {*} key Key. + * @param {*} value Value. + * @constructor + * @extends {goog.structs.Node} + */ +goog.structs.TreeNode = function(key, value) { + goog.structs.Node.call(this, key, value); +}; +goog.inherits(goog.structs.TreeNode, goog.structs.Node); + + +/** + * Constant for empty array to avoid unnecessary allocations. + * @private + */ +goog.structs.TreeNode.EMPTY_ARRAY_ = []; + + +/** + * Reference to the parent node or null if it has no parent. + * @type {goog.structs.TreeNode} + * @private + */ +goog.structs.TreeNode.prototype.parent_ = null; + + +/** + * Child nodes or null in case of leaf node. + * @type {Array.<!goog.structs.TreeNode>} + * @private + */ +goog.structs.TreeNode.prototype.children_ = null; + + +/** + * @return {!goog.structs.TreeNode} Clone of the tree node without its parent + * and child nodes. The key and the value are copied by reference. + */ +goog.structs.TreeNode.prototype.clone = function() { + return new goog.structs.TreeNode(this.getKey(), this.getValue()); +}; + + +/** + * @return {!goog.structs.TreeNode} Clone of the subtree with this node as root. + */ +goog.structs.TreeNode.prototype.deepClone = function() { + var clone = this.clone(); + this.forEachChild(function(child) { + clone.addChild(child.deepClone()); + }); + return clone; +}; + + +/** + * @return {goog.structs.TreeNode} Parent node or null if it has no parent. + */ +goog.structs.TreeNode.prototype.getParent = function() { + return this.parent_; +}; + + +/** + * @return {boolean} Whether the node is a leaf node. + */ +goog.structs.TreeNode.prototype.isLeaf = function() { + return !this.getChildCount(); +}; + + +/** + * Tells if the node is the last child of its parent. This method helps how to + * connect the tree nodes with lines: L shapes should be used before the last + * children and |- shapes before the rest. Schematic tree visualization: + * + * <pre> + * Node1 + * |-Node2 + * | L-Node3 + * | |-Node4 + * | L-Node5 + * L-Node6 + * </pre> + * + * @return {boolean} Whether the node has parent and is the last child of it. + */ +goog.structs.TreeNode.prototype.isLastChild = function() { + var parent = this.getParent(); + return Boolean(parent && this == goog.array.peek(parent.getChildren())); +}; + + +/** + * @return {!Array.<!goog.structs.TreeNode>} Immutable child nodes. + */ +goog.structs.TreeNode.prototype.getChildren = function() { + return this.children_ || goog.structs.TreeNode.EMPTY_ARRAY_; +}; + + +/** + * Gets the child node of this node at the given index. + * @param {number} index Child index. + * @return {goog.structs.TreeNode} The node at the given index or null if not + * found. + */ +goog.structs.TreeNode.prototype.getChildAt = function(index) { + return this.getChildren()[index] || null; +}; + + +/** + * @return {number} The number of children. + */ +goog.structs.TreeNode.prototype.getChildCount = function() { + return this.getChildren().length; +}; + + +/** + * @return {number} The number of ancestors of the node. + */ +goog.structs.TreeNode.prototype.getDepth = function() { + var depth = 0; + var node = this; + while (node.getParent()) { + depth++; + node = node.getParent(); + } + return depth; +}; + + +/** + * @return {!Array.<!goog.structs.TreeNode>} All ancestor nodes in bottom-up + * order. + */ +goog.structs.TreeNode.prototype.getAncestors = function() { + var ancestors = []; + var node = this.getParent(); + while (node) { + ancestors.push(node); + node = node.getParent(); + } + return ancestors; +}; + + +/** + * @return {!goog.structs.TreeNode} The root of the tree structure, i.e. the + * farthest ancestor of the node or the node itself if it has no parents. + */ +goog.structs.TreeNode.prototype.getRoot = function() { + var root = this; + while (root.getParent()) { + root = root.getParent(); + } + return root; +}; + + +/** + * Builds a nested array structure from the node keys in this node's subtree to + * facilitate testing tree operations that change the hierarchy. + * @return {!Array} The structure of this node's descendants as nested array + * of node keys. The number of unclosed opening brackets up to a particular + * node is proportional to the indentation of that node in the graphical + * representation of the tree. Example: + * <pre> + * this + * |- child1 + * | L- grandchild + * L- child2 + * </pre> + * is represented as ['child1', ['grandchild'], 'child2']. + */ +goog.structs.TreeNode.prototype.getSubtreeKeys = function() { + var ret = []; + this.forEachChild(function(child) { + ret.push(child.getKey()); + if (!child.isLeaf()) { + ret.push(child.getSubtreeKeys()); + } + }); + return ret; +}; + + +/** + * Tells whether this node is the ancestor of the given node. + * @param {!goog.structs.TreeNode} node A node. + * @return {boolean} Whether this node is the ancestor of {@code node}. + */ +goog.structs.TreeNode.prototype.contains = function(node) { + var current = node; + do { + current = current.getParent(); + } while (current && current != this); + return Boolean(current); +}; + + +/** + * Finds the deepest common ancestor of the given nodes. The concept of + * ancestor is not strict in this case, it includes the node itself. + * @param {...!goog.structs.TreeNode} var_args The nodes. + * @return {goog.structs.TreeNode} The common ancestor of the nodes or null if + * they are from different trees. + */ +goog.structs.TreeNode.findCommonAncestor = function(var_args) { + var ret = arguments[0]; + if (!ret) { + return null; + } + + var retDepth = ret.getDepth(); + for (var i = 1; i < arguments.length; i++) { + var node = arguments[i]; + var depth = node.getDepth(); + while (node != ret) { + if (depth <= retDepth) { + ret = ret.getParent(); + retDepth--; + } + if (depth > retDepth) { + node = node.getParent(); + depth--; + } + } + } + + return ret; +}; + + +/** + * Traverses all child nodes. + * @param {function(!goog.structs.TreeNode, number, + * !Array.<!goog.structs.TreeNode>)} f Callback function. It takes the + * node, its index and the array of all child nodes as arguments. + * @param {Object=} opt_this The object to be used as the value of {@code this} + * within {@code f}. + */ +goog.structs.TreeNode.prototype.forEachChild = function(f, opt_this) { + goog.array.forEach(this.getChildren(), f, opt_this); +}; + + +/** + * Traverses all child nodes recursively in preorder. + * @param {function(!goog.structs.TreeNode)} f Callback function. It takes the + * node as argument. + * @param {Object=} opt_this The object to be used as the value of {@code this} + * within {@code f}. + */ +goog.structs.TreeNode.prototype.forEachDescendant = function(f, opt_this) { + goog.array.forEach(this.getChildren(), function(child) { + f.call(opt_this, child); + child.forEachDescendant(f, opt_this); + }); +}; + + +/** + * Traverses the subtree with the possibility to skip branches. Starts with + * this node, and visits the descendant nodes depth-first, in preorder. + * @param {function(!goog.structs.TreeNode): (boolean|undefined)} f Callback + * function. It takes the node as argument. The children of this node will + * be visited if the callback returns true or undefined, and will be + * skipped if the callback returns false. + * @param {Object=} opt_this The object to be used as the value of {@code this} + * within {@code f}. + */ +goog.structs.TreeNode.prototype.traverse = function(f, opt_this) { + if (f.call(opt_this, this) !== false) { + goog.array.forEach(this.getChildren(), function(child) { + child.traverse(f, opt_this); + }); + } +}; + + +/** + * Sets the parent node of this node. The callers must ensure that the parent + * node and only that has this node among its children. + * @param {goog.structs.TreeNode} parent The parent to set. If null, the node + * will be detached from the tree. + * @protected + */ +goog.structs.TreeNode.prototype.setParent = function(parent) { + this.parent_ = parent; +}; + + +/** + * Appends a child node to this node. + * @param {!goog.structs.TreeNode} child Orphan child node. + */ +goog.structs.TreeNode.prototype.addChild = function(child) { + this.addChildAt(child, this.children_ ? this.children_.length : 0); +}; + + +/** + * Inserts a child node at the given index. + * @param {!goog.structs.TreeNode} child Orphan child node. + * @param {number} index The position to insert at. + */ +goog.structs.TreeNode.prototype.addChildAt = function(child, index) { + goog.asserts.assert(!child.getParent()); + child.setParent(this); + this.children_ = this.children_ || []; + goog.asserts.assert(index >= 0 && index <= this.children_.length); + goog.array.insertAt(this.children_, child, index); +}; + + +/** + * Replaces a child node at the given index. + * @param {!goog.structs.TreeNode} newChild Child node to set. It must not have + * parent node. + * @param {number} index Valid index of the old child to replace. + * @return {!goog.structs.TreeNode} The original child node, detached from its + * parent. + */ +goog.structs.TreeNode.prototype.replaceChildAt = function(newChild, index) { + goog.asserts.assert(!newChild.getParent(), + 'newChild must not have parent node'); + var children = this.getChildren(); + var oldChild = children[index]; + goog.asserts.assert(oldChild, 'Invalid child or child index is given.'); + oldChild.setParent(null); + children[index] = newChild; + newChild.setParent(this); + return oldChild; +}; + + +/** + * Replaces the given child node. + * @param {!goog.structs.TreeNode} newChild New node to replace + * {@code oldChild}. It must not have parent node. + * @param {!goog.structs.TreeNode} oldChild Existing child node to be replaced. + * @return {!goog.structs.TreeNode} The replaced child node detached from its + * parent. + */ +goog.structs.TreeNode.prototype.replaceChild = function(newChild, oldChild) { + return this.replaceChildAt(newChild, + goog.array.indexOf(this.getChildren(), oldChild)); +}; + + +/** + * Removes the child node at the given index. + * @param {number} index The position to remove from. + * @return {goog.structs.TreeNode} The removed node if any. + */ +goog.structs.TreeNode.prototype.removeChildAt = function(index) { + var child = this.children_ && this.children_[index]; + if (child) { + child.setParent(null); + goog.array.removeAt(this.children_, index); + if (this.children_.length == 0) { + delete this.children_; + } + return child; + } + return null; +}; + + +/** + * Removes the given child node of this node. + * @param {goog.structs.TreeNode} child The node to remove. + * @return {goog.structs.TreeNode} The removed node if any. + */ +goog.structs.TreeNode.prototype.removeChild = function(child) { + return this.removeChildAt(goog.array.indexOf(this.getChildren(), child)); +}; + + +/** + * Removes all child nodes of this node. + */ +goog.structs.TreeNode.prototype.removeChildren = function() { + if (this.children_) { + goog.array.forEach(this.children_, function(child) { + child.setParent(null); + }); + } + delete this.children_; +}; diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/treenode_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/treenode_test.html.svn-base new file mode 100644 index 0000000..c858b29 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/treenode_test.html.svn-base @@ -0,0 +1,370 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright 2010 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> +<!-- +--> +<head> +<meta http-equiv="X-UA-Compatible" content="IE=edge"> +<title>Closure Unit Tests - goog.structs.TreeNode</title> +<script src="../base.js"></script> +<script> + goog.require('goog.array'); + goog.require('goog.structs.TreeNode'); + goog.require('goog.testing.jsunit'); +</script> +</head> +<body> +<script> + +function testConstructor() { + var node = new goog.structs.TreeNode('key', 'value'); + assertEquals('key', 'key', node.getKey()); + assertEquals('value', 'value', node.getValue()); + assertNull('parent', node.getParent()); + assertArrayEquals('children', [], node.getChildren()); + assertTrue('leaf', node.isLeaf()); +} + +function testClone() { + var node1 = new goog.structs.TreeNode(1, '1'); + var node2 = new goog.structs.TreeNode(2, '2'); + var node3 = new goog.structs.TreeNode(3, '3'); + node1.addChild(node2); + node2.addChild(node3); + + var clone = node2.clone(); + assertEquals('key', 2, clone.getKey()); + assertEquals('value', '2', clone.getValue()); + assertNull('parent', clone.getParent()); + assertArrayEquals('children', [], clone.getChildren()); +} + +function testDeepClone() { + var node1 = new goog.structs.TreeNode(1, '1'); + var node2 = new goog.structs.TreeNode(2, '2'); + var node3 = new goog.structs.TreeNode(3, '3'); + node1.addChild(node2); + node2.addChild(node3); + + var clone = node2.deepClone(); + assertEquals('key', 2, clone.getKey()); + assertEquals('value', '2', clone.getValue()); + assertNull('parent', clone.getParent()); + assertEquals('number of children', 1, clone.getChildren().length); + assertEquals('first child key', 3, clone.getChildAt(0).getKey()); + assertNotEquals('first child has been cloned', node3, clone.getChildAt(0)); +} + +function testGetParent() { + var node1 = new goog.structs.TreeNode(1, null); + var node2 = new goog.structs.TreeNode(2, null); + node1.addChild(node2); + assertEquals('parent', node1, node2.getParent()); + assertNull('orphan', node1.getParent()); +} + +function testIsLeaf() { + var node1 = new goog.structs.TreeNode(1, null); + var node2 = new goog.structs.TreeNode(2, null); + node1.addChild(node2); + assertFalse('not leaf', node1.isLeaf()); + assertTrue('leaf', node2.isLeaf()); +} + +function testIsLastChild() { + var node1 = new goog.structs.TreeNode(1, '1'); + var node2 = new goog.structs.TreeNode(2, '2'); + var node3 = new goog.structs.TreeNode(3, '3'); + node1.addChild(node2); + node1.addChild(node3); + assertFalse('root', node1.isLastChild()); + assertFalse('first child out of the two', node2.isLastChild()); + assertTrue('second child out of the two', node3.isLastChild()); +} + +function testGetChildren() { + var node1 = new goog.structs.TreeNode(1, null); + var node2 = new goog.structs.TreeNode(2, null); + node1.addChild(node2); + assertArrayEquals('1 child', [node2], node1.getChildren()); + assertArrayEquals('no children', [], node2.getChildren()); +} + +function testGetChildAt() { + var node1 = new goog.structs.TreeNode(1, null); + var node2 = new goog.structs.TreeNode(2, null); + node1.addChild(node2); + assertNull('index too low', node1.getChildAt(-1)); + assertEquals('first child', node2, node1.getChildAt(0)); + assertNull('index too high', node1.getChildAt(1)); + assertNull('no children', node2.getChildAt(0)); +} + +function testGetChildCount() { + var node1 = new goog.structs.TreeNode(1, null); + var node2 = new goog.structs.TreeNode(2, null); + node1.addChild(node2); + assertEquals('child count of root node', 1, node1.getChildCount()); + assertEquals('child count of leaf node', 0, node2.getChildCount()); +} + +function testGetDepth() { + var node1 = new goog.structs.TreeNode(1, null); + var node2 = new goog.structs.TreeNode(2, null); + var node3 = new goog.structs.TreeNode(3, null); + node1.addChild(node2); + node2.addChild(node3); + assertEquals('no parent', 0, node1.getDepth()); + assertEquals('1 ancestor', 1, node2.getDepth()); + assertEquals('2 ancestors', 2, node3.getDepth()); +} + +function testGetAncestors() { + var node1 = new goog.structs.TreeNode(1, null); + var node2 = new goog.structs.TreeNode(2, null); + var node3 = new goog.structs.TreeNode(3, null); + node1.addChild(node2); + node2.addChild(node3); + assertArrayEquals('no ancestors', [], node1.getAncestors()); + assertArrayEquals('2 ancestors', [node2, node1], node3.getAncestors()); +} + +function testGetRoot() { + var node1 = new goog.structs.TreeNode(1, null); + var node2 = new goog.structs.TreeNode(2, null); + node1.addChild(node2); + assertEquals('no ancestors', node1, node1.getRoot()); + assertEquals('has ancestors', node1, node2.getRoot()); +} + +function testGetSubtreeKeys() { + var root = new goog.structs.TreeNode('root', null); + var child1 = new goog.structs.TreeNode('child1', null); + var child2 = new goog.structs.TreeNode('child2', null); + var grandchild = new goog.structs.TreeNode('grandchild', null); + root.addChild(child1); + root.addChild(child2); + child1.addChild(grandchild); + assertArrayEquals('node hierarchy', ['child1', ['grandchild'], 'child2'], + root.getSubtreeKeys()); +} + +function testContains() { + var node1 = new goog.structs.TreeNode(1, null); + var node2 = new goog.structs.TreeNode(2, null); + var node3 = new goog.structs.TreeNode(3, null); + var node4 = new goog.structs.TreeNode(4, null); + node1.addChild(node2); + node2.addChild(node3); + node2.addChild(node4); + + assertTrue('parent', node1.contains(node2)); + assertTrue('grandparent', node1.contains(node3)); + assertFalse('child', node2.contains(node1)); + assertFalse('grandchild', node3.contains(node1)); + assertFalse('sibling', node3.contains(node4)); +} + +function testFindCommonAncestor() { + var findCommonAncestor = goog.structs.TreeNode.findCommonAncestor; + var node1 = new goog.structs.TreeNode(1, null); + var node2 = new goog.structs.TreeNode(2, null); + var node3 = new goog.structs.TreeNode(3, null); + var node4 = new goog.structs.TreeNode(4, null); + var node5 = new goog.structs.TreeNode(5, null); + node1.addChild(node2); + node2.addChild(node3); + node1.addChild(node4); + + assertNull('0 nodes', findCommonAncestor()); + assertEquals('1 node', node2, findCommonAncestor(node2)); + assertEquals('same nodes', node3, findCommonAncestor(node3, node3)); + assertEquals('node and child node', node2, findCommonAncestor(node2, node3)); + assertEquals('node and parent node', node1, findCommonAncestor(node2, node1)); + assertEquals('siblings', node1, findCommonAncestor(node2, node4)); + assertEquals('all nodes', node1, + findCommonAncestor(node2, node3, node4, node1)); + assertNull('disconnected nodes', findCommonAncestor(node3, node5)); +} + +function testForEachChild() { + var node1 = new goog.structs.TreeNode(1, null); + var node2 = new goog.structs.TreeNode(2, null); + var node3 = new goog.structs.TreeNode(3, null); + node1.addChild(node2); + node1.addChild(node3); + + var thisContext = {}; + var visitedNodes = []; + var indices = []; + node1.forEachChild(function(node, index, children) { + assertEquals('value of this', thisContext, this); + visitedNodes.push(node); + indices.push(index); + assertArrayEquals('children argument', [node2, node3], children); + }, thisContext); + assertArrayEquals('visited nodes', [node2, node3], visitedNodes); + assertArrayEquals('index of visited nodes', [0, 1], indices); +} + +function testForEachDescendant() { + var node1 = new goog.structs.TreeNode(1, null); + var node2 = new goog.structs.TreeNode(2, null); + var node3 = new goog.structs.TreeNode(3, null); + var node4 = new goog.structs.TreeNode(4, null); + node1.addChild(node2); + node2.addChild(node3); + node2.addChild(node4); + + var thisContext = {}; + var visitedNodes = []; + node1.forEachDescendant(function(node) { + assertEquals('value of this', thisContext, this); + visitedNodes.push(node); + }, thisContext); + assertArrayEquals('visited nodes', [node2, node3, node4], visitedNodes); +} + +function testTraverse() { + var node1 = new goog.structs.TreeNode(1, null); + var node2 = new goog.structs.TreeNode(2, null); + var node3 = new goog.structs.TreeNode(3, null); + var node4 = new goog.structs.TreeNode(4, null); + node1.addChild(node2); + node2.addChild(node3); + node2.addChild(node4); + + var thisContext = {}; + var visitedNodes = []; + node1.traverse(function(node) { + assertEquals('value of this', thisContext, this); + visitedNodes.push(node); + }, thisContext); + assertArrayEquals('callback returns nothing => all nodes are visited', + [node1, node2, node3, node4], visitedNodes); + + visitedNodes = []; + node1.traverse(function(node) { + visitedNodes.push(node); + return node != node2; // Cut off at node2. + }); + assertArrayEquals('children of node2 are skipped', + [node1, node2], visitedNodes); +} + +function testAddChild() { + var node1 = new goog.structs.TreeNode(1, null); + var node2 = new goog.structs.TreeNode(2, null); + var node3 = new goog.structs.TreeNode(3, null); + assertArrayEquals('0 children', [], node1.getChildren()); + node1.addChild(node2); + assertArrayEquals('1 child', [node2], node1.getChildren()); + assertEquals('parent is set', node1, node2.getParent()); + node1.addChild(node3); + assertArrayEquals('2 children', [node2, node3], node1.getChildren()); +} + +function testAddChildAt() { + var node1 = new goog.structs.TreeNode(1, null); + var node2 = new goog.structs.TreeNode(2, null); + var node3 = new goog.structs.TreeNode(3, null); + var node4 = new goog.structs.TreeNode(4, null); + var node5 = new goog.structs.TreeNode(5, null); + node1.addChildAt(node2, 0); + assertArrayEquals('add first child', [node2], node1.getChildren()); + assertEquals('parent is set', node1, node2.getParent()); + node1.addChildAt(node3, 0); + assertArrayEquals('add to the front', [node3, node2], + node1.getChildren()); + node1.addChildAt(node4, 1); + assertArrayEquals('add to the middle', [node3, node4, node2], + node1.getChildren()); + node1.addChildAt(node5, 3); + assertArrayEquals('add to the end', [node3, node4, node2, node5], + node1.getChildren()); +} + +function testReplaceChildAt() { + var root = new goog.structs.TreeNode(0, null); + var node1 = new goog.structs.TreeNode(1, null); + root.addChild(node1); + + var node2 = new goog.structs.TreeNode(2, null); + assertEquals('original node', node1, root.replaceChildAt(node2, 0)); + assertEquals('parent is set', root, node2.getParent()); + assertArrayEquals('children are updated', [node2], root.getChildren()); + assertNull('old child node is detached', node1.getParent()); +} + +function testReplaceChild() { + var root = new goog.structs.TreeNode(0, null); + var node1 = new goog.structs.TreeNode(1, null); + root.addChild(node1); + + var node2 = new goog.structs.TreeNode(2, null); + assertEquals('original node', node1, root.replaceChild(node2, node1)); + assertEquals('parent is set', root, node2.getParent()); + assertArrayEquals('children are updated', [node2], root.getChildren()); + assertNull('old child node is detached', node1.getParent()); +} + +function testRemoveChildAt() { + var node1 = new goog.structs.TreeNode(1, null); + var node2 = new goog.structs.TreeNode(2, null); + var node3 = new goog.structs.TreeNode(3, null); + node1.addChild(node2); + node1.addChild(node3); + + assertNull('index too low', node1.removeChildAt(-1)); + assertNull('index too high', node1.removeChildAt(2)); + assertArrayEquals('node1 is intact', [node2, node3], node1.getChildren()); + + assertEquals('remove first child', node2, node1.removeChildAt(0)); + assertArrayEquals('remove from the front', [node3], node1.getChildren()); + assertNull('parent is unset', node2.getParent()); + + assertEquals('remove last child', node3, node1.removeChildAt(0)); + assertArrayEquals('remove last child', [], node1.getChildren()); + assertTrue('node1 became leaf', node1.isLeaf()); +} + +function testRemoveChild() { + var node1 = new goog.structs.TreeNode(1, null); + var node2 = new goog.structs.TreeNode(2, null); + var node3 = new goog.structs.TreeNode(3, null); + node1.addChild(node2); + node1.addChild(node3); + + assertNull('remove null', node1.removeChild(null)); + assertNull('remove non-child', node1.removeChild(node1)); + assertArrayEquals('node1 is intact', [node2, node3], node1.getChildren()); + + assertEquals('remove node3, return value', node3, node1.removeChild(node3)); + assertArrayEquals('node is removed', [node2], node1.getChildren()); +} + +function testRemoveChildren() { + var node1 = new goog.structs.TreeNode(1, null); + var node2 = new goog.structs.TreeNode(2, null); + var node3 = new goog.structs.TreeNode(3, null); + node1.addChild(node2); + node1.addChild(node3); + + node2.removeChildren(); + assertArrayEquals('removing a leaf node\'s children has no effect', [], + node2.getChildren()); + assertEquals('node still has parent', node1, node2.getParent()); + + node1.removeChildren(); + assertArrayEquals('children have been removed', [], node1.getChildren()); + assertNull('children\'s parents have been unset', node2.getParent()); +} + +</script> +</body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/trie.js.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/trie.js.svn-base new file mode 100644 index 0000000..bf365b0 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/trie.js.svn-base @@ -0,0 +1,368 @@ +// Copyright 2007 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Datastructure: Trie. + * + * + * This file provides the implementation of a trie data structure. A trie is a + * data structure that stores key/value pairs in a prefix tree. See: + * http://en.wikipedia.org/wiki/Trie + */ + + +goog.provide('goog.structs.Trie'); + +goog.require('goog.object'); +goog.require('goog.structs'); + + + +/** + * Class for a Trie datastructure. Trie data structures are made out of trees + * of Trie classes. + * + * @param {Object=} opt_trie Optional goog.structs.Trie or Object to initialize + * trie with. + * @constructor + */ +goog.structs.Trie = function(opt_trie) { + /** + * This trie's child nodes. + * @private + * @type {Object.<goog.structs.Trie>} + */ + this.childNodes_ = {}; + + if (opt_trie) { + this.setAll(opt_trie); + } +}; + + +/** + * This trie's value. For the base trie, this will be the value of the + * empty key, if defined. + * @private + * @type {*} + */ +goog.structs.Trie.prototype.value_ = undefined; + + +/** + * Sets the given key/value pair in the trie. O(L), where L is the length + * of the key. + * @param {string} key The key. + * @param {*} value The value. + */ +goog.structs.Trie.prototype.set = function(key, value) { + this.setOrAdd_(key, value, false); +}; + + +/** + * Adds the given key/value pair in the trie. Throw an exception if the key + * already exists in the trie. O(L), where L is the length of the key. + * @param {string} key The key. + * @param {*} value The value. + */ +goog.structs.Trie.prototype.add = function(key, value) { + this.setOrAdd_(key, value, true); +}; + + +/** + * Helper function for set and add. Adds the given key/value pair to + * the trie, or, if the key already exists, sets the value of the key. If + * opt_add is true, then throws an exception if the key already has a value in + * the trie. O(L), where L is the length of the key. + * @param {string} key The key. + * @param {*} value The value. + * @param {boolean=} opt_add Throw exception if key is already in the trie. + * @private + */ +goog.structs.Trie.prototype.setOrAdd_ = function(key, value, opt_add) { + var node = this; + for (var characterPosition = 0; characterPosition < key.length; + characterPosition++) { + var currentCharacter = key.charAt(characterPosition); + if (!node.childNodes_[currentCharacter]) { + node.childNodes_[currentCharacter] = new goog.structs.Trie(); + } + node = node.childNodes_[currentCharacter]; + } + if (opt_add && node.value_ !== undefined) { + throw Error('The collection already contains the key "' + key + '"'); + } else { + node.value_ = value; + } +}; + + +/** + * Adds multiple key/value pairs from another goog.structs.Trie or Object. + * O(N) where N is the number of nodes in the trie. + * @param {Object|goog.structs.Trie} trie Object containing the data to add. + */ +goog.structs.Trie.prototype.setAll = function(trie) { + var keys = goog.structs.getKeys(trie); + var values = goog.structs.getValues(trie); + + for (var i = 0; i < keys.length; i++) { + this.set(keys[i], values[i]); + } +}; + + +/** + * Retrieves a value from the trie given a key. O(L), where L is the length of + * the key. + * @param {string} key The key to retrieve from the trie. + * @return {*} The value of the key in the trie, or undefined if the trie does + * not contain this key. + */ +goog.structs.Trie.prototype.get = function(key) { + var node = this; + for (var characterPosition = 0; characterPosition < key.length; + characterPosition++) { + var currentCharacter = key.charAt(characterPosition); + if (!node.childNodes_[currentCharacter]) { + return undefined; + } + node = node.childNodes_[currentCharacter]; + } + return node.value_; +}; + + +/** + * Retrieves all values from the trie that correspond to prefixes of the given + * input key. O(L), where L is the length of the key. + * + * @param {string} key The key to use for lookup. The given key as well as all + * prefixes of the key are retrieved. + * @param {?number=} opt_keyStartIndex Optional position in key to start lookup + * from. Defaults to 0 if not specified. + * @return {Object} Map of end index of matching prefixes and corresponding + * values. Empty if no match found. + */ +goog.structs.Trie.prototype.getKeyAndPrefixes = function(key, + opt_keyStartIndex) { + var node = this; + var matches = {}; + var characterPosition = opt_keyStartIndex || 0; + + if (node.value_ !== undefined) { + matches[characterPosition] = node.value_; + } + + for (; characterPosition < key.length; characterPosition++) { + var currentCharacter = key.charAt(characterPosition); + if (!(currentCharacter in node.childNodes_)) { + break; + } + node = node.childNodes_[currentCharacter]; + if (node.value_ !== undefined) { + matches[characterPosition] = node.value_; + } + } + + return matches; +}; + + +/** + * Gets the values of the trie. Not returned in any reliable order. O(N) where + * N is the number of nodes in the trie. Calls getValuesInternal_. + * @return {Array} The values in the trie. + */ +goog.structs.Trie.prototype.getValues = function() { + var allValues = []; + this.getValuesInternal_(allValues); + return allValues; +}; + + +/** + * Gets the values of the trie. Not returned in any reliable order. O(N) where + * N is the number of nodes in the trie. Builds the values as it goes. + * @param {Array.<string>} allValues Array to place values into. + * @private + */ +goog.structs.Trie.prototype.getValuesInternal_ = function(allValues) { + if (this.value_ !== undefined) { + allValues.push(this.value_); + } + for (var childNode in this.childNodes_) { + this.childNodes_[childNode].getValuesInternal_(allValues); + } +}; + + +/** + * Gets the keys of the trie. Not returned in any reliable order. O(N) where + * N is the number of nodes in the trie (or prefix subtree). + * @param {string=} opt_prefix Find only keys with this optional prefix. + * @return {Array} The keys in the trie. + */ +goog.structs.Trie.prototype.getKeys = function(opt_prefix) { + var allKeys = []; + if (opt_prefix) { + // Traverse to the given prefix, then call getKeysInternal_ to dump the + // keys below that point. + var node = this; + for (var characterPosition = 0; characterPosition < opt_prefix.length; + characterPosition++) { + var currentCharacter = opt_prefix.charAt(characterPosition); + if (!node.childNodes_[currentCharacter]) { + return []; + } + node = node.childNodes_[currentCharacter]; + } + node.getKeysInternal_(opt_prefix, allKeys); + } else { + this.getKeysInternal_('', allKeys); + } + return allKeys; +}; + + +/** + * Private method to get keys from the trie. Builds the keys as it goes. + * @param {string} keySoFar The partial key (prefix) traversed so far. + * @param {Array} allKeys The partially built array of keys seen so far. + * @private + */ +goog.structs.Trie.prototype.getKeysInternal_ = function(keySoFar, allKeys) { + if (this.value_ !== undefined) { + allKeys.push(keySoFar); + } + for (var childNode in this.childNodes_) { + this.childNodes_[childNode].getKeysInternal_(keySoFar + childNode, allKeys); + } +}; + + +/** + * Checks to see if a certain key is in the trie. O(L), where L is the length + * of the key. + * @param {string} key A key that may be in the trie. + * @return {boolean} Whether the trie contains key. + */ +goog.structs.Trie.prototype.containsKey = function(key) { + return this.get(key) !== undefined; +}; + + +/** + * Checks to see if a certain value is in the trie. Worst case is O(N) where + * N is the number of nodes in the trie. + * @param {*} value A value that may be in the trie. + * @return {boolean} Whether the trie contains the value. + */ +goog.structs.Trie.prototype.containsValue = function(value) { + if (this.value_ === value) { + return true; + } + for (var childNode in this.childNodes_) { + if (this.childNodes_[childNode].containsValue(value)) { + return true; + } + } + return false; +}; + + +/** + * Completely empties a trie of all keys and values. ~O(1) + */ +goog.structs.Trie.prototype.clear = function() { + this.childNodes_ = {}; + this.value_ = undefined; +}; + + +/** + * Removes a key from the trie or throws an exception if the key is not in the + * trie. O(L), where L is the length of the key. + * @param {string} key A key that should be removed from the trie. + * @return {*} The value whose key was removed. + */ +goog.structs.Trie.prototype.remove = function(key) { + var node = this; + var parents = []; + for (var characterPosition = 0; characterPosition < key.length; + characterPosition++) { + var currentCharacter = key.charAt(characterPosition); + if (!node.childNodes_[currentCharacter]) { + throw Error('The collection does not have the key "' + key + '"'); + } + + // Archive the current parent and child name (key in childNodes_) so that + // we may remove the following node and its parents if they are empty. + parents.push([node, currentCharacter]); + + node = node.childNodes_[currentCharacter]; + } + var oldValue = node.value_; + delete node.value_; + + while (parents.length > 0) { + var currentParentAndCharacter = parents.pop(); + var currentParent = currentParentAndCharacter[0]; + var currentCharacter = currentParentAndCharacter[1]; + if (goog.object.isEmpty( + currentParent.childNodes_[currentCharacter].childNodes_)) { + // If we have no child nodes, then remove this node. + delete currentParent.childNodes_[currentCharacter]; + } else { + // No point of traversing back any further, since we can't remove this + // path. + break; + } + } + return oldValue; +}; + + +/** + * Clones a trie and returns a new trie. O(N), where N is the number of nodes + * in the trie. + * @return {goog.structs.Trie} A new goog.structs.Trie with the same key value + * pairs. + */ +goog.structs.Trie.prototype.clone = function() { + return new goog.structs.Trie(this); +}; + + +/** + * Returns the number of key value pairs in the trie. O(N), where N is the + * number of nodes in the trie. + * TODO: This could be optimized by storing a weight (count below) in every + * node. + * @return {number} The number of pairs. + */ +goog.structs.Trie.prototype.getCount = function() { + return goog.structs.getCount(this.getValues()); +}; + + +/** + * Returns true if this trie contains no elements. ~O(1). + * @return {boolean} True iff this trie contains no elements. + */ +goog.structs.Trie.prototype.isEmpty = function() { + return this.value_ === undefined && goog.structs.isEmpty(this.childNodes_); +}; diff --git a/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/trie_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/trie_test.html.svn-base new file mode 100644 index 0000000..3b180a5 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/.svn/text-base/trie_test.html.svn-base @@ -0,0 +1,378 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright 2007 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> +<!-- +--> +<head> +<meta http-equiv="X-UA-Compatible" content="IE=edge"> +<title>Closure Unit Tests - goog.structs.Trie</title> +</script> +<script src="../base.js"></script> +<script> + goog.require('goog.object'); + goog.require('goog.structs'); + goog.require('goog.structs.Trie'); + goog.require('goog.testing.jsunit'); +</script> +</head> +<body> +<script> + +function makeTrie() { + var trie = new goog.structs.Trie(); + trie.add('hello', 1); + trie.add('hi', 'howdy'); + trie.add('', 'an empty string key'); + trie.add('empty value', ''); + trie.add('zero', 0); + trie.add('object', {}); + trie.add('null', null); + trie.add('hello, world', 2); + trie.add('world', {}); + return trie; +} + +function checkTrie(trie) { + assertEquals('get, should be 1', trie.get('hello'), 1); + assertEquals('get, should be "howdy"', trie.get('hi'), 'howdy'); + assertEquals('get, should be "an empty string key"', trie.get(''), + 'an empty string key'); + assertEquals('get, should be ""', trie.get('empty value'), ''); + assertEquals('get, should be ""', typeof trie.get('empty value'), 'string'); + assertEquals('get, should be an object', typeof trie.get('object'), 'object'); + assertEquals('get, should be 0', trie.get('zero'), 0); + assertEquals('get "null", should be null', trie.get('null'), null); + assertEquals('get, should be 2', trie.get('hello, world'), 2); + assertEquals('get, should be an object', typeof trie.get('world'), 'object'); +} + +function testTrieFormation() { + var t = makeTrie(); + checkTrie(t); +} + +function testFailureOfMultipleAdds() { + var t = new goog.structs.Trie(); + t.add('hello', 'testing'); + assertThrows('Error should be thrown when same key added twice.', function() { + t.add('hello', 'test'); + }); + + t = new goog.structs.Trie(); + t.add('null', null); + assertThrows('Error should be thrown when same key added twice.', function() { + t.add('null', 'hi!'); + }); + + t = new goog.structs.Trie(); + t.add('null', 'blah'); + assertThrows('Error should be thrown when same key added twice.', function() { + t.add('null', null); + }); +} + +function testTrieClone() { + var trieOne = makeTrie(); + var trieTwo = new goog.structs.Trie(trieOne); + checkTrie(trieTwo); +} + +function testTrieFromObject() { + var someObject = {'hello' : 1, + 'hi' : 'howdy', + '' : 'an empty string key', + 'empty value' : '', + 'object' : {}, + 'zero' : 0, + 'null' : null, + 'hello, world' : 2, + 'world' : {}}; + var trie = new goog.structs.Trie(someObject); + checkTrie(trie); +} + +function testTrieGetValues() { + var trie = makeTrie(); + var values = trie.getValues(); + assertTrue('getValues, should contain "howdy"', + goog.object.contains(values, 'howdy')); + assertTrue('getValues, should contain 1', goog.object.contains(values, 1)); + assertTrue('getValues, should contain 0', goog.object.contains(values, 0)); + assertTrue('getValues, should contain ""', goog.object.contains(values, '')); + assertTrue('getValues, should contain null', + goog.object.contains(values, null)); + assertEquals('goog.structs.getCount(getValues()) should be 9', + goog.structs.getCount(values), 9); +} + +function testTrieGetKeys() { + var trie = makeTrie(); + var keys = trie.getKeys(); + assertTrue('getKeys, should contain "hello"', + goog.object.contains(keys, 'hello')); + assertTrue('getKeys, should contain "empty value"', + goog.object.contains(keys, 'empty value')); + assertTrue('getKeys, should contain ""', goog.object.contains(keys, '')); + assertTrue('getKeys, should contain "zero"', + goog.object.contains(keys, 'zero')); + assertEquals('goog.structs.getCount(getKeys()) should be 9', + goog.structs.getCount(keys), 9); +} + + +function testTrieCount() { + var trieOne = makeTrie(); + var trieTwo = new goog.structs.Trie(); + assertEquals('count, should be 9', trieOne.getCount(), 9); + assertEquals('count, should be 0', trieTwo.getCount(), 0); +} + +function testRemoveKeyFromTrie() { + var trie = new goog.structs.Trie(); + trie.add('key1', 'value1'); + trie.add('key2', 'value2'); + trie.add('ke', 'value3'); + trie.add('zero', 0); + trie.remove('key2'); + assertEquals('get "key1", should be "value1"', trie.get('key1'), 'value1'); + assertUndefined('get "key2", should be undefined', trie.get('key2')); + trie.remove('zero'); + assertUndefined('get "zero", should be undefined', trie.get('zero')); + trie.remove('ke'); + assertUndefined('get "ke", should be undefined', trie.get('ke')); + assertEquals('get "key1", should be "value1"', trie.get('key1'), 'value1'); + trie.add('a', 'value4'); + assertTrue('testing internal structure, a should be a child', + 'a' in trie.childNodes_); + trie.remove('a'); + assertFalse('testing internal structure, a should no longer be a child', + 'a' in trie.childNodes_); + + trie.add('xyza', 'value'); + trie.remove('xyza', 'value'); + assertFalse('Should not have "x"', 'x' in trie.childNodes_); + + trie.add('xyza', null); + assertTrue('Should have "x"', 'x' in trie.childNodes_); + trie.remove('xyza'); + assertFalse('Should not have "x"', 'x' in trie.childNodes_); + + trie.add('xyza', 'value'); + trie.add('xb', 'value'); + trie.remove('xyza'); + assertTrue('get "x" should be defined', 'x' in trie.childNodes_); + assertFalse('get "y" should be undefined', + 'y' in trie.childNodes_['x'].childNodes_); +} + +function testRemoveKeyFromTrieWithNulls() { + var trie = new goog.structs.Trie(); + trie.add('key1', null); + trie.add('key2', 'value2'); + trie.add('ke', 'value3'); + trie.add('zero', 0); + trie.remove('key2'); + assertEquals('get "key1", should be null', trie.get('key1'), null); + assertUndefined('get "key2", should be undefined', trie.get('key2')); + trie.remove('zero'); + assertUndefined('get "zero", should be undefined', trie.get('zero')); + trie.remove('ke'); + assertUndefined('get "ke", should be undefined', trie.get('ke')); + assertEquals('get "key1", should be null', trie.get('key1'), null); + trie.add('a', 'value4'); + assertTrue('testing internal structure, a should be a child', + 'a' in trie.childNodes_); + trie.remove('a'); + assertFalse('testing internal structure, a should no longer be a child', + 'a' in trie.childNodes_); + + trie.add('xyza', null); + trie.add('xb', 'value'); + trie.remove('xyza'); + assertTrue('Should have "x"', 'x' in trie.childNodes_); + assertFalse('Should not have "y"', + 'y' in trie.childNodes_['x'].childNodes_); +} + +function testRemoveKeyException() { + var trie = new goog.structs.Trie(); + trie.add('abcdefg', 'value'); + trie.add('abcz', 'value'); + trie.add('abc', 'value'); + + assertThrows('Remove should throw an error on removal of non-existent key', + function() { + trie.remove('abcdefge'); + }); +} + +function testTrieIsEmpty() { + var trieOne = new goog.structs.Trie(); + var trieTwo = makeTrie(); + assertTrue('isEmpty, should be empty', trieOne.isEmpty()); + assertFalse('isEmpty, should not be empty', trieTwo.isEmpty()); + trieOne.add('', 1); + assertFalse('isEmpty, should not be empty', trieTwo.isEmpty()); + trieOne.remove(''); + assertTrue('isEmpty, should be empty', trieOne.isEmpty()); + trieOne.add('', 1); + trieOne.add('a', 1); + trieOne.remove('a'); + assertFalse('isEmpty, should not be empty', trieOne.isEmpty()); + trieOne.remove(''); + assertTrue('isEmpty, should be empty', trieOne.isEmpty()); + trieOne.add('', 1); + trieOne.add('a', 1); + trieOne.remove(''); + assertFalse('isEmpty, should not be empty', trieOne.isEmpty()); + trieOne.remove('a'); + assertTrue('isEmpty, should be empty', trieOne.isEmpty()); +} + +function testTrieClear() { + var trie = new goog.structs.Trie(); + trie.add('key1', 'value1'); + trie.add('key2', 'value2'); + trie.add('key3', null); + trie.clear(); + assertUndefined('get key1, should be undefined', trie.get('key1')); + assertUndefined('get key2, should be undefined', trie.get('key2')); + assertUndefined('get key3, should be undefined', trie.get('key3')); +} + +function testTrieContainsKey() { + var trie = makeTrie(); + assertTrue('containsKey, should contain "hello"', trie.containsKey('hello')); + assertTrue('containsKey, should contain "hi"', trie.containsKey('hi')); + assertTrue('containsKey, should contain ""', trie.containsKey('')); + assertTrue('containsKey, should contain "empty value"', + trie.containsKey('empty value')); + assertTrue('containsKey, should contain "object"', + trie.containsKey('object')); + assertTrue('containsKey, should contain "zero"', trie.containsKey('zero')); + assertTrue('containsKey, should contain "null"', trie.containsKey('null')); + assertFalse('containsKey, should not contain "blah"', + trie.containsKey('blah')); + trie.remove(''); + trie.remove('hi'); + trie.remove('zero'); + trie.remove('null'); + assertFalse('containsKey, should not contain "zero"', + trie.containsKey('zero')); + assertFalse('containsKey, should not contain ""', trie.containsKey('')); + assertFalse('containsKey, should not contain "hi"', trie.containsKey('hi')); + assertFalse('containsKey, should not contain "null"', + trie.containsKey('null')); +} + +function testTrieContainsValue() { + var trie = makeTrie(); + assertTrue('containsValue, should be true, should contain 1', + trie.containsValue(1)); + assertTrue('containsValue, should be true, should contain "howdy"', + trie.containsValue('howdy')); + assertTrue('containsValue, should be true, should contain ""', + trie.containsValue('')); + assertTrue('containsValue, should be true, should contain 0', + trie.containsValue(0)); + assertTrue('containsValue, should be true, should contain null', + trie.containsValue(null)); + assertTrue('containsValue, should be true, should ' + + 'contain "an empty string key"', + trie.containsValue('an empty string key')); + assertFalse('containsValue, should be false, should not contain "blah"', + trie.containsValue('blah')); + trie.remove('empty value'); + trie.remove('zero'); + assertFalse('containsValue, should be false, should not contain 0', + trie.containsValue(0)); + assertFalse('containsValue, should be false, should not contain ""', + trie.containsValue('')); +} + +function testTrieHandlingOfEmptyStrings() { + var trie = new goog.structs.Trie(); + assertEquals('get, should be undefined', trie.get(''), undefined); + assertFalse('containsValue, should be false', trie.containsValue('')); + assertFalse('containsKey, should be false', trie.containsKey('')); + trie.add('', 'test'); + trie.add('test2', ''); + assertTrue('containsValue, should be true', trie.containsValue('')); + assertTrue('containsKey, should be true', trie.containsKey('')); + assertEquals('get, should be "test"', trie.get(''), 'test'); + assertEquals('get, should be ""', trie.get('test2'), ''); + trie.remove(''); + trie.remove('test2'); + assertEquals('get, should be undefined', trie.get(''), undefined); + assertFalse('containsValue, should be false', trie.containsValue('')); + assertFalse('containsKey, should be false', trie.containsKey('')); +} + +function testPrefixOptionOnGetKeys() { + var trie = new goog.structs.Trie(); + trie.add('abcdefg', 'one'); + trie.add('abcdefghijk', 'two'); + trie.add('abcde', 'three'); + trie.add('abcq', null); + trie.add('abc', 'four'); + trie.add('xyz', 'five'); + assertEquals('getKeys, should be 1', trie.getKeys('xy').length, 1); + assertEquals('getKeys, should be 1', trie.getKeys('xyz').length, 1); + assertEquals('getKeys, should be 1', trie.getKeys('x').length, 1); + assertEquals('getKeys, should be 4', trie.getKeys('abc').length, 5); + assertEquals('getKeys, should be 2', trie.getKeys('abcdef').length, 2); + assertEquals('getKeys, should be 0', trie.getKeys('abcdefgi').length, 0); +} + +function testGetKeyAndPrefixes() { + var trie = makeTrie(); + // Note: trie has one of its keys as '' + assertEquals('getKeyAndPrefixes, should be 2', + 2, + goog.object.getCount(trie.getKeyAndPrefixes('world'))); + assertEquals('getKeyAndPrefixes, should be 2', + 2, + goog.object.getCount(trie.getKeyAndPrefixes('hello'))); + assertEquals('getKeyAndPrefixes, should be 2', + 2, + goog.object.getCount(trie.getKeyAndPrefixes('hello,'))); + assertEquals('getKeyAndPrefixes, should be 3', + 3, + goog.object.getCount(trie.getKeyAndPrefixes('hello, world'))); + assertEquals('getKeyAndPrefixes, should be 1', + 1, + goog.object.getCount(trie.getKeyAndPrefixes('hell'))); +} + +function testGetKeyAndPrefixesStartIndex() { + var trie = new goog.structs.Trie(); + trie.add('abcdefg', 'one'); + trie.add('bcdefg', 'two'); + trie.add('abcdefghijk', 'three'); + trie.add('abcde', 'four'); + trie.add('abcq', null); + trie.add('q', null); + trie.add('abc', 'five'); + trie.add('xyz', 'six'); + assertEquals('getKeyAndPrefixes, should be 3', + 3, + goog.object.getCount(trie.getKeyAndPrefixes('abcdefg', 0))); + assertEquals('getKeyAndPrefixes, should be 1', + 1, + goog.object.getCount(trie.getKeyAndPrefixes('abcdefg', 1))); + assertEquals('getKeyAndPrefixes, should be 1', + 1, + goog.object.getCount(trie.getKeyAndPrefixes('abcq', 3))); + assertEquals('getKeyAndPrefixes, should be 0', + 0, + goog.object.getCount(trie.getKeyAndPrefixes('abcd', 3))); +} + +</script> +</body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/structs/avltree.js b/contexts/data/lib/closure-library/closure/goog/structs/avltree.js new file mode 100644 index 0000000..306ab2a --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/avltree.js @@ -0,0 +1,772 @@ +// Copyright 2007 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Datastructure: AvlTree. + * + * + * This file provides the implementation of an AVL-Tree datastructure. The tree + * maintains a set of unique values in a sorted order. The values can be + * accessed efficiently in their sorted order since the tree enforces an O(logn) + * maximum height. See http://en.wikipedia.org/wiki/Avl_tree for more detail. + * + * The big-O notation for all operations are below: + * <pre> + * Method big-O + * ---------------------------------------------------------------------------- + * - add O(logn) + * - remove O(logn) + * - clear O(1) + * - contains O(logn) + * - getCount O(1) + * - getMinimum O(1), or O(logn) when optional root is specified + * - getMaximum O(1), or O(logn) when optional root is specified + * - getHeight O(1) + * - getValues O(n) + * - inOrderTraverse O(logn + k), where k is number of traversed nodes + * - reverseOrderTraverse O(logn + k), where k is number of traversed nodes + * </pre> + */ + + +goog.provide('goog.structs.AvlTree'); +goog.provide('goog.structs.AvlTree.Node'); + +goog.require('goog.structs'); +goog.require('goog.structs.Collection'); + + + +/** + * Constructs an AVL-Tree, which uses the specified comparator to order its + * values. The values can be accessed efficiently in their sorted order since + * the tree enforces a O(logn) maximum height. + * + * @param {Function=} opt_comparator Function used to order the tree's nodes. + * @constructor + * @implements {goog.structs.Collection} + */ +goog.structs.AvlTree = function(opt_comparator) { + this.comparator_ = opt_comparator || + goog.structs.AvlTree.DEFAULT_COMPARATOR_; +}; + + +/** + * String comparison function used to compare values in the tree. This function + * is used by default if no comparator is specified in the tree's constructor. + * + * @param {string} a The first string. + * @param {string} b The second string. + * @return {number} -1 if a < b, 1 if a > b, 0 if a = b. + * @private + */ +goog.structs.AvlTree.DEFAULT_COMPARATOR_ = function(a, b) { + if (String(a) < String(b)) { + return -1; + } else if (String(a) > String(b)) { + return 1; + } + return 0; +}; + + +/** + * Pointer to the root node of the tree. + * + * @type {goog.structs.AvlTree.Node} + * @private + */ +goog.structs.AvlTree.prototype.root_ = null; + + +/** + * Comparison function used to compare values in the tree. This function should + * take two values, a and b, and return x where: + * <pre> + * x < 0 if a < b, + * x > 0 if a > b, + * x = 0 otherwise + * </pre> + * + * @type {Function} + * @private + */ +goog.structs.AvlTree.prototype.comparator_ = null; + + +/** + * Pointer to the node with the smallest value in the tree. + * + * @type {goog.structs.AvlTree.Node} + * @private + */ +goog.structs.AvlTree.prototype.minNode_ = null; + + +/** + * Pointer to the node with the largest value in the tree. + * + * @type {goog.structs.AvlTree.Node} + * @private + */ +goog.structs.AvlTree.prototype.maxNode_ = null; + + +/** + * Keeps track of the number of nodes in the tree. + * + * @type {number} + * @private + */ +goog.structs.AvlTree.prototype.count_ = 0; + + +/** + * Inserts a node into the tree with the specified value if the tree does + * not already contain a node with the specified value. If the value is + * inserted, the tree is balanced to enforce the AVL-Tree height property. + * + * @param {*} value Value to insert into the tree. + * @return {boolean} Whether value was inserted into the tree. + */ +goog.structs.AvlTree.prototype.add = function(value) { + // If the tree is empty, create a root node with the specified value + if (this.root_ == null) { + this.root_ = new goog.structs.AvlTree.Node(value); + this.minNode_ = this.root_; + this.maxNode_ = this.root_; + this.count_ = 1; + return true; + } + + // Assume a node is not added and change status when one is + var retStatus = false; + + // Depth traverse the tree and insert the value if we reach a null node + this.traverse_(function(node) { + var retNode = null; + if (this.comparator_(node.value, value) > 0) { + retNode = node.left; + if (node.left == null) { + var newNode = new goog.structs.AvlTree.Node(value, node); + node.left = newNode; + if (node == this.minNode_) { + this.minNode_ = newNode; + } + retStatus = true; // Value was added to tree + this.balance_(node); // Maintain the AVL-tree balance + } + } else if (this.comparator_(node.value, value) < 0) { + retNode = node.right; + if (node.right == null) { + var newNode = new goog.structs.AvlTree.Node(value, node); + node.right = newNode; + if (node == this.maxNode_) { + this.maxNode_ = newNode; + } + retStatus = true; // Value was added to tree + this.balance_(node); // Maintain the AVL-tree balance + } + } + return retNode; // If null, we'll stop traversing the tree + }); + + // If a node was added, increment count + if (retStatus) { + this.count_ += 1; + } + + // Return true if a node was added, false otherwise + return retStatus; +}; + + +/** + * Removes a node from the tree with the specified value if the tree contains a + * node with this value. If a node is removed the tree is balanced to enforce + * the AVL-Tree height property. The value of the removed node is returned. + * + * @param {*} value Value to find and remove from the tree. + * @return {*} The value of the removed node or null if the value was not in + * the tree. + */ +goog.structs.AvlTree.prototype.remove = function(value) { + // Assume the value is not removed and set the value when it is removed + var retValue = null; + + // Depth traverse the tree and remove the value if we find it + this.traverse_(function(node) { + var retNode = null; + if (this.comparator_(node.value, value) > 0) { + retNode = node.left; + } else if (this.comparator_(node.value, value) < 0) { + retNode = node.right; + } else { + retValue = node.value; + this.removeNode_(node); + } + return retNode; // If null, we'll stop traversing the tree + }); + + // If a node was removed, decrement count. + if (retValue) { + // Had traverse_() cleared the tree, set to 0. + this.count_ = this.root_ ? this.count_ - 1 : 0; + } + + // Return the value that was removed, null if the value was not in the tree + return retValue; +}; + + +/** + * Removes all nodes from the tree. + */ +goog.structs.AvlTree.prototype.clear = function() { + this.root_ = null; + this.minNode_ = null; + this.maxNode_ = null; + this.count_ = 0; +}; + + +/** + * Returns true if the tree contains a node with the specified value, false + * otherwise. + * + * @param {*} value Value to find in the tree. + * @return {boolean} Whether the tree contains a node with the specified value. + */ +goog.structs.AvlTree.prototype.contains = function(value) { + // Assume the value is not in the tree and set this value if it is found + var isContained = false; + + // Depth traverse the tree and set isContained if we find the node + this.traverse_(function(node) { + var retNode = null; + if (this.comparator_(node.value, value) > 0) { + retNode = node.left; + } else if (this.comparator_(node.value, value) < 0) { + retNode = node.right; + } else { + isContained = true; + } + return retNode; // If null, we'll stop traversing the tree + }); + + // Return true if the value is contained in the tree, false otherwise + return isContained; +}; + + +/** + * Returns the number of values stored in the tree. + * + * @return {number} The number of values stored in the tree. + */ +goog.structs.AvlTree.prototype.getCount = function() { + return this.count_; +}; + + +/** + * Returns the value u, such that u is contained in the tree and u < v, for all + * values v in the tree where v != u. + * + * @return {*} The minimum value contained in the tree. + */ +goog.structs.AvlTree.prototype.getMinimum = function() { + return this.getMinNode_().value; +}; + + +/** + * Returns the value u, such that u is contained in the tree and u > v, for all + * values v in the tree where v != u. + * + * @return {*} The maximum value contained in the tree. + */ +goog.structs.AvlTree.prototype.getMaximum = function() { + return this.getMaxNode_().value; +}; + + +/** + * Returns the height of the tree (the maximum depth). This height should + * always be <= 1.4405*(Math.log(n+2)/Math.log(2))-1.3277, where n is the + * number of nodes in the tree. + * + * @return {number} The height of the tree. + */ +goog.structs.AvlTree.prototype.getHeight = function() { + return this.root_ ? this.root_.height : 0; +}; + + +/** + * Inserts the values stored in the tree into a new Array and returns the Array. + * + * @return {Array} An array containing all of the trees values in sorted order. + */ +goog.structs.AvlTree.prototype.getValues = function() { + var ret = []; + this.inOrderTraverse(function(value) { + ret.push(value); + }); + return ret; +}; + + +/** + * Performs an in-order traversal of the tree and calls {@code func} with each + * traversed node, optionally starting from the smallest node with a value >= to + * the specified start value. The traversal ends after traversing the tree's + * maximum node or when {@code func} returns a value that evaluates to true. + * + * @param {Function} func Function to call on each traversed node. + * @param {Object=} opt_startValue If specified, traversal will begin on the + * node with the smallest value >= opt_startValue. + */ +goog.structs.AvlTree.prototype.inOrderTraverse = + function(func, opt_startValue) { + // If our tree is empty, return immediately + if (!this.root_) { + return; + } + + // Depth traverse the tree to find node to begin in-order traversal from + var startNode; + if (opt_startValue) { + this.traverse_(function(node) { + var retNode = null; + if (this.comparator_(node.value, opt_startValue) > 0) { + retNode = node.left; + startNode = node; + } else if (this.comparator_(node.value, opt_startValue) < 0) { + retNode = node.right; + } else { + startNode = node; + } + return retNode; // If null, we'll stop traversing the tree + }); + } else { + startNode = this.getMinNode_(); + } + + // Traverse the tree and call func on each traversed node's value + var node = startNode, prev = startNode.left ? startNode.left : startNode; + while (node != null) { + if (node.left != null && node.left != prev && node.right != prev) { + node = node.left; + } else { + if (node.right != prev) { + if (func(node.value)) { + return; + } + } + var temp = node; + node = node.right != null && node.right != prev ? + node.right : + node.parent; + prev = temp; + } + } +}; + + +/** + * Performs a reverse-order traversal of the tree and calls {@code func} with + * each traversed node, optionally starting from the largest node with a value + * <= to the specified start value. The traversal ends after traversing the + * tree's minimum node or when func returns a value that evaluates to true. + * + * @param {Function} func Function to call on each traversed node. + * @param {Object=} opt_startValue If specified, traversal will begin on the + * node with the largest value <= opt_startValue. + */ +goog.structs.AvlTree.prototype.reverseOrderTraverse = + function(func, opt_startValue) { + // If our tree is empty, return immediately + if (!this.root_) { + return; + } + + // Depth traverse the tree to find node to begin reverse-order traversal from + var startNode; + if (opt_startValue) { + this.traverse_(goog.bind(function(node) { + var retNode = null; + if (this.comparator_(node.value, opt_startValue) > 0) { + retNode = node.left; + } else if (this.comparator_(node.value, opt_startValue) < 0) { + retNode = node.right; + startNode = node; + } else { + startNode = node; + } + return retNode; // If null, we'll stop traversing the tree + }, this)); + } else { + startNode = this.getMaxNode_(); + } + + // Traverse the tree and call func on each traversed node's value + var node = startNode, prev = startNode.right ? startNode.right : startNode; + while (node != null) { + if (node.right != null && node.right != prev && node.left != prev) { + node = node.right; + } else { + if (node.left != prev) { + if (func(node.value)) { + return; + } + } + var temp = node; + node = node.left != null && node.left != prev ? + node.left : + node.parent; + prev = temp; + } + } +}; + + +/** + * Performs a traversal defined by the supplied {@code traversalFunc}. The first + * call to {@code traversalFunc} is passed the root or the optionally specified + * startNode. After that, calls {@code traversalFunc} with the node returned + * by the previous call to {@code traversalFunc} until {@code traversalFunc} + * returns null or the optionally specified endNode. The first call to + * traversalFunc is passed the root or the optionally specified startNode. + * + * @param {Function} traversalFunc Function used to traverse the tree. Takes a + * node as a parameter and returns a node. + * @param {goog.structs.AvlTree.Node=} opt_startNode The node at which the + * traversal begins. + * @param {goog.structs.AvlTree.Node=} opt_endNode The node at which the + * traversal ends. + * @private + */ +goog.structs.AvlTree.prototype.traverse_ = + function(traversalFunc, opt_startNode, opt_endNode) { + var node = opt_startNode ? opt_startNode : this.root_; + var endNode = opt_endNode ? opt_endNode : null; + while (node && node != endNode) { + node = traversalFunc.call(this, node); + } +}; + + +/** + * Ensures that the specified node and all its ancestors are balanced. If they + * are not, performs left and right tree rotations to achieve a balanced + * tree. This method assumes that at most 2 rotations are necessary to balance + * the tree (which is true for AVL-trees that are balanced after each node is + * added or removed). + * + * @param {goog.structs.AvlTree.Node} node Node to begin balance from. + * @private + */ +goog.structs.AvlTree.prototype.balance_ = function(node) { + + this.traverse_(function(node) { + // Calculate the left and right node's heights + var lh = node.left ? node.left.height : 0; + var rh = node.right ? node.right.height : 0; + + // Rotate tree rooted at this node if it is not AVL-tree balanced + if (lh - rh > 1) { + if (node.left.right && (!node.left.left || + node.left.left.height < node.left.right.height)) { + this.leftRotate_(node.left); + } + this.rightRotate_(node); + } else if (rh - lh > 1) { + if (node.right.left && (!node.right.right || + node.right.right.height < node.right.left.height)) { + this.rightRotate_(node.right); + } + this.leftRotate_(node); + } + + // Recalculate the left and right node's heights + lh = node.left ? node.left.height : 0; + rh = node.right ? node.right.height : 0; + + // Set this node's height + node.height = Math.max(lh, rh) + 1; + + // Traverse up tree and balance parent + return node.parent; + }, node); + +}; + + +/** + * Performs a left tree rotation on the specified node. + * + * @param {goog.structs.AvlTree.Node} node Pivot node to rotate from. + * @private + */ +goog.structs.AvlTree.prototype.leftRotate_ = function(node) { + // Re-assign parent-child references for the parent of the node being removed + if (node.isLeftChild()) { + node.parent.left = node.right; + node.right.parent = node.parent; + } else if (node.isRightChild()) { + node.parent.right = node.right; + node.right.parent = node.parent; + } else { + this.root_ = node.right; + this.root_.parent = null; + } + + // Re-assign parent-child references for the child of the node being removed + var temp = node.right; + node.right = node.right.left; + if (node.right != null) node.right.parent = node; + temp.left = node; + node.parent = temp; +}; + + +/** + * Performs a right tree rotation on the specified node. + * + * @param {goog.structs.AvlTree.Node} node Pivot node to rotate from. + * @private + */ +goog.structs.AvlTree.prototype.rightRotate_ = function(node) { + // Re-assign parent-child references for the parent of the node being removed + if (node.isLeftChild()) { + node.parent.left = node.left; + node.left.parent = node.parent; + } else if (node.isRightChild()) { + node.parent.right = node.left; + node.left.parent = node.parent; + } else { + this.root_ = node.left; + this.root_.parent = null; + } + + // Re-assign parent-child references for the child of the node being removed + var temp = node.left; + node.left = node.left.right; + if (node.left != null) node.left.parent = node; + temp.right = node; + node.parent = temp; +}; + + +/** + * Removes the specified node from the tree and ensures the tree still + * maintains the AVL-tree balance. + * + * @param {goog.structs.AvlTree.Node} node The node to be removed. + * @private + */ +goog.structs.AvlTree.prototype.removeNode_ = function(node) { + // Perform normal binary tree node removal, but balance the tree, starting + // from where we removed the node + if (node.left != null || node.right != null) { + var b = null; // Node to begin balance from + var r; // Node to replace the node being removed + if (node.left != null) { + r = this.getMaxNode_(node.left); + if (r != node.left) { + r.parent.right = r.left; + if (r.left) r.left.parent = r.parent; + r.left = node.left; + r.left.parent = r; + b = r.parent; + } + r.parent = node.parent; + r.right = node.right; + if (r.right) r.right.parent = r; + if (node == this.maxNode_) this.maxNode_ = r; + } else { + r = this.getMinNode_(node.right); + if (r != node.right) { + r.parent.left = r.right; + if (r.right) r.right.parent = r.parent; + r.right = node.right; + r.right.parent = r; + b = r.parent; + } + r.parent = node.parent; + r.left = node.left; + if (r.left) r.left.parent = r; + if (node == this.minNode_) this.minNode_ = r; + } + + // Update the parent of the node being removed to point to its replace + if (node.isLeftChild()) { + node.parent.left = r; + } else if (node.isRightChild()) { + node.parent.right = r; + } else { + this.root_ = r; + } + + // Balance the tree + this.balance_(b ? b : r); + } else { + // If the node is a leaf, remove it and balance starting from its parent + if (node.isLeftChild()) { + this.special = 1; + node.parent.left = null; + if (node == this.minNode_) this.minNode_ = node.parent; + this.balance_(node.parent); + } else if (node.isRightChild()) { + node.parent.right = null; + if (node == this.maxNode_) this.maxNode_ = node.parent; + this.balance_(node.parent); + } else { + this.clear(); + } + } +}; + + +/** + * Returns the node with the smallest value in tree, optionally rooted at + * {@code opt_rootNode}. + * + * @param {goog.structs.AvlTree.Node=} opt_rootNode Optional root node. + * @return {goog.structs.AvlTree.Node} The node with the smallest value in + * the tree. + * @private + */ +goog.structs.AvlTree.prototype.getMinNode_ = function(opt_rootNode) { + if (!opt_rootNode) { + return this.minNode_; + } + + var minNode = opt_rootNode; + this.traverse_(function(node) { + var retNode = null; + if (node.left) { + minNode = node.left; + retNode = node.left; + } + return retNode; // If null, we'll stop traversing the tree + }, opt_rootNode); + + return minNode; +}; + + +/** + * Returns the node with the largest value in tree, optionally rooted at + * opt_rootNode. + * + * @param {goog.structs.AvlTree.Node=} opt_rootNode Optional root node. + * @return {goog.structs.AvlTree.Node} The node with the largest value in + * the tree. + * @private + */ +goog.structs.AvlTree.prototype.getMaxNode_ = function(opt_rootNode) { + if (!opt_rootNode) { + return this.maxNode_; + } + + var maxNode = opt_rootNode; + this.traverse_(function(node) { + var retNode = null; + if (node.right) { + maxNode = node.right; + retNode = node.right; + } + return retNode; // If null, we'll stop traversing the tree + }, opt_rootNode); + + return maxNode; +}; + + + +/** + * Constructs an AVL-Tree node with the specified value. If no parent is + * specified, the node's parent is assumed to be null. The node's height + * defaults to 1 and its children default to null. + * + * @param {*} value Value to store in the node. + * @param {goog.structs.AvlTree.Node=} opt_parent Optional parent node. + * @constructor + */ +goog.structs.AvlTree.Node = function(value, opt_parent) { + /** + * The value stored by the node. + * + * @type {*} + */ + this.value = value; + + /** + * The node's parent. Null if the node is the root. + * + * @type {goog.structs.AvlTree.Node} + */ + this.parent = opt_parent ? opt_parent : null; +}; + + +/** + * The node's left child. Null if the node does not have a left child. + * + * @type {goog.structs.AvlTree.Node?} + */ +goog.structs.AvlTree.Node.prototype.left = null; + + +/** + * The node's right child. Null if the node does not have a right child. + * + * @type {goog.structs.AvlTree.Node?} + */ +goog.structs.AvlTree.Node.prototype.right = null; + + +/** + * The height of the tree rooted at this node. + * + * @type {number} + */ +goog.structs.AvlTree.Node.prototype.height = 1; + + +/** + * Returns true iff the specified node has a parent and is the right child of + * its parent. + * + * @return {boolean} Whether the specified node has a parent and is the right + * child of its parent. + */ +goog.structs.AvlTree.Node.prototype.isRightChild = function() { + return !!this.parent && this.parent.right == this; +}; + + +/** + * Returns true iff the specified node has a parent and is the left child of + * its parent. + * + * @return {boolean} Whether the specified node has a parent and is the left + * child of its parent. + */ +goog.structs.AvlTree.Node.prototype.isLeftChild = function() { + return !!this.parent && this.parent.left == this; +}; diff --git a/contexts/data/lib/closure-library/closure/goog/structs/avltree_test.html b/contexts/data/lib/closure-library/closure/goog/structs/avltree_test.html new file mode 100644 index 0000000..144047d --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/avltree_test.html @@ -0,0 +1,251 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright 2007 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> +<head> +<meta http-equiv="X-UA-Compatible" content="IE=edge"> +<title>Closure Unit Tests - goog.structs.AvlTree</title> +<script src="../base.js"></script> +<script> + goog.require('goog.structs'); + goog.require('goog.structs.AvlTree'); + goog.require('goog.testing.jsunit'); +</script> +</head> +<body> +<script> + + /** + * This test verifies that we can insert strings into the AvlTree and have + * them be stored and sorted correctly by the default comparator. + */ + function testInsertsWithDefaultComparator() { + var tree = new goog.structs.AvlTree(); + var values = ['bill', 'blake', 'elliot', 'jacob', 'john', 'myles', 'ted']; + + // Insert strings into tree out of order + tree.add(values[4]); + tree.add(values[3]); + tree.add(values[0]); + tree.add(values[6]); + tree.add(values[5]); + tree.add(values[1]); + tree.add(values[2]); + + // Verify strings are stored in sorted order + var i = 0; + tree.inOrderTraverse(function(value) { + assertEquals(values[i], value); + i += 1; + }); + assertEquals(i, values.length); + }; + + /** + * This test verifies that we can insert strings into and remove strings from + * the AvlTree and have the only the non-removed values be stored and sorted + * correctly by the default comparator. + */ + function testRemovesWithDefaultComparator() { + var tree = new goog.structs.AvlTree(); + var values = ['bill', 'blake', 'elliot', 'jacob', 'john', 'myles', 'ted']; + + // Insert strings into tree out of order + tree.add('frodo'); + tree.add(values[4]); + tree.add(values[3]); + tree.add(values[0]); + tree.add(values[6]); + tree.add('samwise'); + tree.add(values[5]); + tree.add(values[1]); + tree.add(values[2]); + tree.add('pippin'); + + // Remove strings from tree + assertEquals(tree.remove('samwise'), 'samwise'); + assertEquals(tree.remove('pippin'), 'pippin'); + assertEquals(tree.remove('frodo'), 'frodo'); + assertEquals(tree.remove('merry'), null); + + + // Verify strings are stored in sorted order + var i = 0; + tree.inOrderTraverse(function(value) { + assertEquals(values[i], value); + i += 1; + }); + assertEquals(i, values.length); + }; + + /** + * This test verifies that we can insert values into and remove values from + * the AvlTree and have them be stored and sorted correctly by a custom + * comparator. + */ + function testInsertsAndRemovesWithCustomComparator() { + var tree = new goog.structs.AvlTree(function(a, b) { + return a - b; + }); + + var NUM_TO_INSERT = 37; + var valuesToRemove = [1, 0, 6, 7, 36]; + + // Insert ints into tree out of order + var values = []; + for (var i = 0; i < NUM_TO_INSERT; i += 1) { + tree.add(i); + values.push(i); + } + + for (var i = 0; i < valuesToRemove.length; i += 1) { + assertEquals(tree.remove(valuesToRemove[i]), valuesToRemove[i]); + goog.array.remove(values, valuesToRemove[i]); + } + assertEquals(tree.remove(-1), null); + assertEquals(tree.remove(37), null); + + // Verify strings are stored in sorted order + var i = 0; + tree.inOrderTraverse(function(value) { + assertEquals(values[i], value); + i += 1; + }); + assertEquals(i, values.length); + }; + + /** + * This test verifies that we can insert values into and remove values from + * the AvlTree and have it maintain the AVL-Tree upperbound on its height. + */ + function testAvlTreeHeight() { + var tree = new goog.structs.AvlTree(function(a, b) { + return a - b; + }); + + var NUM_TO_INSERT = 2000; + var NUM_TO_REMOVE = 500; + + // Insert ints into tree out of order + for (var i = 0; i < NUM_TO_INSERT; i += 1) { + tree.add(i); + } + + // Remove valuse + for (var i = 0; i < NUM_TO_REMOVE; i += 1) { + tree.remove(i); + } + + assertTrue(tree.getHeight() <= 1.4405 * + (Math.log(NUM_TO_INSERT - NUM_TO_REMOVE + 2) / Math.log(2)) - 1.3277); + }; + + /** + * This test verifies that we can insert values into and remove values from + * the AvlTree and have its contains method correctly determine the values it + * is contains. + */ + function testAvlTreeContains() { + var tree = new goog.structs.AvlTree(); + var values = ['bill', 'blake', 'elliot', 'jacob', 'john', 'myles', 'ted']; + + // Insert strings into tree out of order + tree.add('frodo'); + tree.add(values[4]); + tree.add(values[3]); + tree.add(values[0]); + tree.add(values[6]); + tree.add('samwise'); + tree.add(values[5]); + tree.add(values[1]); + tree.add(values[2]); + tree.add('pippin'); + + // Remove strings from tree + assertEquals(tree.remove('samwise'), 'samwise'); + assertEquals(tree.remove('pippin'), 'pippin'); + assertEquals(tree.remove('frodo'), 'frodo'); + + for (var i = 0; i < values.length; i += 1) { + assertTrue(tree.contains(values[i])); + } + assertFalse(tree.contains('samwise')); + assertFalse(tree.contains('pippin')); + assertFalse(tree.contains('frodo')); + }; + + /** + * This test verifies that we can insert values into and remove values from + * the AvlTree and have its minValue and maxValue routines return the correct + * min and max values contained by the tree. + */ + function testMinAndMaxValues() { + var tree = new goog.structs.AvlTree(function(a, b) { + return a - b; + }); + + var NUM_TO_INSERT = 2000; + var NUM_TO_REMOVE = 500; + + // Insert ints into tree out of order + for (var i = 0; i < NUM_TO_INSERT; i += 1) { + tree.add(i); + } + + // Remove valuse + for (var i = 0; i < NUM_TO_REMOVE; i += 1) { + tree.remove(i); + } + + assertEquals(tree.getMinimum(), NUM_TO_REMOVE); + assertEquals(tree.getMaximum(), NUM_TO_INSERT - 1); + }; + + /** + * This test verifies that we can insert values into and remove values from + * the AvlTree and traverse the tree in reverse order using the + * reverseOrderTraverse routine. + */ + function testReverseOrderTraverse() { + var tree = new goog.structs.AvlTree(function(a, b) { + return a - b; + }); + + var NUM_TO_INSERT = 2000; + var NUM_TO_REMOVE = 500; + + // Insert ints into tree out of order + for (var i = 0; i < NUM_TO_INSERT; i += 1) { + tree.add(i); + } + + // Remove valuse + for (var i = 0; i < NUM_TO_REMOVE; i += 1) { + tree.remove(i); + } + + var i = NUM_TO_INSERT - 1; + tree.reverseOrderTraverse(function(value) { + assertEquals(value, i); + i -= 1; + }); + assertEquals(i, NUM_TO_REMOVE - 1); + }; + + /** + * Verifies correct behavior of getCount(). See http://b/4347755 + */ + function testGetCountBehavior() { + var tree = new goog.structs.AvlTree(); + tree.add(1); + tree.remove(1); + assertEquals(0, tree.getCount()); + } + +</script> +</body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/structs/circularbuffer.js b/contexts/data/lib/closure-library/closure/goog/structs/circularbuffer.js new file mode 100644 index 0000000..2964559 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/circularbuffer.js @@ -0,0 +1,219 @@ +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +/** + * @fileoverview Datastructure: Circular Buffer. + * + * Implements a buffer with a maximum size. New entries override the oldest + * entries when the maximum size has been reached. + * + */ + + +goog.provide('goog.structs.CircularBuffer'); + + + +/** + * Class for CircularBuffer. + * @param {number=} opt_maxSize The maximum size of the buffer. + * @constructor + */ +goog.structs.CircularBuffer = function(opt_maxSize) { + /** + * Maximum size of the the circular array structure. + * @type {number} + * @private + */ + this.maxSize_ = opt_maxSize || 100; + + /** + * Underlying array for the CircularBuffer. + * @type {Array} + * @private + */ + this.buff_ = []; +}; + + +/** + * Index of the next element in the circular array structure. + * @type {number} + * @private + */ +goog.structs.CircularBuffer.prototype.nextPtr_ = 0; + + +/** + * Adds an item to the buffer. May remove the oldest item if the buffer is at + * max size. + * @param {*} item The item to add. + */ +goog.structs.CircularBuffer.prototype.add = function(item) { + this.buff_[this.nextPtr_] = item; + this.nextPtr_ = (this.nextPtr_ + 1) % this.maxSize_; +}; + + +/** + * Returns the item at the specified index. + * @param {number} index The index of the item. The index of an item can change + * after calls to {@code add()} if the buffer is at maximum size. + * @return {*} The item at the specified index. + */ +goog.structs.CircularBuffer.prototype.get = function(index) { + index = this.normalizeIndex_(index); + return this.buff_[index]; +}; + + +/** + * Sets the item at the specified index. + * @param {number} index The index of the item. The index of an item can change + * after calls to {@code add()} if the buffer is at maximum size. + * @param {*} item The item to add. + */ +goog.structs.CircularBuffer.prototype.set = function(index, item) { + index = this.normalizeIndex_(index); + this.buff_[index] = item; +}; + + +/** + * Returns the current number of items in the buffer. + * @return {number} The current number of items in the buffer. + */ +goog.structs.CircularBuffer.prototype.getCount = function() { + return this.buff_.length; +}; + + +/** + * @return {boolean} Whether the buffer is empty. + */ +goog.structs.CircularBuffer.prototype.isEmpty = function() { + return this.buff_.length == 0; +}; + + +/** + * Empties the current buffer. + */ +goog.structs.CircularBuffer.prototype.clear = function() { + this.buff_.length = 0; + this.nextPtr_ = 0; +}; + + +/** + * @return {Array} The values in the buffer. + */ +goog.structs.CircularBuffer.prototype.getValues = function() { + // getNewestValues returns all the values if the maxCount parameter is the + // count + return this.getNewestValues(this.getCount()); +}; + + +/** + * Returns the newest values in the buffer up to {@code count}. + * @param {number} maxCount The maximum number of values to get. Should be a + * positive number. + * @return {Array} The newest values in the buffer up to {@code count}. + */ +goog.structs.CircularBuffer.prototype.getNewestValues = function(maxCount) { + var l = this.getCount(); + var start = this.getCount() - maxCount; + var rv = []; + for (var i = start; i < l; i++) { + rv[i] = this.get(i); + } + return rv; +}; + + +/** + * @return {Array} The indexes in the buffer. + */ +goog.structs.CircularBuffer.prototype.getKeys = function() { + var rv = []; + var l = this.getCount(); + for (var i = 0; i < l; i++) { + rv[i] = i; + } + return rv; +}; + + +/** + * Whether the buffer contains the key/index. + * @param {number} key The key/index to check for. + * @return {boolean} Whether the buffer contains the key/index. + */ +goog.structs.CircularBuffer.prototype.containsKey = function(key) { + return key < this.getCount(); +}; + + +/** + * Whether the buffer contains the given value. + * @param {*} value The value to check for. + * @return {boolean} Whether the buffer contains the given value. + */ +goog.structs.CircularBuffer.prototype.containsValue = function(value) { + var l = this.getCount(); + for (var i = 0; i < l; i++) { + if (this.get(i) == value) { + return true; + } + } + return false; +}; + + +/** + * Returns the last item inserted into the buffer. + * @return {*} The last item inserted into the buffer, or null if the buffer is + * empty. + */ +goog.structs.CircularBuffer.prototype.getLast = function() { + if (this.getCount() == 0) { + return null; + } + return this.get(this.getCount() - 1); +}; + + +/** + * Helper function to convert an index in the number space of oldest to + * newest items in the array to the position that the element will be at in the + * underlying array. + * @param {number} index The index of the item in a list ordered from oldest to + * newest. + * @return {number} The index of the item in the CircularBuffer's underlying + * array. + * @private + */ +goog.structs.CircularBuffer.prototype.normalizeIndex_ = function(index) { + if (index >= this.buff_.length) { + throw Error('Out of bounds exception'); + } + + if (this.buff_.length < this.maxSize_) { + return index; + } + + return (this.nextPtr_ + Number(index)) % this.maxSize_; +}; diff --git a/contexts/data/lib/closure-library/closure/goog/structs/circularbuffer_test.html b/contexts/data/lib/closure-library/closure/goog/structs/circularbuffer_test.html new file mode 100644 index 0000000..8d891c8 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/circularbuffer_test.html @@ -0,0 +1,105 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright 2006 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> +<head> +<meta http-equiv="X-UA-Compatible" content="IE=edge"> +<title>Closure Unit Tests - goog.structs</title> +<script src="../base.js"></script> +<script> + goog.require('goog.structs.CircularBuffer'); + goog.require('goog.testing.jsunit'); +</script> +</head> +<body> +<script> + +function testCircularBuffer() { + var buff = new goog.structs.CircularBuffer(2); + buff.add('first'); + assertEquals(1, buff.getCount()); + assertEquals('first', buff.get(0)); + assertEquals('first', buff.getLast()); + buff.add('second'); + assertEquals(2, buff.getCount()); + assertEquals('first', buff.get(0)); + assertEquals('second', buff.get(1)); + assertEquals('second', buff.getLast()); + buff.add('third'); + assertEquals(2, buff.getCount()); + assertEquals('second', buff.get(0)); + assertEquals('third', buff.get(1)); + assertEquals('third', buff.getLast()); +} + +function testIsEmpty() { + var buff = new goog.structs.CircularBuffer(2); + assertTrue('initially empty', buff.isEmpty()); + buff.add('first'); + assertFalse('not empty after add empty', buff.isEmpty()); +} + +function testClear() { + var buff = new goog.structs.CircularBuffer(2); + buff.add('first'); + buff.clear(); + assertTrue('should be empty after clear', buff.isEmpty()); + +} + +function testGetValues() { + var buff = new goog.structs.CircularBuffer(2); + buff.add('first'); + buff.add('second'); + assertEquals('firstsecond', buff.getValues().join('')); +} + +function testGetNewestVtalues() { + var buff = new goog.structs.CircularBuffer(5); + buff.add('first'); + buff.add('second'); + buff.add('third'); + buff.add('fourth'); + buff.add('fifth'); + assertEquals('fourthfifth', buff.getNewestValues(2).join('')); +} + + +function testGetKeys() { + var buff = new goog.structs.CircularBuffer(2); + buff.add('first'); + buff.add('second'); + assertEquals('01', buff.getKeys().join('')); +} + +function testContainsValue() { + var buff = new goog.structs.CircularBuffer(2); + buff.add('first'); + buff.add('second'); + assertTrue(buff.containsValue('first')); + assertTrue(buff.containsValue('second')); + assertFalse(buff.containsValue('third')); +} + +function testContainsKey() { + var buff = new goog.structs.CircularBuffer(3); + buff.add('first'); + buff.add('second'); + buff.add('third'); + assertTrue(buff.containsKey(0)); + assertTrue(buff.containsKey('0')); + assertTrue(buff.containsKey(1)); + assertTrue(buff.containsKey('1')); + assertTrue(buff.containsKey(2)); + assertTrue(buff.containsKey('2')); + assertFalse(buff.containsKey(3)); + assertFalse(buff.containsKey('3')); +} + +</script> +</body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/structs/collection.js b/contexts/data/lib/closure-library/closure/goog/structs/collection.js new file mode 100644 index 0000000..8ba8cb3 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/collection.js @@ -0,0 +1,54 @@ +// Copyright 2011 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Defines the collection interface. + * + */ + +goog.provide('goog.structs.Collection'); + + + +/** + * An interface for a collection of values. + * @interface + */ +goog.structs.Collection = function() {}; + + +/** + * @param {*} value Value to add to the collection. + */ +goog.structs.Collection.prototype.add; + + +/** + * @param {*} value Value to remove from the collection. + */ +goog.structs.Collection.prototype.remove; + + +/** + * @param {*} value Value to find in the tree. + * @return {boolean} Whether the collection contains the specified value. + */ +goog.structs.Collection.prototype.contains; + + +/** + * @return {number} The number of values stored in the collection. + */ +goog.structs.Collection.prototype.getCount; + diff --git a/contexts/data/lib/closure-library/closure/goog/structs/collection_test.html b/contexts/data/lib/closure-library/closure/goog/structs/collection_test.html new file mode 100644 index 0000000..1ce9932 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/collection_test.html @@ -0,0 +1,57 @@ +<!doctype html> +<html> +<!-- +Copyright 2011 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> + <head> + <title>Closure Unit Tests - goog.structs.Collection</title> + <script src="../base.js"></script> + <script> + goog.require('goog.structs.AvlTree'); + goog.require('goog.structs.Collection'); + goog.require('goog.structs.Set'); + goog.require('goog.testing.jsunit'); + </script> + </head> + <body> + <script> + +function testSet() { + var set = new goog.structs.Set(); + exerciseCollection(set) +} + +function testAvlTree() { + var tree = new goog.structs.AvlTree(); + exerciseCollection(tree) +} + +// Simple exercise of a collection object. +function exerciseCollection(collection) { + assertEquals(0, collection.getCount()); + + for (var i = 1; i <= 10; i++) { + assertFalse(collection.contains(i)); + collection.add(i); + assertTrue(collection.contains(i)); + assertEquals(i, collection.getCount()); + } + + assertEquals(10, collection.getCount()); + + for (var i = 10; i > 0; i--) { + assertTrue(collection.contains(i)); + collection.remove(i); + assertFalse(collection.contains(i)); + assertEquals(i - 1, collection.getCount()); + } + + assertEquals(0, collection.getCount()); +} + + </script> + </body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/structs/heap.js b/contexts/data/lib/closure-library/closure/goog/structs/heap.js new file mode 100644 index 0000000..98c7695 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/heap.js @@ -0,0 +1,333 @@ +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Datastructure: Heap. + * + * + * This file provides the implementation of a Heap datastructure. Smaller keys + * rise to the top. + * + * The big-O notation for all operations are below: + * <pre> + * Method big-O + * ---------------------------------------------------------------------------- + * - insert O(logn) + * - remove O(logn) + * - peek O(1) + * - contains O(n) + * </pre> + */ +// TODO(user): Should this rely on natural ordering via some Comparable +// interface? + + +goog.provide('goog.structs.Heap'); + +goog.require('goog.array'); +goog.require('goog.object'); +goog.require('goog.structs.Node'); + + + +/** + * Class for a Heap datastructure. + * + * @param {goog.structs.Heap|Object=} opt_heap Optional goog.structs.Heap or + * Object to initialize heap with. + * @constructor + */ +goog.structs.Heap = function(opt_heap) { + /** + * The nodes of the heap. + * @private + * @type {Array.<goog.structs.Node>} + */ + this.nodes_ = []; + + if (opt_heap) { + this.insertAll(opt_heap); + } +}; + + +/** + * Insert the given value into the heap with the given key. + * @param {*} key The key. + * @param {*} value The value. + */ +goog.structs.Heap.prototype.insert = function(key, value) { + var node = new goog.structs.Node(key, value); + var nodes = this.nodes_; + nodes.push(node); + this.moveUp_(nodes.length - 1); +}; + + +/** + * Adds multiple key-value pairs from another goog.structs.Heap or Object + * @param {goog.structs.Heap|Object} heap Object containing the data to add. + */ +goog.structs.Heap.prototype.insertAll = function(heap) { + var keys, values; + if (heap instanceof goog.structs.Heap) { + keys = heap.getKeys(); + values = heap.getValues(); + + // If it is a heap and the current heap is empty, I can realy on the fact + // that the keys/values are in the correct order to put in the underlying + // structure. + if (heap.getCount() <= 0) { + var nodes = this.nodes_; + for (var i = 0; i < keys.length; i++) { + nodes.push(new goog.structs.Node(keys[i], values[i])); + } + return; + } + } else { + keys = goog.object.getKeys(heap); + values = goog.object.getValues(heap); + } + + for (var i = 0; i < keys.length; i++) { + this.insert(keys[i], values[i]); + } +}; + + +/** + * Retrieves and removes the root value of this heap. + * @return {*} The value removed from the root of the heap. Returns + * undefined if the heap is empty. + */ +goog.structs.Heap.prototype.remove = function() { + var nodes = this.nodes_; + var count = nodes.length; + var rootNode = nodes[0]; + if (count <= 0) { + return undefined; + } else if (count == 1) { + goog.array.clear(nodes); + } else { + nodes[0] = nodes.pop(); + this.moveDown_(0); + } + return rootNode.getValue(); +}; + + +/** + * Retrieves but does not remove the root value of this heap. + * @return {*} The value at the root of the heap. Returns + * undefined if the heap is empty. + */ +goog.structs.Heap.prototype.peek = function() { + var nodes = this.nodes_; + if (nodes.length == 0) { + return undefined; + } + return nodes[0].getValue(); +}; + + +/** + * Retrieves but does not remove the key of the root node of this heap. + * @return {*} The key at the root of the heap. Returns undefined if the + * heap is empty. + */ +goog.structs.Heap.prototype.peekKey = function() { + return this.nodes_[0] && this.nodes_[0].getKey(); +}; + + +/** + * Moves the node at the given index down to its proper place in the heap. + * @param {number} index The index of the node to move down. + * @private + */ +goog.structs.Heap.prototype.moveDown_ = function(index) { + var nodes = this.nodes_; + var count = nodes.length; + + // Save the node being moved down. + var node = nodes[index]; + // While the current node has a child. + while (index < (count >> 1)) { + var leftChildIndex = this.getLeftChildIndex_(index); + var rightChildIndex = this.getRightChildIndex_(index); + + // Determine the index of the smaller child. + var smallerChildIndex = rightChildIndex < count && + nodes[rightChildIndex].getKey() < nodes[leftChildIndex].getKey() ? + rightChildIndex : leftChildIndex; + + // If the node being moved down is smaller than its children, the node + // has found the correct index it should be at. + if (nodes[smallerChildIndex].getKey() > node.getKey()) { + break; + } + + // If not, then take the smaller child as the current node. + nodes[index] = nodes[smallerChildIndex]; + index = smallerChildIndex; + } + nodes[index] = node; +}; + + +/** + * Moves the node at the given index up to its proper place in the heap. + * @param {number} index The index of the node to move up. + * @private + */ +goog.structs.Heap.prototype.moveUp_ = function(index) { + var nodes = this.nodes_; + var node = nodes[index]; + + // While the node being moved up is not at the root. + while (index > 0) { + // If the parent is less than the node being moved up, move the parent down. + var parentIndex = this.getParentIndex_(index); + if (nodes[parentIndex].getKey() > node.getKey()) { + nodes[index] = nodes[parentIndex]; + index = parentIndex; + } else { + break; + } + } + nodes[index] = node; +}; + + +/** + * Gets the index of the left child of the node at the given index. + * @param {number} index The index of the node to get the left child for. + * @return {number} The index of the left child. + * @private + */ +goog.structs.Heap.prototype.getLeftChildIndex_ = function(index) { + return index * 2 + 1; +}; + + +/** + * Gets the index of the right child of the node at the given index. + * @param {number} index The index of the node to get the right child for. + * @return {number} The index of the right child. + * @private + */ +goog.structs.Heap.prototype.getRightChildIndex_ = function(index) { + return index * 2 + 2; +}; + + +/** + * Gets the index of the parent of the node at the given index. + * @param {number} index The index of the node to get the parent for. + * @return {number} The index of the parent. + * @private + */ +goog.structs.Heap.prototype.getParentIndex_ = function(index) { + return (index - 1) >> 1; +}; + + +/** + * Gets the values of the heap. + * @return {Array} The values in the heap. + */ +goog.structs.Heap.prototype.getValues = function() { + var nodes = this.nodes_; + var rv = []; + var l = nodes.length; + for (var i = 0; i < l; i++) { + rv.push(nodes[i].getValue()); + } + return rv; +}; + + +/** + * Gets the keys of the heap. + * @return {Array} The keys in the heap. + */ +goog.structs.Heap.prototype.getKeys = function() { + var nodes = this.nodes_; + var rv = []; + var l = nodes.length; + for (var i = 0; i < l; i++) { + rv.push(nodes[i].getKey()); + } + return rv; +}; + + +/** + * Whether the heap contains the given value. + * @param {Object} val The value to check for. + * @return {boolean} Whether the heap contains the value. + */ +goog.structs.Heap.prototype.containsValue = function(val) { + return goog.array.some(this.nodes_, function(node) { + return node.getValue() == val; + }); +}; + + +/** + * Whether the heap contains the given key. + * @param {Object} key The key to check for. + * @return {boolean} Whether the heap contains the key. + */ +goog.structs.Heap.prototype.containsKey = function(key) { + return goog.array.some(this.nodes_, function(node) { + return node.getKey() == key; + }); +}; + + +/** + * Clones a heap and returns a new heap + * @return {goog.structs.Heap} A new goog.structs.Heap with the same key-value + * pairs. + */ +goog.structs.Heap.prototype.clone = function() { + return new goog.structs.Heap(this); +}; + + +/** + * The number of key-value pairs in the map + * @return {number} The number of pairs. + */ +goog.structs.Heap.prototype.getCount = function() { + return this.nodes_.length; +}; + + +/** + * Returns true if this heap contains no elements. + * @return {boolean} Whether this heap contains no elements. + */ +goog.structs.Heap.prototype.isEmpty = function() { + return goog.array.isEmpty(this.nodes_); +}; + + +/** + * Removes all elements from the heap. + */ +goog.structs.Heap.prototype.clear = function() { + goog.array.clear(this.nodes_); +}; diff --git a/contexts/data/lib/closure-library/closure/goog/structs/heap_test.html b/contexts/data/lib/closure-library/closure/goog/structs/heap_test.html new file mode 100644 index 0000000..de7e093 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/heap_test.html @@ -0,0 +1,220 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright 2006 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> +<head> +<meta http-equiv="X-UA-Compatible" content="IE=edge"> +<title>Closure Unit Tests - goog.structs.Heap</title> +<script src="../base.js"></script> +<script> + goog.require('goog.structs'); + goog.require('goog.structs.Heap'); + goog.require('goog.testing.jsunit'); +</script> +</head> +<body> +<script> + +function getHeap() { + var h = new goog.structs.Heap(); + h.insert(0, 'a'); + h.insert(1, 'b'); + h.insert(2, 'c'); + h.insert(3, 'd'); + return h; +} + + +function getHeap2() { + var h = new goog.structs.Heap(); + h.insert(1, 'b'); + h.insert(3, 'd'); + h.insert(0, 'a'); + h.insert(2, 'c'); + return h; +} + + +function testGetCount1() { + var h = getHeap(); + assertEquals('count, should be 4', h.getCount(), 4); + h.remove(); + assertEquals('count, should be 3', h.getCount(), 3); +} + +function testGetCount2() { + var h = getHeap(); + h.remove(); + h.remove(); + h.remove(); + h.remove(); + assertEquals('count, should be 0', h.getCount(), 0); +} + + +function testKeys() { + var h = getHeap(); + var keys = h.getKeys(); + for (var i = 0; i < 4; i++) { + assertTrue('getKeys, key ' + i + ' found', goog.structs.contains(keys, i)); + } + assertEquals('getKeys, Should be 4 keys', goog.structs.getCount(keys), 4); +} + + +function testValues() { + var h = getHeap(); + var values = h.getValues(); + + assertTrue('getKeys, value "a" found', goog.structs.contains(values, 'a')); + assertTrue('getKeys, value "b" found', goog.structs.contains(values, 'b')); + assertTrue('getKeys, value "c" found', goog.structs.contains(values, 'c')); + assertTrue('getKeys, value "d" found', goog.structs.contains(values, 'd')); + assertEquals('getKeys, Should be 4 keys', goog.structs.getCount(values), 4); +} + + +function testContainsKey() { + var h = getHeap(); + + for (var i = 0; i < 4; i++) { + assertTrue('containsKey, key ' + i + ' found', h.containsKey(i)); + } + assertFalse('containsKey, value 4 not found', h.containsKey(4)); +} + + +function testContainsValue() { + var h = getHeap(); + + assertTrue('containsValue, value "a" found', h.containsValue('a')); + assertTrue('containsValue, value "b" found', h.containsValue('b')); + assertTrue('containsValue, value "c" found', h.containsValue('c')); + assertTrue('containsValue, value "d" found', h.containsValue('d')); + assertFalse('containsValue, value "e" not found', h.containsValue('e')); +} + + +function testClone() { + var h = getHeap(); + var h2 = h.clone(); + assertTrue('clone so it should not be empty', !h2.isEmpty()); + assertTrue('clone so it should contain key 0', h2.containsKey(0)); + assertTrue('clone so it should contain value "a"', h2.containsValue('a')); +} + + +function testClear() { + var h = getHeap(); + h.clear(); + assertTrue('cleared so it should be empty', h.isEmpty()); +} + + +function testIsEmpty() { + var h = getHeap(); + assertFalse('4 values so should not be empty', h.isEmpty()); + + h.remove(); + h.remove(); + h.remove(); + assertFalse('1 values so should not be empty', h.isEmpty()); + + h.remove(); + assertTrue('0 values so should be empty', h.isEmpty()); +} + + +function testPeek1() { + var h = getHeap(); + assertEquals('peek, Should be "a"', h.peek(), 'a'); +} + + +function testPeek2() { + var h = getHeap2(); + assertEquals('peek, Should be "a"', h.peek(), 'a'); +} + + +function testPeek3() { + var h = getHeap(); + h.clear(); + assertEquals('peek, Should be "undefined"', h.peek(), undefined); +} + + +function testPeekKey1() { + var h = getHeap(); + assertEquals('peekKey, Should be "0"', h.peekKey(), 0); +} + + +function testPeekKey2() { + var h = getHeap2(); + assertEquals('peekKey, Should be "0"', h.peekKey(), 0); +} + + +function testPeekKey3() { + var h = getHeap(); + h.clear(); + assertEquals('peekKey, Should be "undefined"', h.peekKey(), undefined); +} + + +function testRemove1() { + var h = getHeap(); + + assertEquals('remove, Should be "a"', h.remove(), 'a'); + assertEquals('remove, Should be "b"', h.remove(), 'b'); + assertEquals('remove, Should be "c"', h.remove(), 'c'); + assertEquals('remove, Should be "d"', h.remove(), 'd'); +} + + +function testRemove2() { + var h = getHeap2(); + + assertEquals('remove, Should be "a"', h.remove(), 'a'); + assertEquals('remove, Should be "b"', h.remove(), 'b'); + assertEquals('remove, Should be "c"', h.remove(), 'c'); + assertEquals('remove, Should be "d"', h.remove(), 'd'); +} + + +function testInsertPeek1() { + var h = new goog.structs.Heap(); + + h.insert(3, 'd'); + assertEquals('peek, Should be "d"', h.peek(), 'd'); + h.insert(2, 'c'); + assertEquals('peek, Should be "c"', h.peek(), 'c'); + h.insert(1, 'b'); + assertEquals('peek, Should be "b"', h.peek(), 'b'); + h.insert(0, 'a'); + assertEquals('peek, Should be "a"', h.peek(), 'a'); +} + + +function testInsertPeek2() { + var h = new goog.structs.Heap(); + + h.insert(1, 'b'); + assertEquals('peak, Should be "b"', h.peek(), 'b'); + h.insert(3, 'd'); + assertEquals('peak, Should be "b"', h.peek(), 'b'); + h.insert(0, 'a'); + assertEquals('peak, Should be "a"', h.peek(), 'a'); + h.insert(2, 'c'); + assertEquals('peak, Should be "a"', h.peek(), 'a'); +} + + +</script> +</body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/structs/inversionmap.js b/contexts/data/lib/closure-library/closure/goog/structs/inversionmap.js new file mode 100644 index 0000000..1c7c2e2 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/inversionmap.js @@ -0,0 +1,159 @@ +// Copyright 2008 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Provides inversion and inversion map functionality for storing + * integer ranges and corresponding values. + * + */ + +goog.provide('goog.structs.InversionMap'); + +goog.require('goog.array'); + + + +/** + * Maps ranges to values using goog.structs.Inversion. + * @param {Array.<number>} rangeArray An array of monotonically + * increasing integer values, with at least one instance. + * @param {Array.<*>} valueArray An array of corresponding values. + * Length must be the same as rangeArray. + * @param {boolean=} opt_delta If true, saves only delta from previous value. + * @constructor + */ +goog.structs.InversionMap = function(rangeArray, valueArray, opt_delta) { + if (rangeArray.length != valueArray.length) { + // rangeArray and valueArray has to match in number of entries. + return null; + } + this.storeInversion_(rangeArray, opt_delta); + + /** + * @type {Array} + * @protected + */ + this.values = valueArray; +}; + + +/** + * @type {Array} + * @protected + */ +goog.structs.InversionMap.prototype.rangeArray; + + +/** + * Stores the integers as ranges (half-open). + * If delta is true, the integers are delta from the previous value and + * will be restored to the absolute value. + * When used as a set, even indices are IN, and odd are OUT. + * @param {Array.<number?>} rangeArray An array of monotonically + * increasing integer values, with at least one instance. + * @param {boolean=} opt_delta If true, saves only delta from previous value. + * @private + */ +goog.structs.InversionMap.prototype.storeInversion_ = function(rangeArray, + opt_delta) { + this.rangeArray = rangeArray; + + for (var i = 1; i < rangeArray.length; i++) { + if (rangeArray[i] == null) { + rangeArray[i] = rangeArray[i - 1] + 1; + } else if (opt_delta) { + rangeArray[i] += rangeArray[i - 1]; + } + } +}; + + +/** + * Splices a range -> value map into this inversion map. + * @param {Array.<number>} rangeArray An array of monotonically + * increasing integer values, with at least one instance. + * @param {Array.<*>} valueArray An array of corresponding values. + * Length must be the same as rangeArray. + * @param {boolean=} opt_delta If true, saves only delta from previous value. + */ +goog.structs.InversionMap.prototype.spliceInversion = function( + rangeArray, valueArray, opt_delta) { + // By building another inversion map, we build the arrays that we need + // to splice in. + var otherMap = new goog.structs.InversionMap( + rangeArray, valueArray, opt_delta); + + // Figure out where to splice those arrays. + var startRange = otherMap.rangeArray[0]; + var endRange = + (/** @type {number} */ goog.array.peek(otherMap.rangeArray)); + var startSplice = this.getLeast(startRange); + var endSplice = this.getLeast(endRange); + + // The inversion map works by storing the start points of ranges... + if (startRange != this.rangeArray[startSplice]) { + // ...if we're splicing in a start point that isn't already here, + // then we need to insert it after the insertion point. + startSplice++; + } // otherwise we overwrite the insertion point. + + var spliceLength = endSplice - startSplice + 1; + goog.partial(goog.array.splice, this.rangeArray, startSplice, + spliceLength).apply(null, otherMap.rangeArray); + goog.partial(goog.array.splice, this.values, startSplice, + spliceLength).apply(null, otherMap.values); +}; + + +/** + * Gets the value corresponding to a number from the inversion map. + * @param {number} intKey The number for which value needs to be retrieved + * from inversion map. + * @return {*} Value retrieved from inversion map; null if not found. + */ +goog.structs.InversionMap.prototype.at = function(intKey) { + var index = this.getLeast(intKey); + if (index < 0) { + return null; + } + return this.values[index]; +}; + + +/** + * Gets the largest index such that rangeArray[index] <= intKey from the + * inversion map. + * @param {number} intKey The probe for which rangeArray is searched. + * @return {number} Largest index such that rangeArray[index] <= intKey. + * @protected + */ +goog.structs.InversionMap.prototype.getLeast = function(intKey) { + var arr = this.rangeArray; + var low = 0; + var high = arr.length; + while (high - low > 8) { + var mid = (high + low) >> 1; + if (arr[mid] <= intKey) { + low = mid; + } else { + high = mid; + } + } + for (; low < high; ++low) { + if (intKey < arr[low]) { + break; + } + } + return low - 1; +}; diff --git a/contexts/data/lib/closure-library/closure/goog/structs/inversionmap_test.html b/contexts/data/lib/closure-library/closure/goog/structs/inversionmap_test.html new file mode 100644 index 0000000..d461edf --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/inversionmap_test.html @@ -0,0 +1,157 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright 2008 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> +<head> +<meta http-equiv="X-UA-Compatible" content="IE=edge"> +<title>Closure Unit Tests - goog.structs.InversionMap</title> +<script type="text/javascript" src="../base.js"></script> +<script type="text/javascript"> + goog.require('goog.structs.InversionMap'); + goog.require('goog.testing.jsunit'); +</script> +</head> +<body> +<script type="text/javascript"> + function testInversionWithDelta() { + var alphabetNames = new goog.structs.InversionMap( + [ 0, 97, 1, 1, 1, 20, 1, 1, 1 ], + [ null, + 'LATIN SMALL LETTER A', + 'LATIN SMALL LETTER B', + 'LATIN SMALL LETTER C', + null, + 'LATIN SMALL LETTER X', + 'LATIN SMALL LETTER Y', + 'LATIN SMALL LETTER Z', + null ], + true); + + assertEquals('LATIN SMALL LETTER A', alphabetNames.at(97)); + assertEquals('LATIN SMALL LETTER Y', alphabetNames.at(121)); + assertEquals(null, alphabetNames.at(140)); + assertEquals(null, alphabetNames.at(0)); + } + + function testInversionWithoutDelta() { + var alphabetNames = new goog.structs.InversionMap( + [ 0, 97, 98, 99, 100, 120, 121, 122, 123 ], + [ null, + 'LATIN SMALL LETTER A', + 'LATIN SMALL LETTER B', + 'LATIN SMALL LETTER C', + null, + 'LATIN SMALL LETTER X', + 'LATIN SMALL LETTER Y', + 'LATIN SMALL LETTER Z', + null ], + false); + + assertEquals('LATIN SMALL LETTER A', alphabetNames.at(97)); + assertEquals('LATIN SMALL LETTER Y', alphabetNames.at(121)); + assertEquals(null, alphabetNames.at(140)); + assertEquals(null, alphabetNames.at(0)); + } + + function testInversionWithoutDeltaNoOpt() { + var alphabetNames = new goog.structs.InversionMap( + [ 0, 97, 98, 99, 100, 120, 121, 122, 123 ], + [ null, + 'LATIN SMALL LETTER A', + 'LATIN SMALL LETTER B', + 'LATIN SMALL LETTER C', + null, + 'LATIN SMALL LETTER X', + 'LATIN SMALL LETTER Y', + 'LATIN SMALL LETTER Z', + null ]); + + assertEquals('LATIN SMALL LETTER A', alphabetNames.at(97)); + assertEquals('LATIN SMALL LETTER Y', alphabetNames.at(121)); + assertEquals(null, alphabetNames.at(140)); + assertEquals(null, alphabetNames.at(0)); + } + + function testInversionMapSplice1() { + var alphabetNames = newAsciiMap(); + alphabetNames.spliceInversion( + [ 99, 105, 114 ], [ 'XXX', 'YYY', 'ZZZ' ]); + assertEquals('LATIN SMALL LETTER B', alphabetNames.at(98)); + assertEquals('XXX', alphabetNames.at(100)); + assertEquals('ZZZ', alphabetNames.at(114)); + assertEquals('ZZZ', alphabetNames.at(119)); + assertEquals('LATIN SMALL LETTER X', alphabetNames.at(120)); + } + + function testInversionMapSplice2() { + var alphabetNames = newAsciiMap(); + alphabetNames.spliceInversion( + [ 105, 114, 121 ], [ 'XXX', 'YYY', 'ZZZ' ]); + assertEquals(null, alphabetNames.at(104)); + assertEquals('XXX', alphabetNames.at(105)); + assertEquals('YYY', alphabetNames.at(120)); + assertEquals('ZZZ', alphabetNames.at(121)); + assertEquals('LATIN SMALL LETTER Z', alphabetNames.at(122)); + } + + function testInversionMapSplice3() { + var alphabetNames = newAsciiMap(); + alphabetNames.spliceInversion( + [ 98, 99 ], [ 'CHANGED LETTER B', 'CHANGED LETTER C' ]); + assertEquals('LATIN SMALL LETTER A', alphabetNames.at(97)); + assertEquals('CHANGED LETTER B', alphabetNames.at(98)); + assertEquals('CHANGED LETTER C', alphabetNames.at(99)); + assertEquals('LATIN SMALL LETTER D', alphabetNames.at(100)); + assertEquals(null, alphabetNames.at(101)); + } + + function testInversionMapSplice4() { + var alphabetNames = newAsciiMap(); + alphabetNames.spliceInversion( + [ 98, 1 ], [ 'CHANGED LETTER B', 'CHANGED LETTER C' ], + true /* delta mode */); + assertEquals('LATIN SMALL LETTER A', alphabetNames.at(97)); + assertEquals('CHANGED LETTER B', alphabetNames.at(98)); + assertEquals('CHANGED LETTER C', alphabetNames.at(99)); + assertEquals('LATIN SMALL LETTER D', alphabetNames.at(100)); + assertEquals(null, alphabetNames.at(101)); + } + + function testInversionMapSplice5() { + var map = new goog.structs.InversionMap( + [0, 97, 98, 99], + [null, + 'LATIN SMALL LETTER A', + 'LATIN SMALL LETTER B', + 'LATIN SMALL LETTER C']); + map.spliceInversion( + [98], ['CHANGED LETTER B']); + assertEquals('LATIN SMALL LETTER A', map.at(97)); + assertEquals('CHANGED LETTER B', map.at(98)); + assertEquals('LATIN SMALL LETTER C', map.at(99)); + + assertArrayEquals([0, 97, 98, 99], map.rangeArray); + } + + function newAsciiMap() { + return new goog.structs.InversionMap( + [ 0, 97, 98, 99, 100, 101, 120, 121, 122, 123 ], + [ null, + 'LATIN SMALL LETTER A', + 'LATIN SMALL LETTER B', + 'LATIN SMALL LETTER C', + 'LATIN SMALL LETTER D', + null, + 'LATIN SMALL LETTER X', + 'LATIN SMALL LETTER Y', + 'LATIN SMALL LETTER Z', + null ]); + } + +</script> +</body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/structs/linkedmap.js b/contexts/data/lib/closure-library/closure/goog/structs/linkedmap.js new file mode 100644 index 0000000..bfaf230 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/linkedmap.js @@ -0,0 +1,472 @@ +// Copyright 2007 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview A LinkedMap data structure that is accessed using key/value + * pairs like an ordinary Map, but which guarantees a consistent iteration + * order over its entries. The iteration order is either insertion order (the + * default) or ordered from most recent to least recent use. By setting a fixed + * size, the LRU version of the LinkedMap makes an effective object cache. This + * data structure is similar to Java's LinkedHashMap. + * + */ + + +goog.provide('goog.structs.LinkedMap'); + +goog.require('goog.structs.Map'); + + + +/** + * Class for a LinkedMap datastructure, which combines O(1) map access for + * key/value pairs with a linked list for a consistent iteration order. Sample + * usage: + * + * <pre> + * var m = new LinkedMap(); + * m.set('param1', 'A'); + * m.set('param2', 'B'); + * m.set('param3', 'C'); + * alert(m.getKeys()); // param1, param2, param3 + * + * var c = new LinkedMap(5, true); + * for (var i = 0; i < 10; i++) { + * c.set('entry' + i, false); + * } + * alert(c.getKeys()); // entry9, entry8, entry7, entry6, entry5 + * + * c.set('entry5', true); + * c.set('entry1', false); + * alert(c.getKeys()); // entry1, entry5, entry9, entry8, entry7 + * </pre> + * + * @param {number=} opt_maxCount The maximum number of objects to store in the + * LinkedMap. If unspecified or 0, there is no maximum. + * @param {boolean=} opt_cache When set, the LinkedMap stores items in order + * from most recently used to least recently used, instead of insertion + * order. + * @constructor + */ +goog.structs.LinkedMap = function(opt_maxCount, opt_cache) { + /** + * The maximum number of entries to allow, or null if there is no limit. + * @type {?number} + * @private + */ + this.maxCount_ = opt_maxCount || null; + + /** + * @type {boolean} + * @private + */ + this.cache_ = !!opt_cache; + + this.map_ = new goog.structs.Map(); + + this.head_ = new goog.structs.LinkedMap.Node_('', undefined); + this.head_.next = this.head_.prev = this.head_; +}; + + +/** + * Finds a node and updates it to be the most recently used. + * @param {string} key The key of the node. + * @return {goog.structs.LinkedMap.Node_} The node or null if not found. + * @private + */ +goog.structs.LinkedMap.prototype.findAndMoveToTop_ = function(key) { + var node = /** @type {goog.structs.LinkedMap.Node_} */ (this.map_.get(key)); + if (node) { + if (this.cache_) { + node.remove(); + this.insert_(node); + } + } + return node; +}; + + +/** + * Retrieves the value for a given key. If this is a caching LinkedMap, the + * entry will become the most recently used. + * @param {string} key The key to retrieve the value for. + * @param {*=} opt_val A default value that will be returned if the key is + * not found, defaults to undefined. + * @return {*} The retrieved value. + */ +goog.structs.LinkedMap.prototype.get = function(key, opt_val) { + var node = this.findAndMoveToTop_(key); + return node ? node.value : opt_val; +}; + + +/** + * Retrieves the value for a given key without updating the entry to be the + * most recently used. + * @param {string} key The key to retrieve the value for. + * @param {*=} opt_val A default value that will be returned if the key is + * not found. + * @return {*} The retrieved value. + */ +goog.structs.LinkedMap.prototype.peekValue = function(key, opt_val) { + var node = this.map_.get(key); + return node ? node.value : opt_val; +}; + + +/** + * Sets a value for a given key. If this is a caching LinkedMap, this entry + * will become the most recently used. + * @param {string} key The key to retrieve the value for. + * @param {*} value A default value that will be returned if the key is + * not found. + */ +goog.structs.LinkedMap.prototype.set = function(key, value) { + var node = this.findAndMoveToTop_(key); + if (node) { + node.value = value; + } else { + node = new goog.structs.LinkedMap.Node_(key, value); + this.map_.set(key, node); + this.insert_(node); + } +}; + + +/** + * Returns the value of the first node without making any modifications. + * @return {*} The value of the first node or undefined if the map is empty. + */ +goog.structs.LinkedMap.prototype.peek = function() { + return this.head_.next.value; +}; + + +/** + * Returns the value of the last node without making any modifications. + * @return {*} The value of the last node or undefined if the map is empty. + */ +goog.structs.LinkedMap.prototype.peekLast = function() { + return this.head_.prev.value; +}; + + +/** + * Removes the first node from the list and returns its value. + * @return {*} The value of the popped node, or undefined if the map was empty. + */ +goog.structs.LinkedMap.prototype.shift = function() { + return this.popNode_(this.head_.next); +}; + + +/** + * Removes the last node from the list and returns its value. + * @return {*} The value of the popped node, or undefined if the map was empty. + */ +goog.structs.LinkedMap.prototype.pop = function() { + return this.popNode_(this.head_.prev); +}; + + +/** + * Removes a value from the LinkedMap based on its key. + * @param {string} key The key to remove. + * @return {boolean} True if the entry was removed, false if the key was not + * found. + */ +goog.structs.LinkedMap.prototype.remove = function(key) { + var node = /** @type {goog.structs.LinkedMap.Node_} */ (this.map_.get(key)); + if (node) { + this.removeNode(node); + return true; + } + return false; +}; + + +/** + * Removes a node from the {@code LinkedMap}. It can be overridden to do + * further cleanup such as disposing of the node value. + * @param {!goog.structs.LinkedMap.Node_} node The node to remove. + * @protected + */ +goog.structs.LinkedMap.prototype.removeNode = function(node) { + node.remove(); + this.map_.remove(node.key); +}; + + +/** + * @return {number} The number of items currently in the LinkedMap. + */ +goog.structs.LinkedMap.prototype.getCount = function() { + return this.map_.getCount(); +}; + + +/** + * @return {boolean} True if the cache is empty, false if it contains any items. + */ +goog.structs.LinkedMap.prototype.isEmpty = function() { + return this.map_.isEmpty(); +}; + + +/** + * Sets the maximum number of entries allowed in this object, truncating any + * excess objects if necessary. + * @param {number} maxCount The new maximum number of entries to allow. + */ +goog.structs.LinkedMap.prototype.setMaxCount = function(maxCount) { + this.maxCount_ = maxCount || null; + if (this.maxCount_ != null) { + this.truncate_(this.maxCount_); + } +}; + + +/** + * @return {Array.<string>} The list of the keys in the appropriate order for + * this LinkedMap. + */ +goog.structs.LinkedMap.prototype.getKeys = function() { + return this.map(function(val, key) { + return key; + }); +}; + + +/** + * @return {!Array} The list of the values in the appropriate order for + * this LinkedMap. + */ +goog.structs.LinkedMap.prototype.getValues = function() { + return this.map(function(val, key) { + return val; + }); +}; + + +/** + * Tests whether a provided value is currently in the LinkedMap. This does not + * affect item ordering in cache-style LinkedMaps. + * @param {Object} value The value to check for. + * @return {boolean} Whether the value is in the LinkedMap. + */ +goog.structs.LinkedMap.prototype.contains = function(value) { + return this.some(function(el) { + return el == value; + }); +}; + + +/** + * Tests whether a provided key is currently in the LinkedMap. This does not + * affect item ordering in cache-style LinkedMaps. + * @param {string} key The key to check for. + * @return {boolean} Whether the key is in the LinkedMap. + */ +goog.structs.LinkedMap.prototype.containsKey = function(key) { + return this.map_.containsKey(key); +}; + + +/** + * Removes all entries in this object. + */ +goog.structs.LinkedMap.prototype.clear = function() { + this.truncate_(0); +}; + + +/** + * Calls a function on each item in the LinkedMap. + * + * @see goog.structs.forEach + * @param {Function} f The function to call for each item. The function takes + * three arguments: the value, the key, and the LinkedMap. + * @param {Object=} opt_obj The object context to use as "this" for the + * function. + */ +goog.structs.LinkedMap.prototype.forEach = function(f, opt_obj) { + for (var n = this.head_.next; n != this.head_; n = n.next) { + f.call(opt_obj, n.value, n.key, this); + } +}; + + +/** + * Calls a function on each item in the LinkedMap and returns the results of + * those calls in an array. + * + * @see goog.structs.map + * @param {!Function} f The function to call for each item. The function takes + * three arguments: the value, the key, and the LinkedMap. + * @param {Object=} opt_obj The object context to use as "this" for the + * function. + * @return {!Array} The results of the function calls for each item in the + * LinkedMap. + */ +goog.structs.LinkedMap.prototype.map = function(f, opt_obj) { + var rv = []; + for (var n = this.head_.next; n != this.head_; n = n.next) { + rv.push(f.call(opt_obj, n.value, n.key, this)); + } + return rv; +}; + + +/** + * Calls a function on each item in the LinkedMap and returns true if any of + * those function calls returns a true-like value. + * + * @see goog.structs.some + * @param {Function} f The function to call for each item. The function takes + * three arguments: the value, the key, and the LinkedMap, and returns a + * boolean. + * @param {Object=} opt_obj The object context to use as "this" for the + * function. + * @return {boolean} Whether f evaluates to true for at least one item in the + * LinkedMap. + */ +goog.structs.LinkedMap.prototype.some = function(f, opt_obj) { + for (var n = this.head_.next; n != this.head_; n = n.next) { + if (f.call(opt_obj, n.value, n.key, this)) { + return true; + } + } + return false; +}; + + +/** + * Calls a function on each item in the LinkedMap and returns true only if every + * function call returns a true-like value. + * + * @see goog.structs.some + * @param {Function} f The function to call for each item. The function takes + * three arguments: the value, the key, and the Cache, and returns a + * boolean. + * @param {Object=} opt_obj The object context to use as "this" for the + * function. + * @return {boolean} Whether f evaluates to true for every item in the Cache. + */ +goog.structs.LinkedMap.prototype.every = function(f, opt_obj) { + for (var n = this.head_.next; n != this.head_; n = n.next) { + if (!f.call(opt_obj, n.value, n.key, this)) { + return false; + } + } + return true; +}; + + +/** + * Appends a node to the list. LinkedMap in cache mode adds new nodes to + * the head of the list, otherwise they are appended to the tail. If there is a + * maximum size, the list will be truncated if necessary. + * + * @param {goog.structs.LinkedMap.Node_} node The item to insert. + * @private + */ +goog.structs.LinkedMap.prototype.insert_ = function(node) { + if (this.cache_) { + node.next = this.head_.next; + node.prev = this.head_; + + this.head_.next = node; + node.next.prev = node; + } else { + node.prev = this.head_.prev; + node.next = this.head_; + + this.head_.prev = node; + node.prev.next = node; + } + + if (this.maxCount_ != null) { + this.truncate_(this.maxCount_); + } +}; + + +/** + * Removes elements from the LinkedMap if the given count has been exceeded. + * In cache mode removes nodes from the tail of the list. Otherwise removes + * nodes from the head. + * @param {number} count Number of elements to keep. + * @private + */ +goog.structs.LinkedMap.prototype.truncate_ = function(count) { + for (var i = this.map_.getCount(); i > count; i--) { + this.removeNode(this.cache_ ? this.head_.prev : this.head_.next); + } +}; + + +/** + * Removes the node from the LinkedMap if it is not the head, and returns + * the node's value. + * @param {!goog.structs.LinkedMap.Node_} node The item to remove. + * @return {*} The value of the popped node. + * @private + */ +goog.structs.LinkedMap.prototype.popNode_ = function(node) { + if (this.head_ != node) { + this.removeNode(node); + } + return node.value; +}; + + + +/** + * Internal class for a doubly-linked list node containing a key/value pair. + * @param {string} key The key. + * @param {*} value The value. + * @constructor + * @private + */ +goog.structs.LinkedMap.Node_ = function(key, value) { + this.key = key; + this.value = value; +}; + + +/** + * The next node in the list. + * @type {!goog.structs.LinkedMap.Node_} + */ +goog.structs.LinkedMap.Node_.prototype.next; + + +/** + * The previous node in the list. + * @type {!goog.structs.LinkedMap.Node_} + */ +goog.structs.LinkedMap.Node_.prototype.prev; + + +/** + * Causes this node to remove itself from the list. + */ +goog.structs.LinkedMap.Node_.prototype.remove = function() { + this.prev.next = this.next; + this.next.prev = this.prev; + + delete this.prev; + delete this.next; +}; diff --git a/contexts/data/lib/closure-library/closure/goog/structs/linkedmap_test.html b/contexts/data/lib/closure-library/closure/goog/structs/linkedmap_test.html new file mode 100644 index 0000000..d20faac --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/linkedmap_test.html @@ -0,0 +1,300 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright 2006 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> +<head> +<meta http-equiv="X-UA-Compatible" content="IE=edge"> +<title>Closure Unit Tests - goog.structs.LinkedMap</title> +<script src="../base.js"></script> +<script> + goog.require('goog.structs.LinkedMap'); + goog.require('goog.testing.jsunit'); + goog.require('goog.testing.recordFunction'); +</script> +</head> +<body> +<script> + +function fillLinkedMap(m) { + m.set('a', 0); + m.set('b', 1); + m.set('c', 2); + m.set('d', 3); +} + +var someObj = {}; + +function testLinkedMap() { + var m = new goog.structs.LinkedMap(); + fillLinkedMap(m); + + assertArrayEquals(['a', 'b', 'c', 'd'], m.getKeys()); + assertArrayEquals([0, 1, 2, 3], m.getValues()); +} + +function testMaxSizeLinkedMap() { + var m = new goog.structs.LinkedMap(3); + fillLinkedMap(m); + + assertArrayEquals(['b', 'c', 'd'], m.getKeys()); + assertArrayEquals([1, 2, 3], m.getValues()); +} + +function testLruLinkedMap() { + var m = new goog.structs.LinkedMap(undefined, true); + fillLinkedMap(m); + + assertArrayEquals(['d', 'c', 'b', 'a'], m.getKeys()); + assertArrayEquals([3, 2, 1, 0], m.getValues()); + + m.get('a'); + assertArrayEquals(['a', 'd', 'c', 'b'], m.getKeys()); + assertArrayEquals([0, 3, 2, 1], m.getValues()); + + m.set('b', 4); + assertArrayEquals(['b', 'a', 'd', 'c'], m.getKeys()); + assertArrayEquals([4, 0, 3, 2], m.getValues()); +} + +function testMaxSizeLruLinkedMap() { + var m = new goog.structs.LinkedMap(3, true); + fillLinkedMap(m); + + assertArrayEquals(['d', 'c', 'b'], m.getKeys()); + assertArrayEquals([3, 2, 1], m.getValues()); + + m.get('c'); + assertArrayEquals(['c', 'd', 'b'], m.getKeys()); + assertArrayEquals([2, 3, 1], m.getValues()); + + m.set('d', 4); + assertArrayEquals(['d', 'c', 'b'], m.getKeys()); + assertArrayEquals([4, 2, 1], m.getValues()); +} + +function testGetCount() { + var m = new goog.structs.LinkedMap(); + assertEquals(0, m.getCount()); + m.set('a', 0); + assertEquals(1, m.getCount()); + m.set('a', 1); + assertEquals(1, m.getCount()); + m.set('b', 2); + assertEquals(2, m.getCount()); + m.remove('a'); + assertEquals(1, m.getCount()); +} + +function testIsEmpty() { + var m = new goog.structs.LinkedMap(); + assertTrue(m.isEmpty()); + m.set('a', 0); + assertFalse(m.isEmpty()); + m.remove('a'); + assertTrue(m.isEmpty()); +} + +function testSetMaxCount() { + var m = new goog.structs.LinkedMap(3); + fillLinkedMap(m); + assertEquals(3, m.getCount()); + + m.setMaxCount(5); + m.set('e', 5); + m.set('f', 6); + m.set('g', 7); + assertEquals(5, m.getCount()); + + m.setMaxCount(4); + assertEquals(4, m.getCount()); + + m.setMaxCount(0); + m.set('h', 8); + m.set('i', 9); + m.set('j', 10); + assertEquals(7, m.getCount()); +} + +function testClear() { + var m = new goog.structs.LinkedMap(); + fillLinkedMap(m); + m.clear(); + assertTrue(m.isEmpty()); +} + +function testForEach() { + var m = new goog.structs.LinkedMap(); + fillLinkedMap(m); + + m.forEach(function(val, key, linkedMap) { + linkedMap.set(key, val * 2); + assertEquals('forEach should run in provided context.', someObj, this); + }, someObj); + + assertArrayEquals(['a', 'b', 'c', 'd'], m.getKeys()); + assertArrayEquals([0, 2, 4, 6], m.getValues()); +} + +function testMap() { + var m = new goog.structs.LinkedMap(); + fillLinkedMap(m); + + var result = m.map(function(val, key, linkedMap) { + assertEquals('The LinkedMap object should get passed in', m, linkedMap); + assertEquals('map should run in provided context', someObj, this); + return key + val; + }, someObj); + + assertArrayEquals(['a0', 'b1', 'c2', 'd3'], result); +} + +function testSome() { + var m = new goog.structs.LinkedMap(); + fillLinkedMap(m); + + var result = m.some(function(val, key, linkedMap) { + assertEquals('The LinkedMap object should get passed in', m, linkedMap); + assertEquals('map should run in provided context', someObj, this); + return val > 2; + }, someObj); + + assertTrue(result); + assertFalse(m.some(function(val) {return val > 3})); + + assertTrue(m.some(function(val, key) {return key == 'c';})); + assertFalse(m.some(function(val, key) {return key == 'e';})); +} + +function testEvery() { + var m = new goog.structs.LinkedMap(); + fillLinkedMap(m); + + var result = m.every(function(val, key, linkedMap) { + assertEquals('The LinkedMap object should get passed in', m, linkedMap); + assertEquals('map should run in provided context', someObj, this); + return val < 5; + }, someObj); + + assertTrue(result); + assertFalse(m.every(function(val) {return val < 2})); + + assertTrue(m.every(function(val, key) {return key.length == 1;})); + assertFalse(m.every(function(val, key) {return key == 'b';})); +} + +function testPeek() { + var m = new goog.structs.LinkedMap(); + assertEquals(undefined, m.peek()); + assertEquals(undefined, m.peekLast()); + + fillLinkedMap(m); + assertEquals(0, m.peek()); + + m.remove('a'); + assertEquals(1, m.peek()); + + assertEquals(3, m.peekLast()); + + assertEquals(3, m.peekValue('d')); + assertEquals(1, m.peek()); + + m.remove('d'); + assertEquals(2, m.peekLast()); +} + +function testPop() { + var m = new goog.structs.LinkedMap(); + assertEquals(undefined, m.shift()); + assertEquals(undefined, m.pop()); + + fillLinkedMap(m); + assertEquals(4, m.getCount()); + + assertEquals(0, m.shift()); + assertEquals(1, m.peek()); + + assertEquals(3, m.pop()); + assertEquals(2, m.peekLast()); + + assertEquals(2, m.getCount()); +} + +function testContains() { + var m = new goog.structs.LinkedMap(); + fillLinkedMap(m); + + assertTrue(m.contains(2)); + assertFalse(m.contains(4)); +} + +function testContainsKey() { + var m = new goog.structs.LinkedMap(); + fillLinkedMap(m); + + assertTrue(m.containsKey('b')); + assertFalse(m.containsKey('elephant')); + assertFalse(m.containsKey('undefined')); +} + +function testRemoveNodeCalls() { + var m = new goog.structs.LinkedMap(1); + m.removeNode = goog.testing.recordFunction(m.removeNode); + + m.set('1', 1); + assertEquals('removeNode not called after adding an element', 0, + m.removeNode.getCallCount()); + m.set('1', 2); + assertEquals('removeNode not called after updating an element', 0, + m.removeNode.getCallCount()); + m.set('2', 2); + assertEquals('removeNode called after adding an overflowing element', 1, + m.removeNode.getCallCount()); + + m.remove('3'); + assertEquals('removeNode not called after removing a non-existing element', 1, + m.removeNode.getCallCount()); + m.remove('2'); + assertEquals('removeNode called after removing an existing element', 2, + m.removeNode.getCallCount()); + + m.set('1', 1); + m.clear(); + assertEquals('removeNode called after clearing the map', 3, + m.removeNode.getCallCount()); + m.clear(); + assertEquals('removeNode not called after clearing an empty map', 3, + m.removeNode.getCallCount()); + + m.set('1', 1); + m.pop(); + assertEquals('removeNode called after calling pop', 4, + m.removeNode.getCallCount()); + m.pop(); + assertEquals('removeNode not called after calling pop on an empty map', 4, + m.removeNode.getCallCount()); + + m.set('1', 1); + m.shift(); + assertEquals('removeNode called after calling shift', 5, + m.removeNode.getCallCount()); + m.shift(); + assertEquals('removeNode not called after calling shift on an empty map', 5, + m.removeNode.getCallCount()); + + m.setMaxCount(2); + m.set('1', 1); + m.set('2', 2); + assertEquals('removeNode not called after increasing the maximum map size', 5, + m.removeNode.getCallCount()); + m.setMaxCount(1); + assertEquals('removeNode called after decreasing the maximum map size', 6, + m.removeNode.getCallCount()); +} + +</script> +</body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/structs/map.js b/contexts/data/lib/closure-library/closure/goog/structs/map.js new file mode 100644 index 0000000..f48d81b --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/map.js @@ -0,0 +1,448 @@ +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Datastructure: Hash Map. + * + * @author arv@google.com (Erik Arvidsson) + * @author jonp@google.com (Jon Perlow) Optimized for IE6 + * + * This file contains an implementation of a Map structure. It implements a lot + * of the methods used in goog.structs so those functions work on hashes. For + * convenience with common usage the methods accept any type for the key, though + * internally they will be cast to strings. + */ + + +goog.provide('goog.structs.Map'); + +goog.require('goog.iter.Iterator'); +goog.require('goog.iter.StopIteration'); +goog.require('goog.object'); +goog.require('goog.structs'); + + + +/** + * Class for Hash Map datastructure. + * @param {*=} opt_map Map or Object to initialize the map with. + * @param {...*} var_args If 2 or more arguments are present then they + * will be used as key-value pairs. + * @constructor + */ +goog.structs.Map = function(opt_map, var_args) { + + /** + * Underlying JS object used to implement the map. + * @type {!Object} + * @private + */ + this.map_ = {}; + + /** + * An array of keys. This is necessary for two reasons: + * 1. Iterating the keys using for (var key in this.map_) allocates an + * object for every key in IE which is really bad for IE6 GC perf. + * 2. Without a side data structure, we would need to escape all the keys + * as that would be the only way we could tell during iteration if the + * key was an internal key or a property of the object. + * + * This array can contain deleted keys so it's necessary to check the map + * as well to see if the key is still in the map (this doesn't require a + * memory allocation in IE). + * @type {!Array.<string>} + * @private + */ + this.keys_ = []; + + var argLength = arguments.length; + + if (argLength > 1) { + if (argLength % 2) { + throw Error('Uneven number of arguments'); + } + for (var i = 0; i < argLength; i += 2) { + this.set(arguments[i], arguments[i + 1]); + } + } else if (opt_map) { + this.addAll(/** @type {Object} */ (opt_map)); + } +}; + + +/** + * The number of key value pairs in the map. + * @private + * @type {number} + */ +goog.structs.Map.prototype.count_ = 0; + + +/** + * Version used to detect changes while iterating. + * @private + * @type {number} + */ +goog.structs.Map.prototype.version_ = 0; + + +/** + * @return {number} The number of key-value pairs in the map. + */ +goog.structs.Map.prototype.getCount = function() { + return this.count_; +}; + + +/** + * Returns the values of the map. + * @return {!Array} The values in the map. + */ +goog.structs.Map.prototype.getValues = function() { + this.cleanupKeysArray_(); + + var rv = []; + for (var i = 0; i < this.keys_.length; i++) { + var key = this.keys_[i]; + rv.push(this.map_[key]); + } + return rv; +}; + + +/** + * Returns the keys of the map. + * @return {!Array.<string>} Array of string values. + */ +goog.structs.Map.prototype.getKeys = function() { + this.cleanupKeysArray_(); + return /** @type {!Array.<string>} */ (this.keys_.concat()); +}; + + +/** + * Whether the map contains the given key. + * @param {*} key The key to check for. + * @return {boolean} Whether the map contains the key. + */ +goog.structs.Map.prototype.containsKey = function(key) { + return goog.structs.Map.hasKey_(this.map_, key); +}; + + +/** + * Whether the map contains the given value. This is O(n). + * @param {*} val The value to check for. + * @return {boolean} Whether the map contains the value. + */ +goog.structs.Map.prototype.containsValue = function(val) { + for (var i = 0; i < this.keys_.length; i++) { + var key = this.keys_[i]; + if (goog.structs.Map.hasKey_(this.map_, key) && this.map_[key] == val) { + return true; + } + } + return false; +}; + + +/** + * Whether this map is equal to the argument map. + * @param {goog.structs.Map} otherMap The map against which to test equality. + * @param {function(*, *) : boolean=} opt_equalityFn Optional equality function + * to test equality of values. If not specified, this will test whether + * the values contained in each map are identical objects. + * @return {boolean} Whether the maps are equal. + */ +goog.structs.Map.prototype.equals = function(otherMap, opt_equalityFn) { + if (this === otherMap) { + return true; + } + + if (this.count_ != otherMap.getCount()) { + return false; + } + + var equalityFn = opt_equalityFn || goog.structs.Map.defaultEquals; + + this.cleanupKeysArray_(); + for (var key, i = 0; key = this.keys_[i]; i++) { + if (!equalityFn(this.get(key), otherMap.get(key))) { + return false; + } + } + + return true; +}; + + +/** + * Default equality test for values. + * @param {*} a The first value. + * @param {*} b The second value. + * @return {boolean} Whether a and b reference the same object. + */ +goog.structs.Map.defaultEquals = function(a, b) { + return a === b; +}; + + +/** + * @return {boolean} Whether the map is empty. + */ +goog.structs.Map.prototype.isEmpty = function() { + return this.count_ == 0; +}; + + +/** + * Removes all key-value pairs from the map. + */ +goog.structs.Map.prototype.clear = function() { + this.map_ = {}; + this.keys_.length = 0; + this.count_ = 0; + this.version_ = 0; +}; + + +/** + * Removes a key-value pair based on the key. This is O(logN) amortized due to + * updating the keys array whenever the count becomes half the size of the keys + * in the keys array. + * @param {*} key The key to remove. + * @return {boolean} Whether object was removed. + */ +goog.structs.Map.prototype.remove = function(key) { + if (goog.structs.Map.hasKey_(this.map_, key)) { + delete this.map_[key]; + this.count_--; + this.version_++; + + // clean up the keys array if the threshhold is hit + if (this.keys_.length > 2 * this.count_) { + this.cleanupKeysArray_(); + } + + return true; + } + return false; +}; + + +/** + * Cleans up the temp keys array by removing entries that are no longer in the + * map. + * @private + */ +goog.structs.Map.prototype.cleanupKeysArray_ = function() { + if (this.count_ != this.keys_.length) { + // First remove keys that are no longer in the map. + var srcIndex = 0; + var destIndex = 0; + while (srcIndex < this.keys_.length) { + var key = this.keys_[srcIndex]; + if (goog.structs.Map.hasKey_(this.map_, key)) { + this.keys_[destIndex++] = key; + } + srcIndex++; + } + this.keys_.length = destIndex; + } + + if (this.count_ != this.keys_.length) { + // If the count still isn't correct, that means we have duplicates. This can + // happen when the same key is added and removed multiple times. Now we have + // to allocate one extra Object to remove the duplicates. This could have + // been done in the first pass, but in the common case, we can avoid + // allocating an extra object by only doing this when necessary. + var seen = {}; + var srcIndex = 0; + var destIndex = 0; + while (srcIndex < this.keys_.length) { + var key = this.keys_[srcIndex]; + if (!(goog.structs.Map.hasKey_(seen, key))) { + this.keys_[destIndex++] = key; + seen[key] = 1; + } + srcIndex++; + } + this.keys_.length = destIndex; + } +}; + + +/** + * Returns the value for the given key. If the key is not found and the default + * value is not given this will return {@code undefined}. + * @param {*} key The key to get the value for. + * @param {*=} opt_val The value to return if no item is found for the given + * key, defaults to undefined. + * @return {*} The value for the given key. + */ +goog.structs.Map.prototype.get = function(key, opt_val) { + if (goog.structs.Map.hasKey_(this.map_, key)) { + return this.map_[key]; + } + return opt_val; +}; + + +/** + * Adds a key-value pair to the map. + * @param {*} key The key. + * @param {*} value The value to add. + */ +goog.structs.Map.prototype.set = function(key, value) { + if (!(goog.structs.Map.hasKey_(this.map_, key))) { + this.count_++; + this.keys_.push(key); + // Only change the version if we add a new key. + this.version_++; + } + this.map_[key] = value; +}; + + +/** + * Adds multiple key-value pairs from another goog.structs.Map or Object. + * @param {Object} map Object containing the data to add. + */ +goog.structs.Map.prototype.addAll = function(map) { + var keys, values; + if (map instanceof goog.structs.Map) { + keys = map.getKeys(); + values = map.getValues(); + } else { + keys = goog.object.getKeys(map); + values = goog.object.getValues(map); + } + // we could use goog.array.forEach here but I don't want to introduce that + // dependency just for this. + for (var i = 0; i < keys.length; i++) { + this.set(keys[i], values[i]); + } +}; + + +/** + * Clones a map and returns a new map. + * @return {!goog.structs.Map} A new map with the same key-value pairs. + */ +goog.structs.Map.prototype.clone = function() { + return new goog.structs.Map(this); +}; + + +/** + * Returns a new map in which all the keys and values are interchanged + * (keys become values and values become keys). If multiple keys map to the + * same value, the chosen transposed value is implementation-dependent. + * + * It acts very similarly to {goog.object.transpose(Object)}. + * + * @return {!goog.structs.Map} The transposed map. + */ +goog.structs.Map.prototype.transpose = function() { + var transposed = new goog.structs.Map(); + for (var i = 0; i < this.keys_.length; i++) { + var key = this.keys_[i]; + var value = this.map_[key]; + transposed.set(value, key); + } + + return transposed; +}; + + +/** + * @return {!Object} Object representation of the map. + */ +goog.structs.Map.prototype.toObject = function() { + this.cleanupKeysArray_(); + var obj = {}; + for (var i = 0; i < this.keys_.length; i++) { + var key = this.keys_[i]; + obj[key] = this.map_[key]; + } + return obj; +}; + + +/** + * Returns an iterator that iterates over the keys in the map. Removal of keys + * while iterating might have undesired side effects. + * @return {!goog.iter.Iterator} An iterator over the keys in the map. + */ +goog.structs.Map.prototype.getKeyIterator = function() { + return this.__iterator__(true); +}; + + +/** + * Returns an iterator that iterates over the values in the map. Removal of + * keys while iterating might have undesired side effects. + * @return {!goog.iter.Iterator} An iterator over the values in the map. + */ +goog.structs.Map.prototype.getValueIterator = function() { + return this.__iterator__(false); +}; + + +/** + * Returns an iterator that iterates over the values or the keys in the map. + * This throws an exception if the map was mutated since the iterator was + * created. + * @param {boolean=} opt_keys True to iterate over the keys. False to iterate + * over the values. The default value is false. + * @return {!goog.iter.Iterator} An iterator over the values or keys in the map. + */ +goog.structs.Map.prototype.__iterator__ = function(opt_keys) { + // Clean up keys to minimize the risk of iterating over dead keys. + this.cleanupKeysArray_(); + + var i = 0; + var keys = this.keys_; + var map = this.map_; + var version = this.version_; + var selfObj = this; + + var newIter = new goog.iter.Iterator; + newIter.next = function() { + while (true) { + if (version != selfObj.version_) { + throw Error('The map has changed since the iterator was created'); + } + if (i >= keys.length) { + throw goog.iter.StopIteration; + } + var key = keys[i++]; + return opt_keys ? key : map[key]; + } + }; + return newIter; +}; + + +/** + * Safe way to test for hasOwnProperty. It even allows testing for + * 'hasOwnProperty'. + * @param {Object} obj The object to test for presence of the given key. + * @param {*} key The key to check for. + * @return {boolean} Whether the object has the key. + * @private + */ +goog.structs.Map.hasKey_ = function(obj, key) { + return Object.prototype.hasOwnProperty.call(obj, key); +}; diff --git a/contexts/data/lib/closure-library/closure/goog/structs/map_test.html b/contexts/data/lib/closure-library/closure/goog/structs/map_test.html new file mode 100644 index 0000000..a526a59 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/map_test.html @@ -0,0 +1,430 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright 2006 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> +<head> +<meta http-equiv="X-UA-Compatible" content="IE=edge"> +<title>Closure Unit Tests - goog.structs.Map</title> +<script src="../base.js"></script> +<script> + goog.require('goog.iter'); + goog.require('goog.structs'); + goog.require('goog.structs.Map'); + goog.require('goog.testing.jsunit'); +</script> +</head> +<body> +<script> + +function stringifyMap(m) { + var keys = goog.structs.getKeys(m); + var s = ''; + for (var i = 0; i < keys.length; i++) { + s += keys[i] + m[keys[i]]; + } + return s; +} + +function getMap() { + var m = new goog.structs.Map; + m.set('a', 0); + m.set('b', 1); + m.set('c', 2); + m.set('d', 3); + return m; +} + +function testGetCount() { + var m = getMap(); + assertEquals('count, should be 4', m.getCount(), 4); + m.remove('d'); + assertEquals('count, should be 3', m.getCount(), 3); +} + +function testKeys() { + var m = getMap(); + assertEquals('getKeys, The keys should be a,b,c', m.getKeys().join(','), + 'a,b,c,d'); +} + +function testValues() { + var m = getMap(); + assertEquals('getValues, The values should be 0,1,2', + m.getValues().join(','), '0,1,2,3'); +} + +function testContainsKey() { + var m = getMap(); + assertTrue("containsKey, Should contain the 'a' key", m.containsKey('a')); + assertFalse("containsKey, Should not contain the 'e' key", + m.containsKey('e')); +} + +function testClear() { + var m = getMap(); + m.clear(); + assertTrue('cleared so it should be empty', m.isEmpty()); + assertTrue("cleared so it should not contain 'a' key", !m.containsKey('a')); +} + +function testAddAll() { + var m = new goog.structs.Map; + m.addAll({a:0,b:1,c:2,d:3}); + assertTrue('addAll so it should not be empty', !m.isEmpty()); + assertTrue("addAll so it should contain 'c' key", m.containsKey('c')); + + var m2 = new goog.structs.Map; + m2.addAll(m); + assertTrue('addAll so it should not be empty', !m2.isEmpty()); + assertTrue("addAll so it should contain 'c' key", m2.containsKey('c')); +} + +function testConstructor() { + var m = getMap(); + var m2 = new goog.structs.Map(m); + assertTrue('constr with Map so it should not be empty', !m2.isEmpty()); + assertTrue("constr with Map so it should contain 'c' key", + m2.containsKey('c')); +} + + +function testConstructorWithVarArgs() { + var m = new goog.structs.Map('a', 1); + assertTrue('constr with var_args so it should not be empty', !m.isEmpty()); + assertEquals('constr with var_args', 1, m.get('a')); + + m = new goog.structs.Map('a', 1, 'b', 2); + assertTrue('constr with var_args so it should not be empty', !m.isEmpty()); + assertEquals('constr with var_args', 1, m.get('a')); + assertEquals('constr with var_args', 2, m.get('b')); + + assertThrows('Odd number of arguments is not allowed', function() { + var m = new goog.structs.Map('a', 1, 'b'); + }); +} + +function testClone() { + var m = getMap(); + var m2 = m.clone(); + assertTrue('clone so it should not be empty', !m2.isEmpty()); + assertTrue("clone so it should contain 'c' key", m2.containsKey('c')); +} + + +function testRemove() { + var m = new goog.structs.Map(); + for (var i = 0; i < 1000; i++) { + m.set(i, 'foo'); + } + + for (var i = 0; i < 1000; i++) { + assertTrue(m.keys_.length <= 2 * m.getCount()); + m.remove(i); + } + assertTrue(m.isEmpty()); + assertEquals('', m.getKeys().join('')); +} + + +function testForEach() { + var m = getMap(); + var s = ''; + goog.structs.forEach(m, function(val, key, m2) { + assertNotUndefined(key); + assertEquals(m, m2); + s += key + val; + }); + assertEquals(s, 'a0b1c2d3'); +} + +function testFilter() { + var m = getMap(); + + var m2 = goog.structs.filter(m, function (val, key, m3) { + assertNotUndefined(key); + assertEquals(m, m3); + return val > 1; + }); + assertEquals(stringifyMap(m2), 'c2d3'); +} + + +function testMap() { + var m = getMap(); + var m2 = goog.structs.map(m, function (val, key, m3) { + assertNotUndefined(key); + assertEquals(m, m3); + return val * val; + }); + assertEquals(stringifyMap(m2), 'a0b1c4d9'); +} + +function testSome() { + var m = getMap(); + var b = goog.structs.some(m, function (val, key, m2) { + assertNotUndefined(key); + assertEquals(m, m2); + return val > 1; + }); + assertTrue(b); + var b = goog.structs.some(m, function (val, key, m2) { + assertNotUndefined(key); + assertEquals(m, m2); + return val > 100; + }); + assertFalse(b); +} + +function testEvery() { + var m = getMap(); + var b = goog.structs.every(m, function (val, key, m2) { + assertNotUndefined(key); + assertEquals(m, m2); + return val >= 0; + }); + assertTrue(b); + b = goog.structs.every(m, function (val, key, m2) { + assertNotUndefined(key); + assertEquals(m, m2); + return val > 1; + }); + assertFalse(b); +} + +function testContainsValue() { + var m = getMap(); + assertTrue(m.containsValue(3)); + assertFalse(m.containsValue(4)); +} + +function testObjectProperties() { + var m = new goog.structs.Map; + + assertEquals(m.get('toString'), undefined); + assertEquals(m.get('valueOf'), undefined); + assertEquals(m.get('eval'), undefined); + assertEquals(m.get('toSource'), undefined); + assertEquals(m.get('prototype'), undefined); + assertEquals(m.get(':foo'), undefined); + + m.set('toString', 'once'); + m.set('valueOf', 'upon'); + m.set('eval', 'a'); + m.set('toSource', 'midnight'); + m.set('prototype', 'dreary'); + m.set('hasOwnProperty', 'dark'); + m.set(':foo', 'happy'); + + assertEquals(m.get('toString'), 'once'); + assertEquals(m.get('valueOf'), 'upon'); + assertEquals(m.get('eval'), 'a'); + assertEquals(m.get('toSource'), 'midnight'); + assertEquals(m.get('prototype'), 'dreary'); + assertEquals(m.get('hasOwnProperty'), 'dark'); + assertEquals(m.get(':foo'), 'happy'); + + var keys = m.getKeys().join(','); + assertEquals(keys, + 'toString,valueOf,eval,toSource,prototype,hasOwnProperty,:foo'); + + var values = m.getValues().join(','); + assertEquals(values, 'once,upon,a,midnight,dreary,dark,happy'); +} + +function testDuplicateKeys() { + var m = new goog.structs.Map; + + m.set('a', 1); + m.set('b', 2); + m.set('c', 3); + m.set('d', 4); + m.set('e', 5); + m.set('f', 6); + assertEquals(6, m.getKeys().length); + m.set('foo', 1); + assertEquals(7, m.getKeys().length); + m.remove('foo'); + assertEquals(6, m.getKeys().length); + m.set('foo', 2); + assertEquals(7, m.getKeys().length); + m.remove('foo'); + m.set('foo', 3); + m.remove('foo'); + m.set('foo', 4); + assertEquals(7, m.getKeys().length); +} + +function testGetKeyIterator() { + var m = new goog.structs.Map; + m.set('a', 1); + m.set('b', 2); + m.set('c', 3); + m.set('d', 4); + m.set('e', 5); + + var iter = m.getKeyIterator(); + assertEquals('Should contain the keys', 'abcde', goog.iter.join(iter, '')); + + m.remove('b'); + m.remove('d'); + iter = m.getKeyIterator(); + assertEquals('Should not contain the removed keys', + 'ace', goog.iter.join(iter, '')); +} + +function testGetValueIterator() { + var m = new goog.structs.Map; + m.set('a', 1); + m.set('b', 2); + m.set('c', 3); + m.set('d', 4); + m.set('e', 5); + + var iter = m.getValueIterator(); + assertEquals('Should contain the values', '12345', goog.iter.join(iter, '')); + + m.remove('b'); + m.remove('d'); + iter = m.getValueIterator(); + assertEquals('Should not contain the removed keys', + '135', goog.iter.join(iter, '')); +} + +function testDefaultIterator() { + // The default iterator should behave like the value iterator + + var m = new goog.structs.Map; + m.set('a', 1); + m.set('b', 2); + m.set('c', 3); + m.set('d', 4); + m.set('e', 5); + + assertEquals('Should contain the values', '12345', goog.iter.join(m, '')); + + m.remove('b'); + m.remove('d'); + assertEquals('Should not contain the removed keys', + '135', goog.iter.join(m, '')); +} + +function testMutatedIterator() { + var message = 'The map has changed since the iterator was created'; + + var m = new goog.structs.Map; + m.set('a', 1); + m.set('b', 2); + m.set('c', 3); + m.set('d', 4); + + var iter = m.getValueIterator(); + m.set('e', 5); + var ex = assertThrows('Expected an exception since the map has changed', + function() { + iter.next(); + }); + assertEquals(message, ex.message); + + m = new goog.structs.Map; + m.set('a', 1); + m.set('b', 2); + m.set('c', 3); + m.set('d', 4); + + iter = m.getValueIterator(); + m.remove('d'); + var ex = assertThrows('Expected an exception since the map has changed', + function() { + iter.next(); + }); + assertEquals(message, ex.message); + + m = new goog.structs.Map; + m.set('a', 1); + m.set('b', 2); + m.set('c', 3); + m.set('d', 4); + + iter = m.getValueIterator(); + m.set('d', 5); + iter.next(); + // Changing an existing value is OK. + iter.next(); +}; + +function testTranspose() { + var m = new goog.structs.Map; + m.set('a', 1); + m.set('b', 2); + m.set('c', 3); + m.set('d', 4); + m.set('e', 5); + + var transposed = m.transpose(); + assertEquals('Should contain the keys', 'abcde', + goog.iter.join(transposed, '')); +} + +function testToObject() { + Object.prototype.b = 0; + try { + var map = new goog.structs.Map(); + map.set('a', 0); + var obj = map.toObject(); + assertTrue('object representation has key "a"', obj.hasOwnProperty('a')); + assertFalse('object representation does not have key "b"', + obj.hasOwnProperty('b')); + assertEquals('value for key "a"', 0, obj['a']); + } finally { + delete Object.prototype.b; + } +} + +function testEqualsWithSameObject() { + var map1 = getMap(); + assertTrue('maps are the same object', map1.equals(map1)); +} + +function testEqualsWithDifferentSizeMaps() { + var map1 = getMap(); + var map2 = new goog.structs.Map(); + + assertFalse('maps are different sizes', map1.equals(map2)); +} + +function testEqualsWithDefaultEqualityFn() { + var map1 = new goog.structs.Map(); + var map2 = new goog.structs.Map(); + + assertTrue('maps are both empty', map1.equals(map2)); + + map1 = getMap(); + map2 = getMap(); + assertTrue('maps are the same', map1.equals(map2)); + + map2.set('d', '3'); + assertFalse('maps have 3 and \'3\'', map1.equals(map2)); +} + +function testEqualsWithCustomEqualityFn() { + var map1 = new goog.structs.Map(); + var map2 = new goog.structs.Map(); + + map1.set('a', 0); + map1.set('b', 1); + + map2.set('a', '0'); + map2.set('b', '1'); + + var equalsFn = function(a, b) { return a == b }; + + assertTrue('maps are equal with ==', map1.equals(map2, equalsFn)); +} + +</script> +</body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/structs/node.js b/contexts/data/lib/closure-library/closure/goog/structs/node.js new file mode 100644 index 0000000..bc6a9fb --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/node.js @@ -0,0 +1,74 @@ +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Generic immutable node object to be used in collections. + * + */ + + +goog.provide('goog.structs.Node'); + + + +/** + * A generic immutable node. This can be used in various collections that + * require a node object for its item (such as a heap). + * @param {*} key Key. + * @param {*} value Vaue. + * @constructor + */ +goog.structs.Node = function(key, value) { + /** + * The key. + * @type {*} + * @private + */ + this.key_ = key; + + /** + * The value. + * @type {*} + * @private + */ + this.value_ = value; +}; + + +/** + * Gets the key. + * @return {*} The key. + */ +goog.structs.Node.prototype.getKey = function() { + return this.key_; +}; + + +/** + * Gets the value. + * @return {*} The value. + */ +goog.structs.Node.prototype.getValue = function() { + return this.value_; +}; + + +/** + * Clones a node and returns a new node. + * @return {goog.structs.Node} A new goog.structs.Node with the same key value + * pair. + */ +goog.structs.Node.prototype.clone = function() { + return new goog.structs.Node(this.key_, this.value_); +}; diff --git a/contexts/data/lib/closure-library/closure/goog/structs/pool.js b/contexts/data/lib/closure-library/closure/goog/structs/pool.js new file mode 100644 index 0000000..ba69dd0 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/pool.js @@ -0,0 +1,381 @@ +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Datastructure: Pool. + * + * + * A generic class for handling pools of objects. + * When an object is released, it is attempted to be reused. + */ + + +goog.provide('goog.structs.Pool'); + +goog.require('goog.Disposable'); +goog.require('goog.structs.Queue'); +goog.require('goog.structs.Set'); + + + +/** + * A generic pool class. If min is greater than max, an error is thrown. + * @param {number=} opt_minCount Min. number of objects (Default: 1). + * @param {number=} opt_maxCount Max. number of objects (Default: 10). + * @constructor + * @extends {goog.Disposable} + */ +goog.structs.Pool = function(opt_minCount, opt_maxCount) { + goog.Disposable.call(this); + + /** + * Minimum number of objects allowed + * @type {number} + * @private + */ + this.minCount_ = opt_minCount || 0; + + /** + * Maximum number of objects allowed + * @type {number} + * @private + */ + this.maxCount_ = opt_maxCount || 10; + + // Make sure that the max and min constraints are valid. + if (this.minCount_ > this.maxCount_) { + throw Error(goog.structs.Pool.ERROR_MIN_MAX_); + } + + /** + * Set used to store objects that are currently in the pool and available + * to be used. + * @type {goog.structs.Queue} + * @private + */ + this.freeQueue_ = new goog.structs.Queue(); + + /** + * Set used to store objects that are currently in the pool and in use. + * @type {goog.structs.Set} + * @private + */ + this.inUseSet_ = new goog.structs.Set(); + + /** + * The minimum delay between objects being made available, in milliseconds. If + * this is 0, no minimum delay is enforced. + * @type {number} + * @protected + */ + this.delay = 0; + + /** + * The time of the last object being made available, in milliseconds since the + * epoch (i.e., the result of Date#toTime). If this is null, no access has + * occurred yet. + * @type {number?} + * @protected + */ + this.lastAccess = null; + + // Make sure that the minCount constraint is satisfied. + this.adjustForMinMax(); + + + // TODO(user): Remove once JSCompiler's undefined properties warnings + // don't error for guarded properties. + var magicProps = {canBeReused: 0}; +}; +goog.inherits(goog.structs.Pool, goog.Disposable); + + +/** + * Error to throw when the max/min constraint is attempted to be invalidated. + * I.e., when it is attempted for maxCount to be less than minCount. + * @type {string} + * @private + */ +goog.structs.Pool.ERROR_MIN_MAX_ = + '[goog.structs.Pool] Min can not be greater than max'; + + +/** + * Error to throw when the Pool is attempted to be disposed and it is asked to + * make sure that there are no objects that are in use (i.e., haven't been + * released). + * @type {string} + * @private + */ +goog.structs.Pool.ERROR_DISPOSE_UNRELEASED_OBJS_ = + '[goog.structs.Pool] Objects not released'; + + +/** + * Sets the minimum count of the pool. + * If min is greater than the max count of the pool, an error is thrown. + * @param {number} min The minimum count of the pool. + */ +goog.structs.Pool.prototype.setMinimumCount = function(min) { + // Check count constraints. + if (min > this.maxCount_) { + throw Error(goog.structs.Pool.ERROR_MIN_MAX_); + } + this.minCount_ = min; + + // Adjust the objects in the pool as needed. + this.adjustForMinMax(); +}; + + +/** + * Sets the maximum count of the pool. + * If max is less than the max count of the pool, an error is thrown. + * @param {number} max The maximium count of the pool. + */ +goog.structs.Pool.prototype.setMaximumCount = function(max) { + // Check count constraints. + if (max < this.minCount_) { + throw Error(goog.structs.Pool.ERROR_MIN_MAX_); + } + this.maxCount_ = max; + + // Adjust the objects in the pool as needed. + this.adjustForMinMax(); +}; + + +/** + * Sets the minimum delay between objects being returned by getObject, in + * milliseconds. This defaults to zero, meaning that no minimum delay is + * enforced and objects may be used as soon as they're available. + * @param {number} delay The minimum delay, in milliseconds. + */ +goog.structs.Pool.prototype.setDelay = function(delay) { + this.delay = delay; +}; + + +/** + * @return {Object|undefined} A new object from the pool if there is one + * available, otherwise undefined. + */ +goog.structs.Pool.prototype.getObject = function() { + var time = goog.now(); + if (goog.isDefAndNotNull(this.lastAccess) && + time - this.lastAccess < this.delay) { + return undefined; + } + + var obj = this.removeFreeObject_(); + if (obj) { + this.lastAccess = time; + this.inUseSet_.add(obj); + } + + return obj; +}; + + +/** + * Returns an object to the pool of available objects so that it can be reused. + * @param {Object} obj The object to return to the pool of free objects. + * @return {boolean} Whether the object was found in the Pool's set of in-use + * objects (in other words, whether any action was taken). + */ +goog.structs.Pool.prototype.releaseObject = function(obj) { + if (this.inUseSet_.remove(obj)) { + this.addFreeObject(obj); + return true; + } + return false; +}; + + +/** + * Removes a free object from the collection of objects that are free so that it + * can be used. + * + * NOTE: This method does not mark the returned object as in use. + * + * @return {Object|undefined} The object removed from the free collection, if + * there is one available. Otherwise, undefined. + * @private + */ +goog.structs.Pool.prototype.removeFreeObject_ = function() { + var obj; + while (this.getFreeCount() > 0) { + obj = /** @type {Object} */(this.freeQueue_.dequeue()); + + if (!this.objectCanBeReused(obj)) { + this.adjustForMinMax(); + } else { + break; + } + } + + if (!obj && this.getCount() < this.maxCount_) { + obj = this.createObject(); + } + + return obj; +}; + + +/** + * Adds an object to the collection of objects that are free. If the object can + * not be added, then it is disposed. + * + * @param {Object} obj The object to add to collection of free objects. + */ +goog.structs.Pool.prototype.addFreeObject = function(obj) { + this.inUseSet_.remove(obj); + if (this.objectCanBeReused(obj) && this.getCount() < this.maxCount_) { + this.freeQueue_.enqueue(obj); + } else { + this.disposeObject(obj); + } +}; + + +/** + * Adjusts the objects held in the pool to be within the min/max constraints. + * + * NOTE: It is possible that the number of objects in the pool will still be + * greater than the maximum count of objects allowed. This will be the case + * if no more free objects can be disposed of to get below the minimum count + * (i.e., all objects are in use). + */ +goog.structs.Pool.prototype.adjustForMinMax = function() { + var freeQueue = this.freeQueue_; + + // Make sure the at least the minimum number of objects are created. + while (this.getCount() < this.minCount_) { + freeQueue.enqueue(this.createObject()); + } + + // Make sure no more than the maximum number of objects are created. + while (this.getCount() > this.maxCount_ && this.getFreeCount() > 0) { + this.disposeObject(/** @type {Object} */(freeQueue.dequeue())); + } +}; + + +/** + * Should be overriden by sub-classes to return an instance of the object type + * that is expected in the pool. + * @return {Object} The created object. + */ +goog.structs.Pool.prototype.createObject = function() { + return {}; +}; + + +/** + * Should be overriden to dispose of an object. Default implementation is to + * remove all its members, which should render it useless. Calls the object's + * {@code dispose()} method, if available. + * @param {Object} obj The object to dispose. + */ +goog.structs.Pool.prototype.disposeObject = function(obj) { + if (typeof obj.dispose == 'function') { + obj.dispose(); + } else { + for (var i in obj) { + obj[i] = null; + } + } +}; + + +/** + * Should be overriden to determine whether an object has become unusable and + * should not be returned by getObject(). Calls the object's + * {@code canBeReused()} method, if available. + * @param {Object} obj The object to test. + * @return {boolean} Whether the object can be reused. + */ +goog.structs.Pool.prototype.objectCanBeReused = function(obj) { + if (typeof obj.canBeReused == 'function') { + return obj.canBeReused(); + } + return true; +}; + + +/** + * Returns true if the given object is in the pool. + * @param {Object} obj The object to check the pool for. + * @return {boolean} Whether the pool contains the object. + */ +goog.structs.Pool.prototype.contains = function(obj) { + return this.freeQueue_.contains(obj) || this.inUseSet_.contains(obj); +}; + + +/** + * Returns the number of objects currently in the pool. + * @return {number} Number of objects currently in the pool. + */ +goog.structs.Pool.prototype.getCount = function() { + return this.freeQueue_.getCount() + this.inUseSet_.getCount(); +}; + + +/** + * Returns the number of objects currently in use in the pool. + * @return {number} Number of objects currently in use in the pool. + */ +goog.structs.Pool.prototype.getInUseCount = function() { + return this.inUseSet_.getCount(); +}; + + +/** + * Returns the number of objects currently free in the pool. + * @return {number} Number of objects currently free in the pool. + */ +goog.structs.Pool.prototype.getFreeCount = function() { + return this.freeQueue_.getCount(); +}; + + +/** + * Determines if the pool contains no objects. + * @return {boolean} Whether the pool contains no objects. + */ +goog.structs.Pool.prototype.isEmpty = function() { + return this.freeQueue_.isEmpty() && this.inUseSet_.isEmpty(); +}; + + +/** + * Disposes of the pool and all objects currently held in the pool. + * @override + * @protected + */ +goog.structs.Pool.prototype.disposeInternal = function() { + goog.structs.Pool.superClass_.disposeInternal.call(this); + if (this.getInUseCount() > 0) { + throw Error(goog.structs.Pool.ERROR_DISPOSE_UNRELEASED_OBJS_); + } + delete this.inUseSet_; + + // Call disposeObject on each object held by the pool. + var freeQueue = this.freeQueue_; + while (!freeQueue.isEmpty()) { + this.disposeObject(/** @type {Object} */ (freeQueue.dequeue())); + } + delete this.freeQueue_; +}; diff --git a/contexts/data/lib/closure-library/closure/goog/structs/pool_test.html b/contexts/data/lib/closure-library/closure/goog/structs/pool_test.html new file mode 100644 index 0000000..461e70f --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/pool_test.html @@ -0,0 +1,291 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright 2006 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> +<head> +<meta http-equiv="X-UA-Compatible" content="IE=edge"> +<title>Closure Unit Tests - goog.structs.Pool</title> +<script src="../base.js"></script> +<script> + goog.require('goog.structs'); + goog.require('goog.structs.Pool'); + goog.require('goog.testing.MockClock'); + goog.require('goog.testing.jsunit'); +</script> +</head> +<body> +<script> + +// Implementation of the Pool class with isObjectDead() always returning TRUE, +// so that the the Pool will not reuse any objects. +function NoObjectReusePool(opt_min, opt_max) { + goog.structs.Pool.call(this, opt_min, opt_max); +}; +goog.inherits(NoObjectReusePool, goog.structs.Pool); + +NoObjectReusePool.prototype.objectCanBeReused = function(obj) { + return false; +}; + + +function testExceedMax1() { + var p = new goog.structs.Pool(0, 3); + var obj1 = p.getObject(); + var obj2 = p.getObject(); + var obj3 = p.getObject(); + var obj4 = p.getObject(); + var obj5 = p.getObject(); + + assertNotUndefined(obj1); + assertNotUndefined(obj2); + assertNotUndefined(obj3); + assertUndefined(obj4); + assertUndefined(obj5); +} + + +function testExceedMax2() { + var p = new goog.structs.Pool(0, 1); + var obj1 = p.getObject(); + var obj2 = p.getObject(); + var obj3 = p.getObject(); + var obj4 = p.getObject(); + var obj5 = p.getObject(); + + assertNotUndefined(obj1); + assertUndefined(obj2); + assertUndefined(obj3); + assertUndefined(obj4); + assertUndefined(obj5); +} + + +function testExceedMax3() { + var p = new goog.structs.Pool(); // default: 10 + var objs = []; + + for (var i = 0; i < 12; i++) { + objs[i] = p.getObject(); + } + + for (var i = 0; i < 10; i++) { + assertNotNull('First 10 should be not null', objs[i]); + } + + assertUndefined(objs[10]); + assertUndefined(objs[11]); +} + + +function testReleaseAndGet1() { + var p = new goog.structs.Pool(0, 10); + var o = p.getObject(); + assertEquals(1, p.getCount()); + assertEquals(1, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + assertTrue('Result should be true', p.releaseObject(o)); + assertEquals(1, p.getCount()); + assertEquals(0, p.getInUseCount()); + assertEquals(1, p.getFreeCount()); +} + + +function testReleaseAndGet2() { + var p = new NoObjectReusePool(0, 10); + var o = p.getObject(); + assertEquals(1, p.getCount()); + assertEquals(1, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + assertTrue('Result should be true', p.releaseObject(o)); + assertEquals(0, p.getCount()); + assertEquals(0, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); +} + + +function testReleaseAndGet3() { + var p = new goog.structs.Pool(0, 10); + var o1 = p.getObject(); + var o2 = p.getObject(); + var o3 = p.getObject(); + var o4 = {}; + assertEquals(3, p.getCount()); + assertEquals(3, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + assertTrue('Result should be true', p.releaseObject(o1)); + assertTrue('Result should be true', p.releaseObject(o2)); + assertFalse('Result should be false', p.releaseObject(o4)); + assertEquals(3, p.getCount()); + assertEquals(1, p.getInUseCount()); + assertEquals(2, p.getFreeCount()); +} + + +function testReleaseAndGet4() { + var p = new NoObjectReusePool(0, 10); + var o1 = p.getObject(); + var o2 = p.getObject(); + var o3 = p.getObject(); + var o4 = {}; + assertEquals(3, p.getCount()); + assertEquals(3, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + assertTrue('Result should be true', p.releaseObject(o1)); + assertTrue('Result should be true', p.releaseObject(o2)); + assertFalse('Result should be false', p.releaseObject(o4)); + assertEquals(1, p.getCount()); + assertEquals(1, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); +} + + +function testIsInPool1() { + var p = new goog.structs.Pool(); + var o1 = p.getObject(); + var o2 = p.getObject(); + var o3 = p.getObject(); + var o4 = {}; + var o5 = {}; + var o6 = o1; + + assertTrue(p.contains(o1)); + assertTrue(p.contains(o2)); + assertTrue(p.contains(o3)); + assertFalse(p.contains(o4)); + assertFalse(p.contains(o5)); + assertTrue(p.contains(o6)); +} + + +function testSetMin1() { + var p = new goog.structs.Pool(0, 10); + + assertEquals(0, p.getCount()); + assertEquals(0, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + + p.setMinimumCount(10); + + assertEquals(10, p.getCount()); + assertEquals(0, p.getInUseCount()); + assertEquals(10, p.getFreeCount()); +} + + +function testSetMin2() { + var p = new goog.structs.Pool(0, 10); + + assertEquals(0, p.getCount()); + assertEquals(0, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + + var o1 = p.getObject(); + + assertEquals(1, p.getCount()); + assertEquals(1, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + + p.setMinimumCount(10); + + assertEquals(10, p.getCount()); + assertEquals(1, p.getInUseCount()); + assertEquals(9, p.getFreeCount()); +} + + +function testSetMax1() { + var p = new goog.structs.Pool(0, 10); + + assertEquals(0, p.getCount()); + assertEquals(0, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + + var o1 = p.getObject(); + var o2 = p.getObject(); + var o3 = p.getObject(); + var o4 = p.getObject(); + var o5 = p.getObject(); + + assertEquals(5, p.getCount()); + assertEquals(5, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + + assertTrue('Result should be true', p.releaseObject(o5)); + + assertEquals(5, p.getCount()); + assertEquals(4, p.getInUseCount()); + assertEquals(1, p.getFreeCount()); + + p.setMaximumCount(4); + + assertEquals(4, p.getCount()); + assertEquals(4, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); +} + + +function testInvalidMinMax1() { + var p = new goog.structs.Pool(0, 10); + + assertEquals(0, p.getCount()); + assertEquals(0, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + + assertThrows(function() { + p.setMinimumCount(11); + }); +} + + +function testInvalidMinMax2() { + var p = new goog.structs.Pool(5, 10); + + assertEquals(5, p.getCount()); + assertEquals(0, p.getInUseCount()); + assertEquals(5, p.getFreeCount()); + + assertThrows(function() { + p.setMaximumCount(4); + }); +} + + +function testInvalidMinMax3() { + assertThrows(function() { + new goog.structs.Pool(10, 1); + }); +} + + +function testRateLimiting() { + var clock = new goog.testing.MockClock(); + clock.install(); + + var p = new goog.structs.Pool(0, 3); + p.setDelay(100); + + assertNotUndefined(p.getObject()); + assertUndefined(p.getObject()); + + clock.tick(100); + assertNotUndefined(p.getObject()); + assertUndefined(p.getObject()); + + clock.tick(100); + assertNotUndefined(p.getObject()); + assertUndefined(p.getObject()); + + clock.tick(100); + assertUndefined(p.getObject()); + + goog.dispose(clock); +} + + +</script> +</body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/structs/prioritypool.js b/contexts/data/lib/closure-library/closure/goog/structs/prioritypool.js new file mode 100644 index 0000000..ce2af7f --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/prioritypool.js @@ -0,0 +1,179 @@ +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Datastructure: Priority Pool. + * + * + * An extending of Pool that handles queueing and prioritization. + */ + + +goog.provide('goog.structs.PriorityPool'); + +goog.require('goog.structs.Pool'); +goog.require('goog.structs.PriorityQueue'); + + + +/** + * A generic pool class. If max is greater than min, an error is thrown. + * @param {number=} opt_minCount Min. number of objects (Default: 1). + * @param {number=} opt_maxCount Max. number of objects (Default: 10). + * @constructor + * @extends {goog.structs.Pool} + */ +goog.structs.PriorityPool = function(opt_minCount, opt_maxCount) { + /** + * Queue of requests for pool objects. + * @type {goog.structs.PriorityQueue} + * @private + */ + this.requestQueue_ = new goog.structs.PriorityQueue(); + + // Must break convention of putting the super-class's constructor first. This + // is because the super-class constructor calls adjustForMinMax, which this + // class overrides. In this class's implementation, it assumes that there + // is a requestQueue_, and will error if not present. + goog.structs.Pool.call(this, opt_minCount, opt_maxCount); +}; +goog.inherits(goog.structs.PriorityPool, goog.structs.Pool); + + +/** + * The key for the most recent timeout created. + * @type {number|undefined} + * @private + */ +goog.structs.PriorityPool.prototype.delayTimeout_; + + +/** + * Default priority for pool objects requests. + * @type {number} + * @private + */ +goog.structs.PriorityPool.DEFAULT_PRIORITY_ = 100; + + +/** @override */ +goog.structs.PriorityPool.prototype.setDelay = function(delay) { + goog.base(this, 'setDelay', delay); + + // If the pool hasn't been accessed yet, no need to do anything. + if (!goog.isDefAndNotNull(this.lastAccess)) { + return; + } + + goog.global.clearTimeout(this.delayTimeout_); + this.delayTimeout_ = goog.global.setTimeout( + goog.bind(this.handleQueueRequests_, this), + this.delay + this.lastAccess - goog.now()); + + // Handle all requests. + this.handleQueueRequests_(); +}; + + +/** + * Get a new object from the the pool, if there is one available, otherwise + * return undefined. + * @param {Function=} opt_callback The function to callback when an object is + * available. This could be immediately. If this is not present, then an + * object is immediately returned if available, or undefined if not. + * @param {*=} opt_priority The priority of the request. + * @return {Object|undefined} The new object from the pool if there is one + * available and a callback is not given. Otherwise, undefined. + */ +goog.structs.PriorityPool.prototype.getObject = function(opt_callback, + opt_priority) { + if (!opt_callback) { + var result = goog.base(this, 'getObject'); + if (result && this.delay) { + this.delayTimeout_ = goog.global.setTimeout( + goog.bind(this.handleQueueRequests_, this), + this.delay); + } + return result; + } + + var priority = opt_priority || goog.structs.PriorityPool.DEFAULT_PRIORITY_; + this.requestQueue_.enqueue(priority, opt_callback); + + // Handle all requests. + this.handleQueueRequests_(); + + return undefined; +}; + + +/** + * Handles the request queue. Tries to fires off as many queued requests as + * possible. + * @private + */ +goog.structs.PriorityPool.prototype.handleQueueRequests_ = function() { + var requestQueue = this.requestQueue_; + while (requestQueue.getCount() > 0) { + var obj = this.getObject(); + + if (!obj) { + return; + } else { + var requestCallback = requestQueue.dequeue(); + requestCallback.apply(this, [obj]); + } + } +}; + + +/** + * Adds an object to the collection of objects that are free. If the object can + * not be added, then it is disposed. + * + * NOTE: This method does not remove the object from the in use collection. + * + * @param {Object} obj The object to add to the collection of free objects. + */ +goog.structs.PriorityPool.prototype.addFreeObject = function(obj) { + goog.structs.PriorityPool.superClass_.addFreeObject.call(this, obj); + + // Handle all requests. + this.handleQueueRequests_(); +}; + + +/** + * Adjusts the objects held in the pool to be within the min/max constraints. + * + * NOTE: It is possible that the number of objects in the pool will still be + * greater than the maximum count of objects allowed. This will be the case + * if no more free objects can be disposed of to get below the minimum count + * (i.e., all objects are in use). + */ +goog.structs.PriorityPool.prototype.adjustForMinMax = function() { + goog.structs.PriorityPool.superClass_.adjustForMinMax.call(this); + + // Handle all requests. + this.handleQueueRequests_(); +}; + + +/** @override */ +goog.structs.PriorityPool.prototype.disposeInternal = function() { + goog.structs.PriorityPool.superClass_.disposeInternal.call(this); + goog.global.clearTimeout(this.delayTimeout_); + this.requestQueue_.clear(); + this.requestQueue_ = null; +}; diff --git a/contexts/data/lib/closure-library/closure/goog/structs/prioritypool_test.html b/contexts/data/lib/closure-library/closure/goog/structs/prioritypool_test.html new file mode 100644 index 0000000..7a0b367 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/prioritypool_test.html @@ -0,0 +1,562 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright 2006 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> +<head> +<meta http-equiv="X-UA-Compatible" content="IE=edge"> +<title>Closure Unit Tests - goog.structs.PriorityPool</title> +<script src="../base.js"></script> +<script> + goog.require('goog.structs.PriorityPool'); + goog.require('goog.testing.MockClock'); + goog.require('goog.testing.jsunit'); + goog.require('goog.structs'); +</script> +</head> +<body> +<script> + +// Implementation of the Pool class with isObjectDead() always returning TRUE, +// so that the the Pool will not reuse any objects. +function NoObjectReusePriorityPool(opt_min, opt_max) { + goog.structs.PriorityPool.call(this, opt_min, opt_max); +}; +goog.inherits(NoObjectReusePriorityPool, goog.structs.PriorityPool); + +NoObjectReusePriorityPool.prototype.objectCanBeReused = function(obj) { + return false; +}; + + +function testExceedMax1() { + var p = new goog.structs.PriorityPool(0, 3); + + var getCount1 = 0; + var callback1 = function(obj) { + assertNotNull(obj); + getCount1++; + }; + + var getCount2 = 0; + var callback2 = function(obj) { + getCount2++; + }; + + p.getObject(callback1); + p.getObject(callback1); + p.getObject(callback1); + p.getObject(callback2); + p.getObject(callback2); + p.getObject(callback2); + + assertEquals('getCount for allocated, Should be 3', getCount1, 3); + assertEquals('getCount for unallocated, Should be 0', getCount2, 0); +} + + +function testExceedMax2() { + var p = new goog.structs.PriorityPool(0, 1); + + var getCount1 = 0; + var callback1 = function(obj) { + assertNotNull(obj); + getCount1++; + }; + + var getCount2 = 0; + var callback2 = function(obj) { + getCount2++; + }; + + p.getObject(callback1); + p.getObject(callback2); + p.getObject(callback2); + p.getObject(callback2); + p.getObject(callback2); + p.getObject(callback2); + + assertEquals('getCount for allocated, Should be 1', getCount1, 1); + assertEquals('getCount for unallocated, Should be 0', getCount2, 0); +} + +function testExceedMax3() { + var p = new goog.structs.PriorityPool(0, 2); + + var obj1 = null; + var callback1 = function(obj) { + obj1 = obj; + }; + + var obj2 = null; + var callback2 = function(obj) { + obj2 = obj; + }; + + var obj3 = null; + var callback3 = function(obj) { + obj3 = obj; + }; + + p.getObject(callback1); + p.getObject(callback2); + p.getObject(callback3); + + assertNotNull(obj1); + assertNotNull(obj2); + assertNull(obj3); +} + +function testExceedMax4() { + var p = new goog.structs.PriorityPool(); // default: 10 + var objs = []; + + var getCount1 = 0; + var callback1 = function(obj) { + assertNotNull(obj); + getCount1++; + }; + + var getCount2 = 0; + var callback2 = function(obj) { + getCount2++; + }; + + for (var i = 0; i < 12; i++) { + p.getObject(i < 10 ? callback1 : callback2); + } + + assertEquals('getCount for allocated, Should be 10', getCount1, 10); + assertEquals('getCount for unallocated, Should be 0', getCount2, 0); +} + + +function testReleaseAndGet1() { + var p = new goog.structs.PriorityPool(0, 10); + + var o = null; + var callback = function(obj) { + o = obj; + }; + + p.getObject(callback); + assertEquals(1, p.getCount()); + assertEquals(1, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + assertTrue('Result should be true', p.releaseObject(o)); + assertEquals(1, p.getCount()); + assertEquals(0, p.getInUseCount()); + assertEquals(1, p.getFreeCount()); +} + + +function testReleaseAndGet2() { + var p = new NoObjectReusePriorityPool(0, 10); + + var o = null; + var callback = function(obj) { + o = obj; + }; + + p.getObject(callback); + assertEquals(1, p.getCount()); + assertEquals(1, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + assertTrue('Result should be true', p.releaseObject(o)); + assertEquals(0, p.getCount()); + assertEquals(0, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); +} + + +function testReleaseAndGet3() { + var p = new goog.structs.PriorityPool(0, 10); + var o1 = null; + var callback1 = function(obj) { + o1 = obj; + }; + + var o2 = null; + var callback2 = function(obj) { + o2 = obj; + }; + + var o3 = null; + var callback3 = function(obj) { + o3 = obj; + }; + + var o4 = {}; + + p.getObject(callback1); + p.getObject(callback2); + p.getObject(callback3); + + assertEquals(3, p.getCount()); + assertEquals(3, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + assertTrue('Result should be true', p.releaseObject(o1)); + assertTrue('Result should be true', p.releaseObject(o2)); + assertFalse('Result should be false', p.releaseObject(o4)); + assertEquals(3, p.getCount()); + assertEquals(1, p.getInUseCount()); + assertEquals(2, p.getFreeCount()); +} + + +function testReleaseAndGet4() { + var p = new NoObjectReusePriorityPool(0, 10); + + var o1 = null; + var callback1 = function(obj) { + o1 = obj; + }; + + var o2 = null; + var callback2 = function(obj) { + o2 = obj; + }; + + var o3 = null; + var callback3 = function(obj) { + o3 = obj; + }; + + var o4 = {}; + + p.getObject(callback1); + p.getObject(callback2); + p.getObject(callback3); + assertEquals(3, p.getCount()); + assertEquals(3, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + assertTrue('Result should be true', p.releaseObject(o1)); + assertTrue('Result should be true', p.releaseObject(o2)); + assertFalse('Result should be false', p.releaseObject(o4)); + assertEquals(1, p.getCount()); + assertEquals(1, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); +} + + +function testIsInPool1() { + var p = new goog.structs.PriorityPool(); + var o1 = null; + var callback1 = function(obj) { + o1 = obj; + }; + + var o2 = null; + var callback2 = function(obj) { + o2 = obj; + }; + + var o3 = null; + var callback3 = function(obj) { + o3 = obj; + }; + + var o4 = {}; + var o5 = {}; + + p.getObject(callback1); + p.getObject(callback2); + p.getObject(callback3); + var o6 = o1; + + assertTrue(p.contains(o1)); + assertTrue(p.contains(o2)); + assertTrue(p.contains(o3)); + assertFalse(p.contains(o4)); + assertFalse(p.contains(o5)); + assertTrue(p.contains(o6)); +} + + +function testSetMin1() { + var p = new goog.structs.PriorityPool(0, 10); + + assertEquals(0, p.getCount()); + assertEquals(0, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + + p.setMinimumCount(10); + + assertEquals(10, p.getCount()); + assertEquals(0, p.getInUseCount()); + assertEquals(10, p.getFreeCount()); +} + + +function testSetMin2() { + var p = new goog.structs.PriorityPool(0, 10); + + assertEquals(0, p.getCount()); + assertEquals(0, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + + var o1 = null; + var callback1 = function(obj) { + o1 = obj; + }; + p.getObject(callback1); + + assertEquals(1, p.getCount()); + assertEquals(1, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + + p.setMinimumCount(10); + + assertEquals(10, p.getCount()); + assertEquals(1, p.getInUseCount()); + assertEquals(9, p.getFreeCount()); +} + + +function testSetMax1() { + var p = new goog.structs.PriorityPool(0, 10); + + assertEquals(0, p.getCount()); + assertEquals(0, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + + var o1 = null; + var callback1 = function(obj) { + o1 = obj; + }; + + var o2 = null; + var callback2 = function(obj) { + o2 = obj; + }; + + var o3 = null; + var callback3 = function(obj) { + o3 = obj; + }; + + var o4 = null; + var callback4 = function(obj) { + o4 = obj; + }; + + var o5 = null; + var callback5 = function(obj) { + o5 = obj; + }; + + p.getObject(callback1); + p.getObject(callback2); + p.getObject(callback3); + p.getObject(callback4); + p.getObject(callback5); + + assertEquals(5, p.getCount()); + assertEquals(5, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + + assertTrue('Result should be true', p.releaseObject(o5)); + + assertEquals(5, p.getCount()); + assertEquals(4, p.getInUseCount()); + assertEquals(1, p.getFreeCount()); + + p.setMaximumCount(4); + + assertEquals(4, p.getCount()); + assertEquals(4, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); +} + + +function testInvalidMinMax1() { + var p = new goog.structs.PriorityPool(0, 10); + + assertEquals(0, p.getCount()); + assertEquals(0, p.getInUseCount()); + assertEquals(0, p.getFreeCount()); + + assertThrows(function() { + p.setMinimumCount(11); + }); +} + + +function testInvalidMinMax2() { + var p = new goog.structs.PriorityPool(5, 10); + + assertEquals(5, p.getCount()); + assertEquals(0, p.getInUseCount()); + assertEquals(5, p.getFreeCount()); + + assertThrows(function() { + p.setMaximumCount(4); + }); +} + + +function testInvalidMinMax3() { + assertThrows(function() { + new goog.structs.PriorityPool(10, 1); + }); +} + +function testQueue1() { + var p = new goog.structs.PriorityPool(0, 2); + + var o1 = null; + var callback1 = function(obj) { + o1 = obj; + }; + + var o2 = null; + var callback2 = function(obj) { + o2 = obj; + }; + + var o3 = null; + var callback3 = function(obj) { + o3 = obj; + }; + + p.getObject(callback1); + p.getObject(callback2); + p.getObject(callback3); + + assertNotNull(o1); + assertNotNull(o2); + assertNull(o3); + + p.releaseObject(o1); + assertNotNull(o3); +} + + +function testPriority1() { + var p = new goog.structs.PriorityPool(0, 2); + + var o1 = null; + var callback1 = function(obj) { + o1 = obj; + }; + + var o2 = null; + var callback2 = function(obj) { + o2 = obj; + }; + + var o3 = null; + var callback3 = function(obj) { + o3 = obj; + }; + + var o4 = null; + var callback4 = function(obj) { + o4 = obj; + }; + + p.getObject(callback1); + p.getObject(callback2); + p.getObject(callback3, 10); + p.getObject(callback4, 5); + + assertNotNull(o1); + assertNotNull(o2); + assertNull(o3); + assertNull(o4); + + p.releaseObject(o1); + assertNull(o3); + assertNotNull(o4); +} + + +function testRateLimiting() { + var clock = new goog.testing.MockClock(); + clock.install(); + + var p = new goog.structs.PriorityPool(0, 4); + p.setDelay(100); + + var getCount = 0; + var callback = function(obj) { + assertNotNull(obj); + getCount++; + }; + + p.getObject(callback); + assertEquals(1, getCount); + + p.getObject(callback); + assertEquals(1, getCount); + + clock.tick(100); + assertEquals(2, getCount); + + p.getObject(callback); + p.getObject(callback); + assertEquals(2, getCount); + + clock.tick(100); + assertEquals(3, getCount); + + clock.tick(100); + assertEquals(4, getCount); + + p.getObject(callback); + assertEquals(4, getCount); + + clock.tick(100); + assertEquals(4, getCount); + + goog.dispose(clock); +} + + +function testRateLimitingWithChangingDelay() { + var clock = new goog.testing.MockClock(); + clock.install(); + + var p = new goog.structs.PriorityPool(0, 3); + p.setDelay(100); + + var getCount = 0; + var callback = function(obj) { + assertNotNull(obj); + getCount++; + }; + + p.getObject(callback); + assertEquals(1, getCount); + + p.getObject(callback); + assertEquals(1, getCount); + + clock.tick(50); + assertEquals(1, getCount); + + p.setDelay(50); + assertEquals(2, getCount); + + p.getObject(callback); + assertEquals(2, getCount); + + clock.tick(20); + assertEquals(2, getCount); + + p.setDelay(40); + assertEquals(2, getCount); + + clock.tick(20); + assertEquals(3, getCount); + + goog.dispose(clock); +} + + +</script> +</body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/structs/priorityqueue.js b/contexts/data/lib/closure-library/closure/goog/structs/priorityqueue.js new file mode 100644 index 0000000..07b2b28 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/priorityqueue.js @@ -0,0 +1,64 @@ +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Datastructure: Priority Queue. + * + * + * This file provides the implementation of a Priority Queue. Smaller priorities + * move to the front of the queue. If two values have the same priority, + * it is arbitrary which value will come to the front of the queue first. + */ + +// TODO(user): Should this rely on natural ordering via some Comparable +// interface? + + +goog.provide('goog.structs.PriorityQueue'); + +goog.require('goog.structs'); +goog.require('goog.structs.Heap'); + + + +/** + * Class for Priority Queue datastructure. + * + * @constructor + * @extends {goog.structs.Heap} + */ +goog.structs.PriorityQueue = function() { + goog.structs.Heap.call(this); +}; +goog.inherits(goog.structs.PriorityQueue, goog.structs.Heap); + + +/** + * Puts the specified value in the queue. + * @param {*} priority The priority of the value. + * @param {*} value The value. + */ +goog.structs.PriorityQueue.prototype.enqueue = function(priority, value) { + this.insert(priority, value); +}; + + +/** + * Retrieves and removes the head of this queue. + * @return {*} The element at the head of this queue. Returns + * undefined if the queue is empty. + */ +goog.structs.PriorityQueue.prototype.dequeue = function() { + return this.remove(); +}; diff --git a/contexts/data/lib/closure-library/closure/goog/structs/priorityqueue_test.html b/contexts/data/lib/closure-library/closure/goog/structs/priorityqueue_test.html new file mode 100644 index 0000000..ceae23c --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/priorityqueue_test.html @@ -0,0 +1,179 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright 2006 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> +<head> +<meta http-equiv="X-UA-Compatible" content="IE=edge"> +<title>Closure Unit Tests - goog.structs.PriorityQueue</title> +<script src="../base.js"></script> +<script> + goog.require('goog.structs'); + goog.require('goog.structs.PriorityQueue'); + goog.require('goog.testing.jsunit'); +</script> +</head> +<body> +<script> + +function getPriorityQueue() { + var p = new goog.structs.PriorityQueue(); + p.enqueue(0, 'a'); + p.enqueue(1, 'b'); + p.enqueue(2, 'c'); + p.enqueue(3, 'd'); + return p; +} + + +function getPriorityQueue2() { + var p = new goog.structs.PriorityQueue(); + p.insert(1, 'b'); + p.insert(3, 'd'); + p.insert(0, 'a'); + p.insert(2, 'c'); + return p; +} + + +function testGetCount1() { + var p = getPriorityQueue(); + assertEquals('count, should be 4', p.getCount(), 4); + p.dequeue(); + assertEquals('count, should be 3', p.getCount(), 3); +} + + +function testGetCount2() { + var p = getPriorityQueue(); + assertEquals('count, should be 4', p.getCount(), 4); + p.dequeue(); + assertEquals('count, should be 3', p.getCount(), 3); +} + + +function testGetCount3() { + var p = getPriorityQueue(); + p.dequeue(); + p.dequeue(); + p.dequeue(); + p.dequeue(); + assertEquals('count, should be 0', p.getCount(), 0); +} + + +function testKeys() { + var p = getPriorityQueue(); + var keys = p.getKeys(); + for (var i = 0; i < 4; i++) { + assertTrue('getKeys, key ' + i + ' found', goog.structs.contains(keys, i)); + } + assertEquals('getKeys, Should be 4 keys', goog.structs.getCount(keys), 4); +} + + +function testValues() { + var p = getPriorityQueue(); + var values = p.getValues(); + + assertTrue('getKeys, value "a" found', goog.structs.contains(values, 'a')); + assertTrue('getKeys, value "b" found', goog.structs.contains(values, 'b')); + assertTrue('getKeys, value "c" found', goog.structs.contains(values, 'c')); + assertTrue('getKeys, value "d" found', goog.structs.contains(values, 'd')); + assertEquals('getKeys, Should be 4 keys', goog.structs.getCount(values), 4); +} + + +function testClear() { + var p = getPriorityQueue(); + p.clear(); + assertTrue('cleared so it should be empty', p.isEmpty()); +} + + +function testIsEmpty() { + var p = getPriorityQueue(); + assertFalse('4 values so should not be empty', p.isEmpty()); + + p.dequeue(); + p.dequeue(); + p.dequeue(); + assertFalse('1 values so should not be empty', p.isEmpty()); + + p.dequeue(); + assertTrue('0 values so should be empty', p.isEmpty()); +} + + +function testPeek1() { + var p = getPriorityQueue(); + assertEquals('peek, Should be "a"', p.peek(), 'a'); +} + + +function testPeek2() { + var p = getPriorityQueue2(); + assertEquals('peek, Should be "a"', p.peek(), 'a'); +} + + +function testPeek3() { + var p = getPriorityQueue(); + p.clear(); + assertEquals('peek, Should be "a"', p.peek(), undefined); +} + + +function testDequeue1() { + var p = getPriorityQueue(); + + assertEquals('dequeue, Should be "a"', p.dequeue(), 'a'); + assertEquals('dequeue, Should be "b"', p.dequeue(), 'b'); + assertEquals('dequeue, Should be "c"', p.dequeue(), 'c'); + assertEquals('dequeue, Should be "d"', p.dequeue(), 'd'); +} + + +function testDequeue2() { + var p = getPriorityQueue2(); + + assertEquals('dequeue, Should be "a"', p.dequeue(), 'a'); + assertEquals('dequeue, Should be "b"', p.dequeue(), 'b'); + assertEquals('dequeue, Should be "c"', p.dequeue(), 'c'); + assertEquals('dequeue, Should be "d"', p.dequeue(), 'd'); +} + + +function testEnqueuePeek1() { + var p = new goog.structs.PriorityQueue(); + + p.enqueue(3, 'd'); + assertEquals('peak, Should be "d"', p.peek(), 'd'); + p.enqueue(2, 'c'); + assertEquals('peak, Should be "c"', p.peek(), 'c'); + p.enqueue(1, 'b'); + assertEquals('peak, Should be "b"', p.peek(), 'b'); + p.enqueue(0, 'a'); + assertEquals('peak, Should be "a"', p.peek(), 'a'); +} + + +function testEnqueuePeek2() { + var p = new goog.structs.PriorityQueue(); + + p.enqueue(1, 'b'); + assertEquals('peak, Should be "b"', p.peek(), 'b'); + p.enqueue(3, 'd'); + assertEquals('peak, Should be "b"', p.peek(), 'b'); + p.enqueue(0, 'a'); + assertEquals('peak, Should be "a"', p.peek(), 'a'); + p.enqueue(2, 'c'); + assertEquals('peak, Should be "a"', p.peek(), 'a'); +} + +</script> +</body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/structs/quadtree.js b/contexts/data/lib/closure-library/closure/goog/structs/quadtree.js new file mode 100644 index 0000000..db52476 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/quadtree.js @@ -0,0 +1,571 @@ +// Copyright 2008 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Datastructure: A point Quad Tree for representing 2D data. Each + * region has the same ratio as the bounds for the tree. + * + * The implementation currently requires pre-determined bounds for data as it + * can not rebalance itself to that degree. + * + * @see ../demos/quadtree.html + */ + + +goog.provide('goog.structs.QuadTree'); +goog.provide('goog.structs.QuadTree.Node'); +goog.provide('goog.structs.QuadTree.Point'); + +goog.require('goog.math.Coordinate'); + + + +/** + * Constructs a new quad tree. + * @param {number} minX Minimum x-value that can be held in tree. + * @param {number} minY Minimum y-value that can be held in tree. + * @param {number} maxX Maximum x-value that can be held in tree. + * @param {number} maxY Maximum y-value that can be held in tree. + * @constructor + */ +goog.structs.QuadTree = function(minX, minY, maxX, maxY) { + + /** + * The root node for the quad tree. + * @type {goog.structs.QuadTree.Node} + * @private + */ + this.root_ = new goog.structs.QuadTree.Node( + minX, minY, maxX - minX, maxY - minY); +}; + + +/** + * Count of the number of items in the tree. + * @type {number} + * @private + */ +goog.structs.QuadTree.prototype.count_ = 0; + + +/** + * Returns a reference to the tree's root node. Callers shouldn't modify nodes, + * directly. This is a convenience for visualization and debugging purposes. + * @return {goog.structs.QuadTree.Node} The root node. + */ +goog.structs.QuadTree.prototype.getRootNode = function() { + return this.root_; +}; + + +/** + * Sets the value of an (x, y) point within the quad-tree. + * @param {number} x The x-coordinate. + * @param {number} y The y-coordinate. + * @param {*} value The value associated with the point. + */ +goog.structs.QuadTree.prototype.set = function(x, y, value) { + var root = this.root_; + if (x < root.x || y < root.y || x > root.x + root.w || y > root.y + root.h) { + throw Error('Out of bounds : (' + x + ', ' + y + ')'); + } + if (this.insert_(root, new goog.structs.QuadTree.Point(x, y, value))) { + this.count_++; + } +}; + + +/** + * Gets the value of the point at (x, y) or null if the point is empty. + * @param {number} x The x-coordinate. + * @param {number} y The y-coordinate. + * @param {*=} opt_default The default value to return if the node doesn't + * exist. + * @return {*} The value of the node, the default value if the node + * doesn't exist, or undefined if the node doesn't exist and no default + * has been provided. + */ +goog.structs.QuadTree.prototype.get = function(x, y, opt_default) { + var node = this.find_(this.root_, x, y); + return node ? node.point.value : opt_default; +}; + + +/** + * Removes a point from (x, y) if it exists. + * @param {number} x The x-coordinate. + * @param {number} y The y-coordinate. + * @return {*} The value of the node that was removed, or null if the + * node doesn't exist. + */ +goog.structs.QuadTree.prototype.remove = function(x, y) { + var node = this.find_(this.root_, x, y); + if (node) { + var value = node.point.value; + node.point = null; + node.nodeType = goog.structs.QuadTree.NodeType.EMPTY; + this.balance_(node); + this.count_--; + return value; + } else { + return null; + } +}; + + +/** + * Returns true if the point at (x, y) exists in the tree. + * @param {number} x The x-coordinate. + * @param {number} y The y-coordinate. + * @return {boolean} Whether the tree contains a point at (x, y). + */ +goog.structs.QuadTree.prototype.contains = function(x, y) { + return this.get(x, y) != null; +}; + + +/** + * @return {boolean} Whether the tree is empty. + */ +goog.structs.QuadTree.prototype.isEmpty = function() { + return this.root_.nodeType == goog.structs.QuadTree.NodeType.EMPTY; +}; + + +/** + * @return {number} The number of items in the tree. + */ +goog.structs.QuadTree.prototype.getCount = function() { + return this.count_; +}; + + +/** + * Removes all items from the tree. + */ +goog.structs.QuadTree.prototype.clear = function() { + this.root_.nw = this.root_.ne = this.root_.sw = this.root_.se = null; + this.root_.nodeType = goog.structs.QuadTree.NodeType.EMPTY; + this.root_.point = null; + this.count_ = 0; +}; + + +/** + * Returns an array containing the coordinates of each point stored in the tree. + * @return {Array.<goog.math.Coordinate?>} Array of coordinates. + */ +goog.structs.QuadTree.prototype.getKeys = function() { + var arr = []; + this.traverse_(this.root_, function(node) { + arr.push(new goog.math.Coordinate(node.point.x, node.point.y)); + }); + return arr; +}; + + +/** + * Returns an array containing all values stored within the tree. + * @return {Array.<Object>} The values stored within the tree. + */ +goog.structs.QuadTree.prototype.getValues = function() { + var arr = []; + this.traverse_(this.root_, function(node) { + // Must have a point because it's a leaf. + arr.push(node.point.value); + }); + return arr; +}; + + +/** + * Clones the quad-tree and returns the new instance. + * @return {goog.structs.QuadTree} A clone of the tree. + */ +goog.structs.QuadTree.prototype.clone = function() { + var x1 = this.root_.x; + var y1 = this.root_.y; + var x2 = x1 + this.root_.w; + var y2 = y1 + this.root_.h; + var clone = new goog.structs.QuadTree(x1, y1, x2, y2); + // This is inefficient as the clone needs to recalculate the structure of the + // tree, even though we know it already. But this is easier and can be + // optimized when/if needed. + this.traverse_(this.root_, function(node) { + clone.set(node.point.x, node.point.y, node.point.value); + }); + return clone; +}; + + +/** + * Traverses the tree and calls a function on each node. + * @param {function(Object, goog.math.Coordinate, goog.structs.QuadTree)} fn + * The function to call for every value. This function takes 3 arguments + * (the value, the coordinate, and the tree itself) and the return value is + * irrelevant. + * @param {Object=} opt_obj The object to be used as the value of 'this' + * within {@ code fn}. + */ +goog.structs.QuadTree.prototype.forEach = function(fn, opt_obj) { + this.traverse_(this.root_, function(node) { + var coord = new goog.math.Coordinate(node.point.x, node.point.y); + fn.call(opt_obj, node.point.value, coord, this); + }); +}; + + +/** + * Traverses the tree depth-first, with quadrants being traversed in clockwise + * order (NE, SE, SW, NW). The provided function will be called for each + * leaf node that is encountered. + * @param {goog.structs.QuadTree.Node} node The current node. + * @param {function(goog.structs.QuadTree.Node)} fn The function to call + * for each leaf node. This function takes the node as an argument, and its + * return value is irrelevant. + * @private + */ +goog.structs.QuadTree.prototype.traverse_ = function(node, fn) { + switch (node.nodeType) { + case goog.structs.QuadTree.NodeType.LEAF: + fn.call(this, node); + break; + + case goog.structs.QuadTree.NodeType.POINTER: + this.traverse_(node.ne, fn); + this.traverse_(node.se, fn); + this.traverse_(node.sw, fn); + this.traverse_(node.nw, fn); + break; + } +}; + + +/** + * Finds a leaf node with the same (x, y) coordinates as the target point, or + * null if no point exists. + * @param {goog.structs.QuadTree.Node} node The node to search in. + * @param {number} x The x-coordinate of the point to search for. + * @param {number} y The y-coordinate of the point to search for. + * @return {goog.structs.QuadTree.Node} The leaf node that matches the target, + * or null if it doesn't exist. + * @private + */ +goog.structs.QuadTree.prototype.find_ = function(node, x, y) { + switch (node.nodeType) { + case goog.structs.QuadTree.NodeType.EMPTY: + return null; + + case goog.structs.QuadTree.NodeType.LEAF: + return node.point.x == x && node.point.y == y ? node : null; + + case goog.structs.QuadTree.NodeType.POINTER: + return this.find_(this.getQuadrantForPoint_(node, x, y), x, y); + + default: + throw Error('Invalid nodeType'); + } +}; + + +/** + * Inserts a point into the tree, updating the tree's structure if necessary. + * @param {goog.structs.QuadTree.Node} parent The parent to insert the point + * into. + * @param {goog.structs.QuadTree.Point} point The point to insert. + * @return {boolean} True if a new node was added to the tree; False if a node + * already existed with the correpsonding coordinates and had its value + * reset. + * @private + */ +goog.structs.QuadTree.prototype.insert_ = function(parent, point) { + switch (parent.nodeType) { + case goog.structs.QuadTree.NodeType.EMPTY: + this.setPointForNode_(parent, point); + return true; + + case goog.structs.QuadTree.NodeType.LEAF: + if (parent.point.x == point.x && parent.point.y == point.y) { + this.setPointForNode_(parent, point); + return false; + } else { + this.split_(parent); + return this.insert_(parent, point); + } + + case goog.structs.QuadTree.NodeType.POINTER: + return this.insert_( + this.getQuadrantForPoint_(parent, point.x, point.y), point); + + default: + throw Error('Invalid nodeType in parent'); + } +}; + + +/** + * Converts a leaf node to a pointer node and reinserts the node's point into + * the correct child. + * @param {goog.structs.QuadTree.Node} node The node to split. + * @private + */ +goog.structs.QuadTree.prototype.split_ = function(node) { + var oldPoint = node.point; + node.point = null; + + node.nodeType = goog.structs.QuadTree.NodeType.POINTER; + + var x = node.x; + var y = node.y; + var hw = node.w / 2; + var hh = node.h / 2; + + node.nw = new goog.structs.QuadTree.Node(x, y, hw, hh, node); + node.ne = new goog.structs.QuadTree.Node(x + hw, y, hw, hh, node); + node.sw = new goog.structs.QuadTree.Node(x, y + hh, hw, hh, node); + node.se = new goog.structs.QuadTree.Node(x + hw, y + hh, hw, hh, node); + + this.insert_(node, oldPoint); +}; + + +/** + * Attempts to balance a node. A node will need balancing if all its children + * are empty or it contains just one leaf. + * @param {goog.structs.QuadTree.Node} node The node to balance. + * @private + */ +goog.structs.QuadTree.prototype.balance_ = function(node) { + switch (node.nodeType) { + case goog.structs.QuadTree.NodeType.EMPTY: + case goog.structs.QuadTree.NodeType.LEAF: + if (node.parent) { + this.balance_(node.parent); + } + break; + + case goog.structs.QuadTree.NodeType.POINTER: + var nw = node.nw, ne = node.ne, sw = node.sw, se = node.se; + var firstLeaf = null; + + // Look for the first non-empty child, if there is more than one then we + // break as this node can't be balanced. + if (nw.nodeType != goog.structs.QuadTree.NodeType.EMPTY) { + firstLeaf = nw; + } + if (ne.nodeType != goog.structs.QuadTree.NodeType.EMPTY) { + if (firstLeaf) { + break; + } + firstLeaf = ne; + } + if (sw.nodeType != goog.structs.QuadTree.NodeType.EMPTY) { + if (firstLeaf) { + break; + } + firstLeaf = sw; + } + if (se.nodeType != goog.structs.QuadTree.NodeType.EMPTY) { + if (firstLeaf) { + break; + } + firstLeaf = se; + } + + if (!firstLeaf) { + // All child nodes are empty: so make this node empty. + node.nodeType = goog.structs.QuadTree.NodeType.EMPTY; + node.nw = node.ne = node.sw = node.se = null; + + } else if (firstLeaf.nodeType == goog.structs.QuadTree.NodeType.POINTER) { + // Only child was a pointer, therefore we can't rebalance. + break; + + } else { + // Only child was a leaf: so update node's point and make it a leaf. + node.nodeType = goog.structs.QuadTree.NodeType.LEAF; + node.nw = node.ne = node.sw = node.se = null; + node.point = firstLeaf.point; + } + + // Try and balance the parent as well. + if (node.parent) { + this.balance_(node.parent); + } + + break; + } +}; + + +/** + * Returns the child quadrant within a node that contains the given (x, y) + * coordinate. + * @param {goog.structs.QuadTree.Node} parent The node. + * @param {number} x The x-coordinate to look for. + * @param {number} y The y-coordinate to look for. + * @return {goog.structs.QuadTree.Node} The child quadrant that contains the + * point. + * @private + */ +goog.structs.QuadTree.prototype.getQuadrantForPoint_ = function(parent, x, y) { + var mx = parent.x + parent.w / 2; + var my = parent.y + parent.h / 2; + if (x < mx) { + return y < my ? parent.nw : parent.sw; + } else { + return y < my ? parent.ne : parent.se; + } +}; + + +/** + * Sets the point for a node, as long as the node is a leaf or empty. + * @param {goog.structs.QuadTree.Node} node The node to set the point for. + * @param {goog.structs.QuadTree.Point} point The point to set. + * @private + */ +goog.structs.QuadTree.prototype.setPointForNode_ = function(node, point) { + if (node.nodeType == goog.structs.QuadTree.NodeType.POINTER) { + throw Error('Can not set point for node of type POINTER'); + } + node.nodeType = goog.structs.QuadTree.NodeType.LEAF; + node.point = point; +}; + + +/** + * Enumeration of node types. + * @enum {number} + */ +goog.structs.QuadTree.NodeType = { + EMPTY: 0, + LEAF: 1, + POINTER: 2 +}; + + + +/** + * Constructs a new quad tree node. + * @param {number} x X-coordiate of node. + * @param {number} y Y-coordinate of node. + * @param {number} w Width of node. + * @param {number} h Height of node. + * @param {goog.structs.QuadTree.Node=} opt_parent Optional parent node. + * @constructor + */ +goog.structs.QuadTree.Node = function(x, y, w, h, opt_parent) { + /** + * The x-coordinate of the node. + * @type {number} + */ + this.x = x; + + /** + * The y-coordinate of the node. + * @type {number} + */ + this.y = y; + + /** + * The width of the node. + * @type {number} + */ + this.w = w; + + /** + * The height of the node. + * @type {number} + */ + this.h = h; + + /** + * The parent node. + * @type {goog.structs.QuadTree.Node?} + */ + this.parent = opt_parent || null; +}; + + +/** + * The node's type. + * @type {goog.structs.QuadTree.NodeType} + */ +goog.structs.QuadTree.Node.prototype.nodeType = + goog.structs.QuadTree.NodeType.EMPTY; + + +/** + * The child node in the North-West quadrant. + * @type {goog.structs.QuadTree.Node?} + */ +goog.structs.QuadTree.Node.prototype.nw = null; + + +/** + * The child node in the North-East quadrant. + * @type {goog.structs.QuadTree.Node?} + */ +goog.structs.QuadTree.Node.prototype.ne = null; + + +/** + * The child node in the South-West quadrant. + * @type {goog.structs.QuadTree.Node?} + */ +goog.structs.QuadTree.Node.prototype.sw = null; + + +/** + * The child node in the South-East quadrant. + * @type {goog.structs.QuadTree.Node?} + */ +goog.structs.QuadTree.Node.prototype.se = null; + + +/** + * The point for the node, if it is a leaf node. + * @type {goog.structs.QuadTree.Point?} + */ +goog.structs.QuadTree.Node.prototype.point = null; + + + +/** + * Creates a new point object. + * @param {number} x The x-coordinate of the point. + * @param {number} y The y-coordinate of the point. + * @param {*=} opt_value Optional value associated with the point. + * @constructor + */ +goog.structs.QuadTree.Point = function(x, y, opt_value) { + /** + * The x-coordinate for the point. + * @type {number} + */ + this.x = x; + + /** + * The y-coordinate for the point. + * @type {number} + */ + this.y = y; + + /** + * Optional value associated with the point. + * @type {*} + */ + this.value = goog.isDef(opt_value) ? opt_value : null; +}; diff --git a/contexts/data/lib/closure-library/closure/goog/structs/quadtree_test.html b/contexts/data/lib/closure-library/closure/goog/structs/quadtree_test.html new file mode 100644 index 0000000..c51e144 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/quadtree_test.html @@ -0,0 +1,179 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright 2008 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> +<head> +<meta http-equiv="X-UA-Compatible" content="IE=edge"> +<title>Closure Unit Tests - goog.structs.QuadTree</title> +<script src="../base.js"></script> +<script> + goog.require('goog.array'); + goog.require('goog.structs'); + goog.require('goog.structs.QuadTree'); + goog.require('goog.testing.jsunit'); +</script> +</head> +<body> +<script> + + function getTree() { + var qt = new goog.structs.QuadTree(0, 0, 100, 100); + qt.set(5, 20, 'Foo'); + qt.set(50, 32, 'Bar'); + qt.set(47, 96, 'Baz'); + qt.set(50, 50, 'Bing'); + qt.set(12, 0, 'Bong'); + return qt; + } + + function testGetCount() { + var qt = getTree(); + assertEquals('Count should be 5', 5, qt.getCount()); + qt.remove(50, 32); + assertEquals('Count should be 4', 4, qt.getCount()); + } + + function testGetKeys() { + var keys = getTree().getKeys(); + var keyString = keys.sort().join(' '); + var expected = '(12, 0) (47, 96) (5, 20) (50, 32) (50, 50)'; + assertEquals('Sorted keys should be ' + expected, expected, keyString); + } + + function testGetValues() { + var values = getTree().getValues(); + var valueString = values.sort().join(','); + assertEquals('Sorted values should be Bar,Baz,Bing,Bong,Foo', + 'Bar,Baz,Bing,Bong,Foo', valueString); + } + + function testContains() { + var qt = getTree(); + assertTrue('Should contain (5, 20)', qt.contains(5, 20)); + assertFalse('Should not contain (13, 13)', qt.contains(13, 13)); + } + + function testClear() { + var qt = getTree(); + qt.clear(); + assertTrue('Tree should be empty', qt.isEmpty()); + assertFalse('Tree should not contain (5, 20)', qt.contains(5, 20)); + } + + function testConstructor() { + var qt = new goog.structs.QuadTree(-10, -5, 6, 12); + var root = qt.getRootNode(); + assertEquals('X of root should be -10', -10, root.x); + assertEquals('Y of root should be -5', -5, root.y); + assertEquals('Width of root should be 16', 16, root.w); + assertEquals('Height of root should be 17', 17, root.h); + assertTrue('Tree should be empty', qt.isEmpty()); + } + + function testClone() { + var qt = getTree().clone(); + assertFalse('Clone should not be empty', qt.isEmpty()); + assertTrue('Should contain (47, 96)', qt.contains(47, 96)); + } + + function testRemove() { + var qt = getTree(); + assertEquals('(5, 20) should be removed', 'Foo', qt.remove(5, 20)); + assertEquals('(5, 20) should be removed', 'Bar', qt.remove(50, 32)); + assertEquals('(5, 20) should be removed', 'Baz', qt.remove(47, 96)); + assertEquals('(5, 20) should be removed', 'Bing', qt.remove(50, 50)); + assertEquals('(5, 20) should be removed', 'Bong', qt.remove(12, 0)); + assertNull('(6, 6) wasn\'t there to remove', qt.remove(6, 6)); + assertTrue('Tree should be empty', qt.isEmpty()); + assertTreesChildrenAreNull(qt) + } + + function testIsEmpty() { + var qt = getTree(); + qt.clear(); + assertTrue(qt.isEmpty()); + assertEquals('Root should be empty node', + goog.structs.QuadTree.NodeType.EMPTY, qt.getRootNode().nodeType); + assertTreesChildrenAreNull(qt); + } + + function testForEach() { + var qt = getTree(); + var s = ''; + goog.structs.forEach(qt, function(val, key, qt2) { + assertNotUndefined(key); + assertEquals(qt, qt2); + s += key.x + ',' + key.y + '=' + val + ' '; + }); + assertEquals('50,32=Bar 50,50=Bing 47,96=Baz 5,20=Foo 12,0=Bong ', s); + } + + function testBalancing() { + var qt = new goog.structs.QuadTree(0, 0, 100, 100); + var root = qt.getRootNode(); + + // Add a point to the NW quadrant. + qt.set(25, 25, 'first'); + + assertEquals('Root should be a leaf node.', + goog.structs.QuadTree.NodeType.LEAF, root.nodeType); + assertTreesChildrenAreNull(qt); + + assertEquals('first', root.point.value); + + // Add another point in the NW quadrant + qt.set(25, 30, 'second'); + + assertEquals('Root should now be a pointer.', + goog.structs.QuadTree.NodeType.POINTER, root.nodeType); + assertNotNull('NE should be not be null', root.ne); + assertNotNull('NW should be not be null', root.nw); + assertNotNull('SE should be not be null', root.se); + assertNotNull('SW should be not be null', root.sw); + assertNull(root.point); + + // Delete the second point. + qt.remove(25, 30); + + assertEquals('Root should have been rebalanced and be a leaf node.', + goog.structs.QuadTree.NodeType.LEAF, root.nodeType); + assertTreesChildrenAreNull(qt); + assertEquals('first', root.point.value); + } + + function testTreeBounds() { + var qt = getTree(); + assertFails(qt, qt.set, [-10, -10, 1]); + assertFails(qt, qt.set, [-10, 10, 2]); + assertFails(qt, qt.set, [10, -10, 3]); + assertFails(qt, qt.set, [-10, 110, 4]); + assertFails(qt, qt.set, [10, 130, 5]); + assertFails(qt, qt.set, [110, -10, 6]); + assertFails(qt, qt.set, [150, 14, 7]); + } + + // Helper functions + + function assertFails(context, fn, args) { + assertThrows('Exception expected from ' + fn.toString() + + ' with arguments ' + args, + function() { + fn.apply(context, args); + }); + } + + function assertTreesChildrenAreNull(qt) { + var root = qt.getRootNode(); + assertNull('NE should be null', root.ne); + assertNull('NW should be null', root.nw); + assertNull('SE should be null', root.se); + assertNull('SW should be null', root.sw); + } + +</script> +</body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/structs/queue.js b/contexts/data/lib/closure-library/closure/goog/structs/queue.js new file mode 100644 index 0000000..3be02f5 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/queue.js @@ -0,0 +1,157 @@ +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Datastructure: Queue. + * + * + * This file provides the implementation of a FIFO Queue structure. + * API is similar to that of com.google.common.collect.IntQueue + */ + +goog.provide('goog.structs.Queue'); + +goog.require('goog.array'); + + + +/** + * Class for FIFO Queue data structure. + * + * @constructor + */ +goog.structs.Queue = function() { + this.elements_ = []; +}; + + +/** + * The index of the next element to be removed from the queue. + * @private + * @type {number} + */ +goog.structs.Queue.prototype.head_ = 0; + + +/** + * The index at which the next element would be added to the queue. + * @private + * @type {number} + */ +goog.structs.Queue.prototype.tail_ = 0; + + +/** + * Puts the specified element on this queue. + * @param {*} element The element to be added to the queue. + */ +goog.structs.Queue.prototype.enqueue = function(element) { + this.elements_[this.tail_++] = element; +}; + + +/** + * Retrieves and removes the head of this queue. + * @return {*} The element at the head of this queue. Returns undefined if the + * queue is empty. + */ +goog.structs.Queue.prototype.dequeue = function() { + if (this.head_ == this.tail_) { + return undefined; + } + var result = this.elements_[this.head_]; + delete this.elements_[this.head_]; + this.head_++; + return result; +}; + + +/** + * Retrieves but does not remove the head of this queue. + * @return {*} The element at the head of this queue. Returns undefined if the + * queue is empty. + */ +goog.structs.Queue.prototype.peek = function() { + if (this.head_ == this.tail_) { + return undefined; + } + return this.elements_[this.head_]; +}; + + +/** + * Returns the number of elements in this queue. + * @return {number} The number of elements in this queue. + */ +goog.structs.Queue.prototype.getCount = function() { + return this.tail_ - this.head_; +}; + + +/** + * Returns true if this queue contains no elements. + * @return {boolean} true if this queue contains no elements. + */ +goog.structs.Queue.prototype.isEmpty = function() { + return this.tail_ - this.head_ == 0; +}; + + +/** + * Removes all elements from the queue. + */ +goog.structs.Queue.prototype.clear = function() { + this.elements_.length = 0; + this.head_ = 0; + this.tail_ = 0; +}; + + +/** + * Returns true if the given value is in the queue. + * @param {*} obj The value to look for. + * @return {boolean} Whether the object is in the queue. + */ +goog.structs.Queue.prototype.contains = function(obj) { + return goog.array.contains(this.elements_, obj); +}; + + +/** + * Removes the first occurrence of a particular value from the queue. + * @param {*} obj Object to remove. + * @return {boolean} True if an element was removed. + */ +goog.structs.Queue.prototype.remove = function(obj) { + var index = goog.array.indexOf(this.elements_, obj); + if (index < 0) { + return false; + } + if (index == this.head_) { + this.dequeue(); + } else { + goog.array.removeAt(this.elements_, index); + this.tail_--; + } + return true; +}; + + +/** + * Returns all the values in the queue. + * @return {Array} An array of the values in the queue. + */ +goog.structs.Queue.prototype.getValues = function() { + return this.elements_.slice(this.head_, this.tail_); +}; diff --git a/contexts/data/lib/closure-library/closure/goog/structs/queue_test.html b/contexts/data/lib/closure-library/closure/goog/structs/queue_test.html new file mode 100644 index 0000000..bbfae75 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/queue_test.html @@ -0,0 +1,140 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright 2006 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> +<head> +<meta http-equiv="X-UA-Compatible" content="IE=edge"> +<title>Closure Unit Tests - goog.structs.Queue</title> +<script src="../base.js"></script> +<script> + goog.require('goog.structs.Queue'); + goog.require('goog.testing.jsunit'); +</script> +</head> +<body> +<script> + +function stringifyQueue(q) { + var values = q.getValues(); + var s = ''; + for (var i = 0; i < values.length; i++) { + s += values[i]; + } + return s; +} + +function createQueue() { + var q = new goog.structs.Queue(); + q.enqueue('a'); + q.enqueue('b'); + q.enqueue('c'); + return q; +} + +function testConstructor() { + var q = new goog.structs.Queue(); + assertTrue('testConstructor(), queue should be empty initially', q.isEmpty()); + assertEquals('testConstructor(), count should be 0', q.getCount(), 0); + assertEquals('testConstructor(), head element should be undefined', q.peek(), + undefined); +} + +function testCount() { + var q = createQueue(); + assertEquals('testCount(), count should be 3', q.getCount(), 3); + q.enqueue('d'); + assertEquals('testCount(), count should be 4', q.getCount(), 4); + q.dequeue(); + assertEquals('testCount(), count should be 3', q.getCount(), 3); + q.clear(); + assertEquals('testCount(), count should be 0', q.getCount(), 0); +} + +function testEnqueue() { + var q = new goog.structs.Queue(); + q.enqueue('a'); + assertEquals('testEnqueue(), count should be 1', q.getCount(), 1); + q.enqueue('b'); + assertEquals('testEnqueue(), count should be 2', q.getCount(), 2); + assertEquals('testEnqueue(), head element should be a', q.peek(), 'a'); + q.dequeue(); + assertEquals('testEnqueue(), count should be 1', q.getCount(), 1); + assertEquals('testEnqueue(), head element should be b', q.peek(), 'b'); +} + +function testDequeue() { + var q = createQueue(); + var head = q.dequeue(); + assertEquals('testDequeue(), should return a', head, 'a'); + q.dequeue(); + head = q.dequeue(); + assertEquals('testDequeue(), should return c', head, 'c'); + assertTrue('testDequeue(), queue should be empty', q.isEmpty()); + head = q.dequeue(); + assertEquals('testDequeue(), should return undefined for empty queue', head, + undefined); +} + +function testPeek() { + var q = createQueue(); + var head = q.peek(); + assertEquals('testPeek(), should return a', head, 'a'); + var head2 = q.dequeue(); + assertEquals('testPeek(), dequeue should return peek() result', head, head2); + head = q.peek(); + assertEquals('testPeek(), should return b', head, 'b'); + q.clear(); + head = q.peek(); + assertEquals('testPeek(), should return undefined for empty queue', head, + undefined); +} + +function testClear() { + var q = createQueue(); + q.clear(); + assertTrue('testClear(), queue should be empty', q.isEmpty()); +} + +function testQueue() { + var q = createQueue(); + assertEquals('testQueue(), contents must be abc', stringifyQueue(q), 'abc'); +} + +function testRemove() { + var q = createQueue(); + assertEquals('testRemove(), contents must be abc', stringifyQueue(q), 'abc'); + + q.dequeue(); + assertEquals('testRemove(), contents must be bc', stringifyQueue(q), 'bc'); + + q.enqueue('a'); + assertEquals('testRemove(), contents must be bca', stringifyQueue(q), 'bca'); + + assertTrue('testRemove(), remove should have returned true', q.remove('c')); + assertEquals('testRemove(), contents must be ba', stringifyQueue(q), 'ba'); + + assertTrue('testRemove(), remove should have returned true', q.remove('b')); + assertEquals('testRemove(), contents must be a', stringifyQueue(q), 'a'); + + assertFalse('testRemove(), remove should have returned false', q.remove('b')); + assertEquals('testRemove(), contents must be a', stringifyQueue(q), 'a'); + + assertTrue('testRemove(), remove should have returned true', q.remove('a')); + assertEquals('testRemove(), contents must be empty', stringifyQueue(q), ''); +} + +function testContains() { + var q = createQueue(); + assertTrue('testContains(), contains should have returned true', + q.contains('a')); + assertFalse('testContains(), contains should have returned false', + q.contains('foobar')); +} + +</script> +</body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/structs/set.js b/contexts/data/lib/closure-library/closure/goog/structs/set.js new file mode 100644 index 0000000..4719f6a --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/set.js @@ -0,0 +1,255 @@ +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Datastructure: Set. + * + * @author arv@google.com (Erik Arvidsson) + * @author pallosp@google.com (Peter Pallos) + * + * This class implements a set data structure. Adding and removing is O(1). It + * supports both object and primitive values. Be careful because you can add + * both 1 and new Number(1), because these are not the same. You can even add + * multiple new Number(1) because these are not equal. + */ + + +goog.provide('goog.structs.Set'); + +goog.require('goog.structs'); +goog.require('goog.structs.Collection'); +goog.require('goog.structs.Map'); + + + +/** + * A set that can contain both primitives and objects. Adding and removing + * elements is O(1). Primitives are treated as identical if they have the same + * type and convert to the same string. Objects are treated as identical only + * if they are references to the same object. WARNING: A goog.structs.Set can + * contain both 1 and (new Number(1)), because they are not the same. WARNING: + * Adding (new Number(1)) twice will yield two distinct elements, because they + * are two different objects. WARNING: Any object that is added to a + * goog.structs.Set will be modified! Because goog.getUid() is used to + * identify objects, every object in the set will be mutated. + * @param {Array|Object=} opt_values Initial values to start with. + * @constructor + * @implements {goog.structs.Collection} + */ +goog.structs.Set = function(opt_values) { + this.map_ = new goog.structs.Map; + if (opt_values) { + this.addAll(opt_values); + } +}; + + +/** + * Obtains a unique key for an element of the set. Primitives will yield the + * same key if they have the same type and convert to the same string. Object + * references will yield the same key only if they refer to the same object. + * @param {*} val Object or primitive value to get a key for. + * @return {string} A unique key for this value/object. + * @private + */ +goog.structs.Set.getKey_ = function(val) { + var type = typeof val; + if (type == 'object' && val || type == 'function') { + return 'o' + goog.getUid(/** @type {Object} */ (val)); + } else { + return type.substr(0, 1) + val; + } +}; + + +/** + * @return {number} The number of elements in the set. + */ +goog.structs.Set.prototype.getCount = function() { + return this.map_.getCount(); +}; + + +/** + * Add a primitive or an object to the set. + * @param {*} element The primitive or object to add. + */ +goog.structs.Set.prototype.add = function(element) { + this.map_.set(goog.structs.Set.getKey_(element), element); +}; + + +/** + * Adds all the values in the given collection to this set. + * @param {Array|Object} col A collection containing the elements to add. + */ +goog.structs.Set.prototype.addAll = function(col) { + var values = goog.structs.getValues(col); + var l = values.length; + for (var i = 0; i < l; i++) { + this.add(values[i]); + } +}; + + +/** + * Removes all values in the given collection from this set. + * @param {Array|Object} col A collection containing the elements to remove. + */ +goog.structs.Set.prototype.removeAll = function(col) { + var values = goog.structs.getValues(col); + var l = values.length; + for (var i = 0; i < l; i++) { + this.remove(values[i]); + } +}; + + +/** + * Removes the given element from this set. + * @param {*} element The primitive or object to remove. + * @return {boolean} Whether the element was found and removed. + */ +goog.structs.Set.prototype.remove = function(element) { + return this.map_.remove(goog.structs.Set.getKey_(element)); +}; + + +/** + * Removes all elements from this set. + */ +goog.structs.Set.prototype.clear = function() { + this.map_.clear(); +}; + + +/** + * Tests whether this set is empty. + * @return {boolean} True if there are no elements in this set. + */ +goog.structs.Set.prototype.isEmpty = function() { + return this.map_.isEmpty(); +}; + + +/** + * Tests whether this set contains the given element. + * @param {*} element The primitive or object to test for. + * @return {boolean} True if this set contains the given element. + */ +goog.structs.Set.prototype.contains = function(element) { + return this.map_.containsKey(goog.structs.Set.getKey_(element)); +}; + + +/** + * Tests whether this set contains all the values in a given collection. + * Repeated elements in the collection are ignored, e.g. (new + * goog.structs.Set([1, 2])).containsAll([1, 1]) is True. + * @param {Object} col A collection-like object. + * @return {boolean} True if the set contains all elements. + */ +goog.structs.Set.prototype.containsAll = function(col) { + return goog.structs.every(col, this.contains, this); +}; + + +/** + * Finds all values that are present in both this set and the given collection. + * @param {Array|Object} col A collection. + * @return {!goog.structs.Set} A new set containing all the values (primitives + * or objects) present in both this set and the given collection. + */ +goog.structs.Set.prototype.intersection = function(col) { + var result = new goog.structs.Set(); + + var values = goog.structs.getValues(col); + for (var i = 0; i < values.length; i++) { + var value = values[i]; + if (this.contains(value)) { + result.add(value); + } + } + + return result; +}; + + +/** + * Returns an array containing all the elements in this set. + * @return {!Array} An array containing all the elements in this set. + */ +goog.structs.Set.prototype.getValues = function() { + return this.map_.getValues(); +}; + + +/** + * Creates a shallow clone of this set. + * @return {!goog.structs.Set} A new set containing all the same elements as + * this set. + */ +goog.structs.Set.prototype.clone = function() { + return new goog.structs.Set(this); +}; + + +/** + * Tests whether the given collection consists of the same elements as this set, + * regardless of order, without repetition. Primitives are treated as equal if + * they have the same type and convert to the same string; objects are treated + * as equal if they are references to the same object. This operation is O(n). + * @param {Object} col A collection. + * @return {boolean} True if the given collection consists of the same elements + * as this set, regardless of order, without repetition. + */ +goog.structs.Set.prototype.equals = function(col) { + return this.getCount() == goog.structs.getCount(col) && this.isSubsetOf(col); +}; + + +/** + * Tests whether the given collection contains all the elements in this set. + * Primitives are treated as equal if they have the same type and convert to the + * same string; objects are treated as equal if they are references to the same + * object. This operation is O(n). + * @param {Object} col A collection. + * @return {boolean} True if this set is a subset of the given collection. + */ +goog.structs.Set.prototype.isSubsetOf = function(col) { + var colCount = goog.structs.getCount(col); + if (this.getCount() > colCount) { + return false; + } + // TODO(user) Find the minimal collection size where the conversion makes + // the contains() method faster. + if (!(col instanceof goog.structs.Set) && colCount > 5) { + // Convert to a goog.structs.Set so that goog.structs.contains runs in + // O(1) time instead of O(n) time. + col = new goog.structs.Set(col); + } + return goog.structs.every(this, function(value) { + return goog.structs.contains(col, value); + }); +}; + + +/** + * Returns an iterator that iterates over the elements in this set. + * @param {boolean=} opt_keys This argument is ignored. + * @return {!goog.iter.Iterator} An iterator over the elements in this set. + */ +goog.structs.Set.prototype.__iterator__ = function(opt_keys) { + return this.map_.__iterator__(false); +}; diff --git a/contexts/data/lib/closure-library/closure/goog/structs/set_perf.html b/contexts/data/lib/closure-library/closure/goog/structs/set_perf.html new file mode 100644 index 0000000..1b784bd --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/set_perf.html @@ -0,0 +1,237 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright 2009 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> +<!-- +--> +<head> +<meta http-equiv="X-UA-Compatible" content="IE=edge"> + <title>Closure Performance Tests - goog.ui.Set vs goog.ui.StringSet</title> + <link rel="stylesheet" type="text/css" href="../testing/performancetable.css"/> + <script src="../base.js"></script> + <script> + goog.require('goog.functions'); + goog.require('goog.string'); + goog.require('goog.structs.Set'); + goog.require('goog.structs.StringSet'); + goog.require('goog.testing.PerformanceTable'); + goog.require('goog.testing.PropertyReplacer'); + goog.require('goog.testing.jsunit'); + </script> +</head> +<body> + <h1>goog.ui.Set and goog.ui.StringSet Performance Tests</h1> + <p> + <strong>User-agent:</strong> + <script>document.write(navigator.userAgent);</script> + </p> + <div id="perfTable"></div> + <hr> + + <script> + var table = new goog.testing.PerformanceTable( + goog.dom.getElement('perfTable')); + + // Number of operations to measure in each table line. + var OPS_COUNT = 20000; + + var stubs = new goog.testing.PropertyReplacer(); + + function tearDown() { + stubs.reset(); + } + + function testCreateSetFromArrayWithoutRepetition() { + var values = [] + for (var i = 0; i < OPS_COUNT; i++) { + values.push(i); + } + + table.run(function() { + var s = new goog.structs.StringSet(values); + }, 'Create string set from number array without repetition'); + + values = [] + for (var i = 0; i < OPS_COUNT; i++) { + values.push(String(i)); + } + + table.run(function() { + var s = new goog.structs.StringSet(values); + }, 'Create string set from string array without repetition'); + } + + function testCreateSetWithoutRepetition() { + table.run(function() { + var s = new goog.structs.Set(); + for (var i = 0; i < OPS_COUNT; i++) { + s.add(i); + } + }, 'Add elements to set without repetition'); + + table.run(function() { + var s = new goog.structs.StringSet(); + for (var i = 0; i < OPS_COUNT; i++) { + s.add(i); + } + }, 'Add elements to string set without repetition'); + + stubs.set(goog.structs.StringSet.prototype, 'encode', + goog.functions.identity); + stubs.set(goog.structs.StringSet.prototype, 'decode', + goog.functions.identity); + + table.run(function() { + var s = new goog.structs.StringSet(); + for (var i = 0; i < OPS_COUNT; i++) { + s.add(i); + } + }, 'Add elements to string set without repetition and escaping'); + } + + function testCreateSetWithRepetition() { + table.run(function() { + var s = new goog.structs.Set(); + for (var n = 0; n < 10 ; n++) { + for (var i = 0; i < OPS_COUNT / 10; i++) { + s.add(i); + } + } + }, 'Add elements to set with repetition'); + + table.run(function() { + var s = new goog.structs.StringSet(); + for (var n = 0; n < 10; n++) { + for (var i = 0; i < OPS_COUNT / 10; i++) { + s.add(i); + } + } + }, 'Add elements to string set with repetition'); + } + + function testForEach() { + var bigSet = new goog.structs.Set; + var bigStringSet = new goog.structs.StringSet; + for (var i = 0; i < OPS_COUNT; i++) { + bigSet.add(i); + bigStringSet.add(i); + } + + table.run(function() { + goog.structs.forEach(bigSet, goog.nullFunction); + }, 'Iterate over set with forEach'); + + table.run(function() { + goog.structs.forEach(bigStringSet, goog.nullFunction); + }, 'Iterate over string set with forEach'); + } + + function testForEachWithLargeKeys() { + var bigSet = new goog.structs.Set; + var bigStringSet = new goog.structs.StringSet; + for (var i = 0; i < OPS_COUNT / 100; i++) { + bigSet.add(goog.string.repeat(String(i), 1000)); + bigStringSet.add(goog.string.repeat(String(i), 1000)); + } + + table.run(function() { + for (var i = 0; i < 100; i++) { + goog.structs.forEach(bigSet, goog.nullFunction); + } + }, 'Iterate over set of large strings with forEach'); + + table.run(function() { + for (var i = 0; i < 100; i++) { + goog.structs.forEach(bigStringSet, goog.nullFunction); + } + }, 'Iterate over string set of large strings with forEach'); + } + + function testAddRemove() { + table.run(function() { + var s = new goog.structs.Set(); + for (var i = 0; i < OPS_COUNT / 2; i++) { + s.add(i); + } + for (var i = 0; i < OPS_COUNT / 2; i++) { + s.remove(i); + } + }, 'Add then remove elements from set'); + + table.run(function() { + var s = new goog.structs.StringSet(); + for (var i = 0; i < OPS_COUNT / 2; i++) { + s.add(i); + } + for (var i = 0; i < OPS_COUNT / 2; i++) { + s.remove(i); + } + }, 'Add then remove elements from string set'); + } + + function testContains() { + var bigSet = new goog.structs.Set; + var bigStringSet = new goog.structs.StringSet; + var arr = []; + for (var i = 0; i < OPS_COUNT; i++) { + bigSet.add(i); + bigStringSet.add(i); + arr.push(i); + } + + table.run(function() { + for (var i = 0; i < OPS_COUNT; i++) { + bigSet.contains(i); + } + }, 'Membership check for each element of set'); + + table.run(function() { + for (var i = 0; i < OPS_COUNT; i++) { + bigStringSet.contains(i); + } + }, 'Membership check for each element of string set with contains'); + + table.run(function() { + bigStringSet.containsArray(arr); + }, 'Membership check for each element of string set with containsArray'); + + stubs.set(goog.structs.StringSet.prototype, 'encode', + goog.functions.identity); + stubs.set(goog.structs.StringSet.prototype, 'decode', + goog.functions.identity); + + table.run(function() { + for (var i = 0; i < OPS_COUNT; i++) { + bigStringSet.contains(i); + } + }, 'Membership check for each element of string set without escaping'); + } + + function testEquals() { + table.run(function() { + var s1 = new goog.structs.Set(); + var s2 = new goog.structs.Set(); + for (var i = 0; i < OPS_COUNT / 4; i++) { + s1.add(i); + s2.add(i); + } + s1.equals(s2); + }, 'Create then compare two sets'); + + table.run(function() { + var s1 = new goog.structs.StringSet(); + var s2 = new goog.structs.StringSet(); + for (var i = 0; i < OPS_COUNT / 4; i++) { + s1.add(i); + s2.add(i); + } + s1.equals(s2); + }, 'Create then compare two string sets'); + } + </script> +</body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/structs/set_test.html b/contexts/data/lib/closure-library/closure/goog/structs/set_test.html new file mode 100644 index 0000000..aa3f587 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/set_test.html @@ -0,0 +1,551 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright 2006 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> +<head> +<meta http-equiv="X-UA-Compatible" content="IE=edge"> +<title>Closure Unit Tests - goog.structs.Set</title> +<script src="../base.js"></script> +<script> + goog.require('goog.iter'); + goog.require('goog.structs'); + goog.require('goog.structs.Set'); + goog.require('goog.testing.jsunit'); +</script> +</head> +<body> +<script> + +var Set = goog.structs.Set; + +function stringifySet(s) { + return goog.structs.getValues(s).join(''); +} + +function testGetCount() { + var s = new Set; + var a = new String('a'); s.add(a); + var b = new String('b'); s.add(b); + var c = new String('c'); s.add(c); + assertEquals('count, should be 3', s.getCount(), 3); + var d = new String('d'); s.add(d); + assertEquals('count, should be 4', s.getCount(), 4); + s.remove(d); + assertEquals('count, should be 3', s.getCount(), 3); + + s = new Set; + s.add('a'); + s.add('b'); + s.add('c'); + assertEquals('count, should be 3', s.getCount(), 3); + s.add('d'); + assertEquals('count, should be 4', s.getCount(), 4); + s.remove('d'); + assertEquals('count, should be 3', s.getCount(), 3); +} + +function testGetValues() { + var s = new Set; + var a = new String('a'); s.add(a); + var b = new String('b'); s.add(b); + var c = new String('c'); s.add(c); + var d = new String('d'); s.add(d); + assertEquals(s.getValues().join(''), 'abcd'); + + var s = new Set; + s.add('a'); + s.add('b'); + s.add('c'); + s.add('d'); + assertEquals(s.getValues().join(''), 'abcd'); +} + +function testContains() { + var s = new Set; + var a = new String('a'); s.add(a); + var b = new String('b'); s.add(b); + var c = new String('c'); s.add(c); + var d = new String('d'); s.add(d); + var e = new String('e');; + + assertTrue("contains, Should contain 'a'", s.contains(a)); + assertFalse("contains, Should not contain 'e'", s.contains(e)); + + s = new Set; + s.add('a'); + s.add('b'); + s.add('c'); + s.add('d'); + + assertTrue("contains, Should contain 'a'", s.contains('a')); + assertFalse("contains, Should not contain 'e'", s.contains('e')); +} + +function testContainsFunctionValue() { + var s = new Set; + + var fn1 = function() {}; + + assertFalse(s.contains(fn1)); + s.add(fn1); + assertTrue(s.contains(fn1)); + + var fn2 = function() {}; + + assertFalse(s.contains(fn2)); + s.add(fn2); + assertTrue(s.contains(fn2)); + + assertEquals(s.getCount(), 2); +} + +function testContainsAll() { + var set = new Set([1, 2, 3]); + + assertTrue("{1, 2, 3} contains []", set.containsAll([])); + assertTrue("{1, 2, 3} contains [1]", set.containsAll([1])); + assertTrue("{1, 2, 3} contains [1, 1]", set.containsAll([1, 1])); + assertTrue("{1, 2, 3} contains [3, 2, 1]", set.containsAll([3, 2, 1])); + assertFalse("{1, 2, 3} doesn't contain [4]", set.containsAll([4])); + assertFalse("{1, 2, 3} doesn't contain [1, 4]", set.containsAll([1, 4])); + + assertTrue("{1, 2, 3} contains {a: 1}", set.containsAll({a: 1})); + assertFalse("{1, 2, 3} doesn't contain {a: 4}", set.containsAll({a: 4})); + + assertTrue("{1, 2, 3} contains {1}", set.containsAll(new Set([1]))); + assertFalse("{1, 2, 3} doesn't contain {4}", set.containsAll(new Set([4]))); +} + +function testIntersection() { + var emptySet = new Set; + + assertTrue('intersection of empty set and [] should be empty', + emptySet.intersection([]).isEmpty()); + assertIntersection('intersection of 2 empty sets should be empty', + emptySet, new Set(), new Set()); + + var abcdSet = new Set(); + abcdSet.add('a'); + abcdSet.add('b'); + abcdSet.add('c'); + abcdSet.add('d'); + + assertTrue('intersection of populated set and [] should be empty', + abcdSet.intersection([]).isEmpty()); + assertIntersection('intersection of 2 empty sets should be empty', + abcdSet, new Set(), new Set()); + + var bcSet = new Set(['b', 'c']); + assertIntersection('intersection of [a,b,c,d] and [b,c]', + abcdSet, bcSet, bcSet); + + var bceSet = new Set(['b', 'c', 'e']); + assertIntersection('intersection of [a,b,c,d] and [b,c,e]', + abcdSet, bceSet, bcSet); +} + +/** + * Helper function to assert intersection is commutative. + */ +function assertIntersection(msg, set1, set2, expectedIntersection) { + assertTrue(msg + ': set1->set2', + set1.intersection(set2).equals(expectedIntersection)); + assertTrue(msg + ': set2->set1', + set2.intersection(set1).equals(expectedIntersection)); +} + +function testRemoveAll() { + assertRemoveAll('removeAll of empty set from empty set', [], [], []); + assertRemoveAll('removeAll of empty set from populated set', + ['a', 'b', 'c', 'd'], [], ['a', 'b', 'c', 'd']); + assertRemoveAll('removeAll of [a,d] from [a,b,c,d]', + ['a', 'b', 'c', 'd'], ['a', 'd'], ['b', 'c']); + assertRemoveAll('removeAll of [b,c] from [a,b,c,d]', + ['a', 'b', 'c', 'd'], ['b', 'c'], ['a', 'd']); + assertRemoveAll('removeAll of [b,c,e] from [a,b,c,d]', + ['a', 'b', 'c', 'd'], ['b', 'c', 'e'], ['a', 'd']); + assertRemoveAll('removeAll of [a,b,c,d] from [a,d]', + ['a', 'd'], ['a', 'b', 'c', 'd'], []); + assertRemoveAll('removeAll of [a,b,c,d] from [b,c]', + ['b', 'c'], ['a', 'b', 'c', 'd'], []); + assertRemoveAll('removeAll of [a,b,c,d] from [b,c,e]', + ['b', 'c', 'e'], ['a', 'b', 'c', 'd'], ['e']); +} + +/** + * Helper function to test removeAll. + */ +function assertRemoveAll(msg, elements1, elements2, expectedResult) { + var set1 = new Set(elements1); + var set2 = new Set(elements2); + set1.removeAll(set2); + + assertTrue(msg + ': set1 count increased after removeAll', + elements1.length >= set1.getCount()); + assertEquals(msg + ': set2 count changed after removeAll', + elements2.length, set2.getCount()); + assertTrue(msg + ': wrong set1 after removeAll', set1.equals(expectedResult)); + assertIntersection(msg + ': non-empty intersection after removeAll', + set1, set2, []); +} + +function testAdd() { + var s = new Set; + var a = new String('a'); + var b = new String('b'); + s.add(a); + assertTrue(s.contains(a)); + s.add(b) + assertTrue(s.contains(b)); + + s = new Set; + s.add('a') + assertTrue(s.contains('a')); + s.add('b') + assertTrue(s.contains('b')); + s.add(null); + assertTrue('contains null', s.contains(null)); + assertFalse('does not contain "null"', s.contains('null')); +} + + +function testClear() { + var s = new Set; + var a = new String('a'); s.add(a); + var b = new String('b'); s.add(b); + var c = new String('c'); s.add(c); + var d = new String('d'); s.add(d); + s.clear(); + assertTrue('cleared so it should be empty', s.isEmpty()); + assertTrue("cleared so it should not contain 'a' key", !s.contains(a)); + + s = new Set; + s.add('a'); + s.add('b'); + s.add('c'); + s.add('d'); + s.clear(); + assertTrue('cleared so it should be empty', s.isEmpty()); + assertTrue("cleared so it should not contain 'a' key", !s.contains('a')); +} + + +function testAddAll() { + var s = new Set; + var a = new String('a'); + var b = new String('b'); + var c = new String('c'); + var d = new String('d'); + s.addAll([a, b, c, d]); + assertTrue('addAll so it should not be empty', !s.isEmpty()); + assertTrue("addAll so it should contain 'c' key", s.contains(c)); + + var s2 = new Set; + s2.addAll(s); + assertTrue('addAll so it should not be empty', !s2.isEmpty()); + assertTrue("addAll so it should contain 'c' key", s2.contains(c)); + + + s = new Set; + s.addAll(['a', 'b', 'c', 'd']); + assertTrue('addAll so it should not be empty', !s.isEmpty()); + assertTrue("addAll so it should contain 'c' key", s.contains('c')); + + s2 = new Set; + s2.addAll(s); + assertTrue('addAll so it should not be empty', !s2.isEmpty()); + assertTrue("addAll so it should contain 'c' key", s2.contains('c')); +} + + +function testConstructor() { + var s = new Set; + var a = new String('a'); s.add(a); + var b = new String('b'); s.add(b); + var c = new String('c'); s.add(c); + var d = new String('d'); s.add(d); + var s2 = new Set(s); + assertFalse('constr with Set so it should not be empty', s2.isEmpty()); + assertTrue('constr with Set so it should contain c', s2.contains(c)); + + s = new Set; + s.add('a'); + s.add('b'); + s.add('c'); + s.add('d'); + s2 = new Set(s); + assertFalse('constr with Set so it should not be empty', s2.isEmpty()); + assertTrue('constr with Set so it should contain c', s2.contains('c')); +} + + +function testClone() { + var s = new Set; + var a = new String('a'); s.add(a); + var b = new String('b'); s.add(b); + var c = new String('c'); s.add(c); + var d = new String('d'); s.add(d); + + var s2 = s.clone(); + assertFalse('clone so it should not be empty', s2.isEmpty()); + assertTrue("clone so it should contain 'c' key", s2.contains(c)); + + var s = new Set; + s.add('a'); + s.add('b'); + s.add('c'); + s.add('d'); + + s2 = s.clone(); + assertFalse('clone so it should not be empty', s2.isEmpty()); + assertTrue("clone so it should contain 'c' key", s2.contains('c')); +} + + +/** + * Helper method for testEquals(). + * @param {Object} a First element to use in the tests. + * @param {Object} b Second element to use in the tests. + * @param {Object} c Third element to use in the tests. + * @param {Object} d Fourth element to use in the tests. + */ +function helperForTestEquals(a, b, c, d) { + var s = new Set([a, b, c]); + + assertTrue("set == itself", s.equals(s)); + assertTrue("set == same set", s.equals(new Set([a, b, c]))); + assertTrue("set == its clone", s.equals(s.clone())); + assertTrue("set == array of same elements", s.equals([a, b, c])); + assertTrue("set == array of same elements in different order", + s.equals([c, b, a])); + + assertFalse("set != empty set", s.equals(new Set)); + assertFalse("set != its subset", s.equals(new Set([a, c]))); + assertFalse("set != its superset", + s.equals(new Set([a, b, c, d]))); + assertFalse("set != different set", + s.equals(new Set([b, c, d]))); + assertFalse("set != its subset as array", s.equals([a, c])); + assertFalse("set != its superset as array", s.equals([a, b, c, d])); + assertFalse("set != different set as array", s.equals([b, c, d])); + assertFalse("set != [a, b, c, c]", s.equals([a, b, c, c])); + assertFalse("set != [a, b, b]", s.equals([a, b, b])); + assertFalse("set != [a, a]", s.equals([a, a])); +} + + +function testEquals() { + helperForTestEquals(1, 2, 3, 4); + helperForTestEquals('a', 'b', 'c', 'd'); + helperForTestEquals(new String('a'), new String('b'), + new String('c'), new String('d')); +} + + +/** + * Helper method for testIsSubsetOf(). + * @param {Object} a First element to use in the tests. + * @param {Object} b Second element to use in the tests. + * @param {Object} c Third element to use in the tests. + * @param {Object} d Fourth element to use in the tests. + */ +function helperForTestIsSubsetOf(a, b, c, d) { + var s = new Set([a, b, c]); + + assertTrue("set <= itself", s.isSubsetOf(s)); + assertTrue("set <= same set", + s.isSubsetOf(new Set([a, b, c]))); + assertTrue("set <= its clone", s.isSubsetOf(s.clone())); + assertTrue("set <= array of same elements", s.isSubsetOf([a, b, c])); + assertTrue("set <= array of same elements in different order", + s.equals([c, b, a])); + + assertTrue("set <= Set([a, b, c, d])", + s.isSubsetOf(new Set([a, b, c, d]))); + assertTrue("set <= [a, b, c, d]", s.isSubsetOf([a, b, c, d])); + assertTrue("set <= [a, b, c, c]", s.isSubsetOf([a, b, c, c])); + + assertFalse("set !<= Set([a, b])", + s.isSubsetOf(new Set([a, b]))); + assertFalse("set !<= [a, b]", s.isSubsetOf([a, b])); + assertFalse("set !<= Set([c, d])", + s.isSubsetOf(new Set([c, d]))); + assertFalse("set !<= [c, d]", s.isSubsetOf([c, d])); + assertFalse("set !<= Set([a, c, d])", + s.isSubsetOf(new Set([a, c, d]))); + assertFalse("set !<= [a, c, d]", s.isSubsetOf([a, c, d])); + assertFalse("set !<= [a, a, b]", s.isSubsetOf([a, a, b])); + assertFalse("set !<= [a, a, b, b]", s.isSubsetOf([a, a, b, b])); +} + + +function testIsSubsetOf() { + helperForTestIsSubsetOf(1, 2, 3, 4); + helperForTestIsSubsetOf('a', 'b', 'c', 'd'); + helperForTestIsSubsetOf(new String('a'), new String('b'), + new String('c'), new String('d')); +} + + +function testForEach() { + var s = new Set; + var a = new String('a'); s.add(a); + var b = new String('b'); s.add(b); + var c = new String('c'); s.add(c); + var d = new String('d'); s.add(d); + var str = ''; + goog.structs.forEach(s, function(val, key, set) { + assertUndefined(key); + assertEquals(s, set); + str += val; + }); + assertEquals(str, 'abcd'); + + s = new Set; + s.add('a'); + s.add('b'); + s.add('c'); + s.add('d'); + str = ''; + goog.structs.forEach(s, function(val, key, set) { + assertUndefined(key); + assertEquals(s, set); + str += val; + }); + assertEquals(str, 'abcd'); +} + + +function testFilter() { + var s = new Set; + var a = new Number(0); s.add(a); + var b = new Number(1); s.add(b); + var c = new Number(2); s.add(c); + var d = new Number(3); s.add(d); + + var s2 = goog.structs.filter(s, function (val, key, set) { + assertUndefined(key); + assertEquals(s, set); + return val > 1; + }); + assertEquals(stringifySet(s2), '23'); + + s = new Set; + s.add(0); + s.add(1); + s.add(2); + s.add(3); + + s2 = goog.structs.filter(s, function (val, key, set) { + assertUndefined(key); + assertEquals(s, set); + return val > 1; + }); + assertEquals(stringifySet(s2), '23'); +} + + +function testSome() { + var s = new Set; + var a = new Number(0); s.add(a); + var b = new Number(1); s.add(b); + var c = new Number(2); s.add(c); + var d = new Number(3); s.add(d); + + var b = goog.structs.some(s, function (val, key, s2) { + assertUndefined(key); + assertEquals(s, s2); + return val > 1; + }); + assertTrue(b); + var b = goog.structs.some(s, function (val, key, s2) { + assertUndefined(key); + assertEquals(s, s2); + return val > 100; + }); + assertFalse(b); + + s = new Set; + s.add(0); + s.add(1); + s.add(2); + s.add(3); + + b = goog.structs.some(s, function (val, key, s2) { + assertUndefined(key); + assertEquals(s, s2); + return val > 1; + }); + assertTrue(b); + b = goog.structs.some(s, function (val, key, s2) { + assertUndefined(key); + assertEquals(s, s2); + return val > 100; + }); + assertFalse(b); +} + + +function testEvery() { + var s = new Set; + var a = new Number(0); s.add(a); + var b = new Number(1); s.add(b); + var c = new Number(2); s.add(c); + var d = new Number(3); s.add(d); + + var b = goog.structs.every(s, function (val, key, s2) { + assertUndefined(key); + assertEquals(s, s2); + return val >= 0; + }); + assertTrue(b); + b = goog.structs.every(s, function (val, key, s2) { + assertUndefined(key); + assertEquals(s, s2); + return val > 1; + }); + assertFalse(b); + + s = new Set; + s.add(0); + s.add(1); + s.add(2); + s.add(3); + + b = goog.structs.every(s, function (val, key, s2) { + assertUndefined(key); + assertEquals(s, s2); + return val >= 0; + }); + assertTrue(b); + b = goog.structs.every(s, function (val, key, s2) { + assertUndefined(key); + assertEquals(s, s2); + return val > 1; + }); + assertFalse(b); +} + +function testIterator() { + var s = new Set; + s.add(0); + s.add(1); + s.add(2); + s.add(3); + s.add(4); + + assertEquals('01234', goog.iter.join(s, '')); + + s.remove(1); + s.remove(3); + + assertEquals('024', goog.iter.join(s, '')); +} + +</script> +</body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/structs/simplepool.js b/contexts/data/lib/closure-library/closure/goog/structs/simplepool.js new file mode 100644 index 0000000..3c13e0a --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/simplepool.js @@ -0,0 +1,205 @@ +// Copyright 2007 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Datastructure: Pool. + * + * + * A generic class for handling pools of objects that is more efficient than + * goog.structs.Pool because it doesn't maintain a list of objects that are in + * use. See constructor comment. + */ + + +goog.provide('goog.structs.SimplePool'); + +goog.require('goog.Disposable'); + + + +/** + * A generic pool class. Simpler and more efficient than goog.structs.Pool + * because it doesn't maintain a list of objects that are in use. This class + * has constant overhead and doesn't create any additional objects as part of + * the pool management after construction time. + * + * IMPORTANT: If the objects being pooled are arrays or maps that can have + * unlimited number of properties, they need to be cleaned before being + * returned to the pool. + * + * Also note that {@see goog.object.clean} actually allocates an array to clean + * the object passed to it, so simply using this function would defy the + * purpose of using the pool. + * + * @param {number} initialCount Initial number of objects to populate the + * free pool at construction time. + * @param {number} maxCount Maximum number of objects to keep in the free pool. + * @constructor + * @extends {goog.Disposable} + */ +goog.structs.SimplePool = function(initialCount, maxCount) { + goog.Disposable.call(this); + + /** + * Maximum number of objects allowed + * @type {number} + * @private + */ + this.maxCount_ = maxCount; + + /** + * Queue used to store objects that are currently in the pool and available + * to be used. + * @type {Array} + * @private + */ + this.freeQueue_ = []; + + this.createInitial_(initialCount); +}; +goog.inherits(goog.structs.SimplePool, goog.Disposable); + + +/** + * Function for overriding createObject. The avoids a common case requiring + * subclassing this class. + * @type {Function} + * @private + */ +goog.structs.SimplePool.prototype.createObjectFn_ = null; + + +/** + * Function for overriding disposeObject. The avoids a common case requiring + * subclassing this class. + * @type {Function} + * @private + */ +goog.structs.SimplePool.prototype.disposeObjectFn_ = null; + + +/** + * Sets the {@code createObject} function which is used for creating a new + * object in the pool. + * @param {Function} createObjectFn Create object function which returns the + * newly createrd object. + */ +goog.structs.SimplePool.prototype.setCreateObjectFn = function(createObjectFn) { + this.createObjectFn_ = createObjectFn; +}; + + +/** + * Sets the {@code disposeObject} function which is used for disposing of an + * object in the pool. + * @param {Function} disposeObjectFn Dispose object function which takes the + * object to dispose as a parameter. + */ +goog.structs.SimplePool.prototype.setDisposeObjectFn = function( + disposeObjectFn) { + this.disposeObjectFn_ = disposeObjectFn; +}; + + +/** + * Gets an unused object from the the pool, if there is one available, + * otherwise creates a new one. + * @return {*} An object from the pool or a new one if necessary. + */ +goog.structs.SimplePool.prototype.getObject = function() { + if (this.freeQueue_.length) { + return this.freeQueue_.pop(); + } + return this.createObject(); +}; + + +/** + * Returns an object to the pool so that it can be reused. If the pool is + * already full, the object is disposed instead. + * @param {*} obj The object to release. + */ +goog.structs.SimplePool.prototype.releaseObject = function(obj) { + if (this.freeQueue_.length < this.maxCount_) { + this.freeQueue_.push(obj); + } else { + this.disposeObject(obj); + } +}; + + +/** + * Populates the pool with initialCount objects. + * @param {number} initialCount The number of objects to add to the pool. + * @private + */ +goog.structs.SimplePool.prototype.createInitial_ = function(initialCount) { + if (initialCount > this.maxCount_) { + throw Error('[goog.structs.SimplePool] Initial cannot be greater than max'); + } + for (var i = 0; i < initialCount; i++) { + this.freeQueue_.push(this.createObject()); + } +}; + + +/** + * Should be overriden by sub-classes to return an instance of the object type + * that is expected in the pool. + * @return {*} The created object. + */ +goog.structs.SimplePool.prototype.createObject = function() { + if (this.createObjectFn_) { + return this.createObjectFn_(); + } else { + return {}; + } +}; + + +/** + * Should be overriden to dispose of an object. Default implementation is to + * remove all of the object's members, which should render it useless. Calls the + * object's dispose method, if available. + * @param {*} obj The object to dispose. + */ +goog.structs.SimplePool.prototype.disposeObject = function(obj) { + if (this.disposeObjectFn_) { + this.disposeObjectFn_(obj); + } else if (goog.isObject(obj)) { + if (goog.isFunction(obj.dispose)) { + obj.dispose(); + } else { + for (var i in obj) { + delete obj[i]; + } + } + } +}; + + +/** + * Disposes of the pool and all objects currently held in the pool. + * @override + * @protected + */ +goog.structs.SimplePool.prototype.disposeInternal = function() { + goog.structs.SimplePool.superClass_.disposeInternal.call(this); + // Call disposeObject on each object held by the pool. + var freeQueue = this.freeQueue_; + while (freeQueue.length) { + this.disposeObject(freeQueue.pop()); + } + delete this.freeQueue_; +}; diff --git a/contexts/data/lib/closure-library/closure/goog/structs/stringset.js b/contexts/data/lib/closure-library/closure/goog/structs/stringset.js new file mode 100644 index 0000000..c95ad8c --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/stringset.js @@ -0,0 +1,404 @@ +// Copyright 2009 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Data structure for set of strings. + * + * + * This class implements a set data structure for strings. Adding and removing + * is O(1). It doesn't contain any bloat from {@link goog.structs.Set}, i.e. + * it isn't optimized for IE6 garbage collector (see the description of + * {@link goog.structs.Map#keys_} for details), and it distinguishes its + * elements by their string value not by hash code. + */ + +goog.provide('goog.structs.StringSet'); + +goog.require('goog.iter'); + + + +/** + * Creates a set of strings. + * @param {!Array=} opt_elements Elements to add to the set. The non-string + * items will be converted to strings, so 15 and '15' will mean the same. + * @constructor + */ +goog.structs.StringSet = function(opt_elements) { + /** + * An object storing the escaped elements of the set in its keys. + * @type {!Object} + * @private + */ + this.elements_ = {}; + + if (opt_elements) { + for (var i = 0; i < opt_elements.length; i++) { + this.elements_[this.encode(opt_elements[i])] = null; + } + } +}; + + +/** + * Empty object. Referring to it is faster than creating a new empty object in + * {@link #encode}. + * @type {Object} + * @private + */ +goog.structs.StringSet.EMPTY_OBJECT_ = {}; + + +/** + * The '__proto__' and the '__count__' keys aren't enumerable in Firefox, and + * 'toString', 'valueOf', 'constructor', etc. aren't enumerable in IE so they + * have to be escaped before they are added to the internal object. + * NOTE: When a new set is created, 50-80% of the CPU time is spent in encode. + * @param {*} element The element to escape. + * @return {*} The escaped element or the element itself if it doesn't have to + * be escaped. + * @protected + */ +goog.structs.StringSet.prototype.encode = function(element) { + return element in goog.structs.StringSet.EMPTY_OBJECT_ || + String(element).charCodeAt(0) == 32 ? ' ' + element : element; +}; + + +/** + * Inverse function of {@link #encode}. + * NOTE: forEach would be 30% faster in FF if the compiler inlined decode. + * @param {string} key The escaped element used as the key of the internal + * object. + * @return {string} The unescaped element. + * @protected + */ +goog.structs.StringSet.prototype.decode = function(key) { + return key.charCodeAt(0) == 32 ? key.substr(1) : key; +}; + + +/** + * Adds a single element to the set. + * @param {*} element The element to add. It will be converted to string. + */ +goog.structs.StringSet.prototype.add = function(element) { + this.elements_[this.encode(element)] = null; +}; + + +/** + * Adds a the elements of an array to this set. + * @param {!Array} arr The array to add the elements of. + */ +goog.structs.StringSet.prototype.addArray = function(arr) { + for (var i = 0; i < arr.length; i++) { + this.elements_[this.encode(arr[i])] = null; + } +}; + + +/** + * Adds the elements which are in {@code set1} but not in {@code set2} to this + * set. + * @param {!goog.structs.StringSet} set1 First set. + * @param {!goog.structs.StringSet} set2 Second set. + * @private + */ +goog.structs.StringSet.prototype.addDifference_ = function(set1, set2) { + for (var key in set1.elements_) { + if (set1.elements_.hasOwnProperty(key) && + !set2.elements_.hasOwnProperty(key)) { + this.elements_[key] = null; + } + } +}; + + +/** + * Adds a the elements of a set to this set. + * @param {!goog.structs.StringSet} stringSet The set to add the elements of. + */ +goog.structs.StringSet.prototype.addSet = function(stringSet) { + for (var key in stringSet.elements_) { + if (stringSet.elements_.hasOwnProperty(key)) { + this.elements_[key] = null; + } + } +}; + + +/** + * Removes all elements of the set. + */ +goog.structs.StringSet.prototype.clear = function() { + this.elements_ = {}; +}; + + +/** + * @return {!goog.structs.StringSet} Clone of the set. + */ +goog.structs.StringSet.prototype.clone = function() { + var ret = new goog.structs.StringSet; + ret.addSet(this); + return ret; +}; + + +/** + * Tells if the set contains the given element. + * @param {*} element The element to check. + * @return {boolean} Whether it is in the set. + */ +goog.structs.StringSet.prototype.contains = function(element) { + return this.elements_.hasOwnProperty(this.encode(element)); +}; + + +/** + * Tells if the set contains all elements of the array. + * @param {!Array} arr The elements to check. + * @return {boolean} Whether they are in the set. + */ +goog.structs.StringSet.prototype.containsArray = function(arr) { + for (var i = 0; i < arr.length; i++) { + if (!this.elements_.hasOwnProperty(this.encode(arr[i]))) { + return false; + } + } + return true; +}; + + +/** + * Tells if this set has the same elements as the given set. + * @param {!goog.structs.StringSet} stringSet The other set. + * @return {boolean} Whether they have the same elements. + */ +goog.structs.StringSet.prototype.equals = function(stringSet) { + return this.isSubsetOf(stringSet) && stringSet.isSubsetOf(this); +}; + + +/** + * Calls a function for each element in the set. + * @param {function(string, undefined, !goog.structs.StringSet)} f The function + * to call for every element. It takes the element, undefined (because sets + * have no notion of keys), and the set. + * @param {Object=} opt_obj The object to be used as the value of 'this' + * within {@code f}. + */ +goog.structs.StringSet.prototype.forEach = function(f, opt_obj) { + for (var key in this.elements_) { + if (this.elements_.hasOwnProperty(key)) { + f.call(opt_obj, this.decode(key), undefined, this); + } + } +}; + + +/** + * Counts the number of elements in the set in linear time. + * NOTE: getCount is always called at most once per set instance in google3. + * If this usage pattern won't change, the linear getCount implementation is + * better, because + * <li>populating a set and getting the number of elements in it takes the same + * amount of time as keeping a count_ member up to date and getting its value; + * <li>if getCount is not called, adding and removing elements have no overhead. + * @return {number} The number of elements in the set. + */ +goog.structs.StringSet.prototype.getCount = function() { + var count = 0; + for (var key in this.elements_) { + if (this.elements_.hasOwnProperty(key)) { + count++; + } + } + return count; +}; + + +/** + * Calculates the difference of two sets. + * @param {!goog.structs.StringSet} stringSet The set to subtract from this set. + * @return {!goog.structs.StringSet} {@code this} minus {@code stringSet}. + */ +goog.structs.StringSet.prototype.getDifference = function(stringSet) { + var ret = new goog.structs.StringSet; + ret.addDifference_(this, stringSet); + return ret; +}; + + +/** + * Calculates the intersection of this set with another set. + * @param {!goog.structs.StringSet} stringSet The set to take the intersection + * with. + * @return {!goog.structs.StringSet} A new set with the common elements. + */ +goog.structs.StringSet.prototype.getIntersection = function(stringSet) { + var ret = new goog.structs.StringSet; + for (var key in this.elements_) { + if (stringSet.elements_.hasOwnProperty(key) && + this.elements_.hasOwnProperty(key)) { + ret.elements_[key] = null; + } + } + return ret; +}; + + +/** + * Calculates the symmetric difference of two sets. + * @param {!goog.structs.StringSet} stringSet The other set. + * @return {!goog.structs.StringSet} A new set with the elements in exactly one + * of {@code this} and {@code stringSet}. + */ +goog.structs.StringSet.prototype.getSymmetricDifference = function(stringSet) { + var ret = new goog.structs.StringSet; + ret.addDifference_(this, stringSet); + ret.addDifference_(stringSet, this); + return ret; +}; + + +/** + * Calculates the union of this set and another set. + * @param {!goog.structs.StringSet} stringSet The set to take the union with. + * @return {!goog.structs.StringSet} A new set with the union of elements. + */ +goog.structs.StringSet.prototype.getUnion = function(stringSet) { + var ret = this.clone(); + ret.addSet(stringSet); + return ret; +}; + + +/** + * @return {!Array.<string>} The elements of the set. + */ +goog.structs.StringSet.prototype.getValues = function() { + var ret = []; + for (var key in this.elements_) { + if (this.elements_.hasOwnProperty(key)) { + ret.push(this.decode(key)); + } + } + return ret; +}; + + +/** + * Tells if this set and the given set are disjoint. + * @param {!goog.structs.StringSet} stringSet The other set. + * @return {boolean} True iff they don't have common elements. + */ +goog.structs.StringSet.prototype.isDisjoint = function(stringSet) { + for (var key in this.elements_) { + if (stringSet.elements_.hasOwnProperty(key) && + this.elements_.hasOwnProperty(key)) { + return false; + } + } + return true; +}; + + +/** + * @return {boolean} Whether the set is empty. + */ +goog.structs.StringSet.prototype.isEmpty = function() { + for (var key in this.elements_) { + if (this.elements_.hasOwnProperty(key)) { + return false; + } + } + return true; +}; + + +/** + * Tells if this set is the subset of the given set. + * @param {!goog.structs.StringSet} stringSet The other set. + * @return {boolean} Whether this set if the subset of that. + */ +goog.structs.StringSet.prototype.isSubsetOf = function(stringSet) { + for (var key in this.elements_) { + if (!stringSet.elements_.hasOwnProperty(key) && + this.elements_.hasOwnProperty(key)) { + return false; + } + } + return true; +}; + + +/** + * Tells if this set is the superset of the given set. + * @param {!goog.structs.StringSet} stringSet The other set. + * @return {boolean} Whether this set if the superset of that. + */ +goog.structs.StringSet.prototype.isSupersetOf = function(stringSet) { + return this.isSubsetOf.call(stringSet, this); +}; + + +/** + * Removes a single element from the set. + * @param {*} element The element to remove. + * @return {boolean} Whether the element was in the set. + */ +goog.structs.StringSet.prototype.remove = function(element) { + var key = this.encode(element); + if (this.elements_.hasOwnProperty(key)) { + delete this.elements_[key]; + return true; + } + return false; +}; + + +/** + * Removes all elements of the given array from this set. + * @param {!Array} arr The elements to remove. + */ +goog.structs.StringSet.prototype.removeArray = function(arr) { + for (var i = 0; i < arr.length; i++) { + delete this.elements_[this.encode(arr[i])]; + } +}; + + +/** + * Removes all elements of the given set from this set. + * @param {!goog.structs.StringSet} stringSet The set of elements to remove. + */ +goog.structs.StringSet.prototype.removeSet = function(stringSet) { + for (var key in stringSet.elements_) { + delete this.elements_[key]; + } +}; + + +/** + * Returns an iterator that iterates over the elements in the set. + * NOTE: creating the iterator copies the whole set so use {@link #forEach} when + * possible. + * @param {boolean=} opt_keys Ignored for sets. + * @return {!goog.iter.Iterator} An iterator over the elements in the set. + */ +goog.structs.StringSet.prototype.__iterator__ = function(opt_keys) { + return goog.iter.toIterator(this.getValues()); +}; diff --git a/contexts/data/lib/closure-library/closure/goog/structs/stringset_test.html b/contexts/data/lib/closure-library/closure/goog/structs/stringset_test.html new file mode 100644 index 0000000..804e5eb --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/stringset_test.html @@ -0,0 +1,251 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright 2009 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> +<!-- +--> +<head> +<meta http-equiv="X-UA-Compatible" content="IE=edge"> +<title>Closure Unit Tests - goog.structs.StringSet</title> +<script src="../base.js"></script> +<script> + goog.require('goog.array'); + goog.require('goog.iter'); + goog.require('goog.structs.StringSet'); + goog.require('goog.testing.asserts'); + goog.require('goog.testing.jsunit'); +</script> +</head> +<body> +<script> + +// Test how overwritten object prototype affects StringSet. +Object.prototype.evil1 = null; +Object.prototype.evil2 = null; + +var TEST_VALUES = [ + '', ' ', ' ', 'true', 'null', 'undefined', '0', 'new', 'constructor', + 'prototype', '__proto__', 'set', 'hasOwnProperty', 'toString', 'valueOf', + 'evil1' +]; + +var TEST_VALUES_WITH_DUPLICATES = [ + '', '', ' ', ' ', 'true', true, 'null', null, 'undefined', undefined, '0', 0, + 'new', 'constructor', 'prototype', '__proto__', 'set', 'hasOwnProperty', + 'toString', 'valueOf', 'evil1' +]; + +function testConstructor() { + var empty = new goog.structs.StringSet; + assertSameElements('elements in empty set', [], empty.getValues()); + + var s = new goog.structs.StringSet(TEST_VALUES_WITH_DUPLICATES); + assertSameElements('duplicates are filtered out by their string value', + TEST_VALUES, s.getValues()); +} + +function testAdd() { + var s = new goog.structs.StringSet; + goog.array.forEach(TEST_VALUES_WITH_DUPLICATES, s.add, s); + assertSameElements(TEST_VALUES, s.getValues()); +} + +function testAddArray() { + var s = new goog.structs.StringSet; + s.addArray(TEST_VALUES_WITH_DUPLICATES); + assertSameElements('added elements from array', TEST_VALUES, s.getValues()); +} + +function testAddSet() { + var s = new goog.structs.StringSet; + s.addSet(new goog.structs.StringSet([1, 2])); + assertSameElements('empty set + {1, 2}', ['1', '2'], s.getValues()); + s.addSet(new goog.structs.StringSet([2, 3])); + assertSameElements('{1, 2} + {2, 3}', ['1', '2', '3'], s.getValues()); +} + +function testClear() { + var s = new goog.structs.StringSet([1, 2]); + s.clear(); + assertSameElements('cleared set', [], s.getValues()); +} + +function testClone() { + var s = new goog.structs.StringSet([1, 2]); + var c = s.clone(); + assertSameElements('elements in clone', ['1', '2'], c.getValues()); + s.add(3); + assertSameElements('changing the original set does not affect the clone', + ['1', '2'], c.getValues()); +} + +function testContains() { + var e = new goog.structs.StringSet; + goog.array.forEach(TEST_VALUES, function(element) { + assertFalse('empty set does not contain ' + element, e.contains(element)); + }); + + var s = new goog.structs.StringSet(TEST_VALUES); + goog.array.forEach(TEST_VALUES_WITH_DUPLICATES, function(element) { + assertTrue('s contains ' + element, s.contains(element)); + }); + assertFalse('s does not contain 42', s.contains(42)); + + Object.prototype[' a'] = 'a'; + Object.prototype[' a'] = 'a'; + assertFalse('empty set does not contain elements defined in Object.prototype', + new goog.structs.StringSet().contains(' a')); +} + +function testContainsArray() { + var s = new goog.structs.StringSet(TEST_VALUES); + assertTrue('set contains empty array', s.containsArray([])); + assertTrue('set contains all elements of itself with some duplication', + s.containsArray(TEST_VALUES_WITH_DUPLICATES)); + assertFalse('set does not contain 42', s.containsArray([42])); +} + +function testEquals() { + var s = new goog.structs.StringSet([1, 2]); + assertTrue('set equals to itself', s.equals(s)); + assertTrue('set equals to its clone', s.equals(s.clone())); + assertFalse('set does not equal to its subset', + s.equals(new goog.structs.StringSet([1]))); + assertFalse('set does not equal to its superset', + s.equals(new goog.structs.StringSet([1, 2, 3]))); +} + +function testForEach() { + var s = new goog.structs.StringSet(TEST_VALUES); + var values = []; + var context = {}; + s.forEach(function(value, key, stringSet) { + assertEquals('context of forEach callback', context, this); + values.push(value); + assertUndefined('key argument of forEach callback', key); + assertEquals('set argument of forEach callback', s, stringSet); + }, context); + assertSameElements('values passed to forEach callback', TEST_VALUES, values); +} + +function testGetCount() { + var empty = new goog.structs.StringSet; + assertEquals('count(empty set)', 0, empty.getCount()); + + var s = new goog.structs.StringSet(TEST_VALUES); + assertEquals('count(non-empty set)', TEST_VALUES.length, s.getCount()); +} + +function testGetDifference() { + var s1 = new goog.structs.StringSet([1, 2]); + var s2 = new goog.structs.StringSet([2, 3]); + assertSameElements('{1, 2} - {2, 3}', ['1'], + s1.getDifference(s2).getValues()); +} + +function testGetIntersection() { + var s1 = new goog.structs.StringSet([1, 2]); + var s2 = new goog.structs.StringSet([2, 3]); + assertSameElements('{1, 2} * {2, 3}', ['2'], + s1.getIntersection(s2).getValues()); +} + +function testGetSymmetricDifference() { + var s1 = new goog.structs.StringSet([1, 2]); + var s2 = new goog.structs.StringSet([2, 3]); + assertSameElements('{1, 2} sym.diff. {2, 3}', ['1', '3'], + s1.getSymmetricDifference(s2).getValues()); +} + +function testGetUnion() { + var s1 = new goog.structs.StringSet([1, 2]); + var s2 = new goog.structs.StringSet([2, 3]); + assertSameElements('{1, 2} + {2, 3}', ['1', '2', '3'], + s1.getUnion(s2).getValues()); +} + +function testIsDisjoint() { + var s = new goog.structs.StringSet; + var s12 = new goog.structs.StringSet([1, 2]); + var s23 = new goog.structs.StringSet([2, 3]); + var s34 = new goog.structs.StringSet([3, 4]); + + assertTrue('{} and {1, 2} are disjoint', s.isDisjoint(s12)); + assertTrue('{1, 2} and {3, 4} are disjoint', s12.isDisjoint(s34)); + assertFalse('{1, 2} and {2, 3} are not disjoint', s12.isDisjoint(s23)); +} + +function testIsEmpty() { + assertTrue('empty set', new goog.structs.StringSet().isEmpty()); + assertFalse('non-empty set', new goog.structs.StringSet(['']).isEmpty()); +} + +function testIsSubsetOf() { + var s1 = new goog.structs.StringSet([1]); + var s12 = new goog.structs.StringSet([1, 2]); + var s123 = new goog.structs.StringSet([1, 2, 3]); + var s23 = new goog.structs.StringSet([2, 3]); + + assertTrue('{1, 2} is subset of {1, 2}', s12.isSubsetOf(s12)); + assertTrue('{1, 2} is subset of {1, 2, 3}', s12.isSubsetOf(s123)); + assertFalse('{1, 2} is not subset of {1}', s12.isSubsetOf(s1)); + assertFalse('{1, 2} is not subset of {2, 3}', s12.isSubsetOf(s23)); +} + +function testIsSupersetOf() { + var s1 = new goog.structs.StringSet([1]); + var s12 = new goog.structs.StringSet([1, 2]); + var s123 = new goog.structs.StringSet([1, 2, 3]); + var s23 = new goog.structs.StringSet([2, 3]); + + assertTrue('{1, 2} is superset of {1}', s12.isSupersetOf(s1)); + assertTrue('{1, 2} is superset of {1, 2}', s12.isSupersetOf(s12)); + assertFalse('{1, 2} is not superset of {1, 2, 3}', s12.isSupersetOf(s123)); + assertFalse('{1, 2} is not superset of {2, 3}', s12.isSupersetOf(s23)); +} + +function testRemove() { + var n = new goog.structs.StringSet([1, 2]); + assertFalse('3 not removed from {1, 2}', n.remove(3)); + assertSameElements('set == {1, 2}', ['1', '2'], n.getValues()); + assertTrue('2 removed from {1, 2}', n.remove(2)); + assertSameElements('set == {1}', ['1'], n.getValues()); + assertTrue('"1" removed from {1}', n.remove('1')); + assertSameElements('set == {}', [], n.getValues()); + + var s = new goog.structs.StringSet(TEST_VALUES); + goog.array.forEach(TEST_VALUES, s.remove, s); + assertSameElements('all special values have been removed', [], s.getValues()); +} + +function testRemoveArray() { + var s = new goog.structs.StringSet(TEST_VALUES); + s.removeArray(TEST_VALUES.slice(0, TEST_VALUES.length - 2)); + assertSameElements('removed elements from array', + TEST_VALUES.slice(TEST_VALUES.length - 2), s.getValues()); +} + +function testRemoveSet() { + var s1 = new goog.structs.StringSet([1, 2]); + var s2 = new goog.structs.StringSet([2, 3]); + s1.removeSet(s2); + assertSameElements('{1, 2} - {2, 3}', ['1'], s1.getValues()); +} + +function testIterator() { + var s = new goog.structs.StringSet(TEST_VALUES_WITH_DUPLICATES); + var values = [] + goog.iter.forEach(s, function(value) { + values.push(value); + }); + assertSameElements('__iterator__ takes all elements once', + TEST_VALUES, values); +} + +</script> +</body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/structs/structs.js b/contexts/data/lib/closure-library/closure/goog/structs/structs.js new file mode 100644 index 0000000..ec39582 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/structs.js @@ -0,0 +1,342 @@ +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Generics method for collection-like classes and objects. + * + * @author arv@google.com (Erik Arvidsson) + * + * This file contains functions to work with collections. It supports using + * Map, Set, Array and Object and other classes that implement collection-like + * methods. + */ + + +goog.provide('goog.structs'); + +goog.require('goog.array'); +goog.require('goog.object'); + + +// We treat an object as a dictionary if it has getKeys or it is an object that +// isn't arrayLike. + + +/** + * Returns the number of values in the collection-like object. + * @param {Object} col The collection-like object. + * @return {number} The number of values in the collection-like object. + */ +goog.structs.getCount = function(col) { + if (typeof col.getCount == 'function') { + return col.getCount(); + } + if (goog.isArrayLike(col) || goog.isString(col)) { + return col.length; + } + return goog.object.getCount(col); +}; + + +/** + * Returns the values of the collection-like object. + * @param {Object} col The collection-like object. + * @return {!Array} The values in the collection-like object. + */ +goog.structs.getValues = function(col) { + if (typeof col.getValues == 'function') { + return col.getValues(); + } + if (goog.isString(col)) { + return col.split(''); + } + if (goog.isArrayLike(col)) { + var rv = []; + var l = col.length; + for (var i = 0; i < l; i++) { + rv.push(col[i]); + } + return rv; + } + return goog.object.getValues(col); +}; + + +/** + * Returns the keys of the collection. Some collections have no notion of + * keys/indexes and this function will return undefined in those cases. + * @param {Object} col The collection-like object. + * @return {!Array|undefined} The keys in the collection. + */ +goog.structs.getKeys = function(col) { + if (typeof col.getKeys == 'function') { + return col.getKeys(); + } + // if we have getValues but no getKeys we know this is a key-less collection + if (typeof col.getValues == 'function') { + return undefined; + } + if (goog.isArrayLike(col) || goog.isString(col)) { + var rv = []; + var l = col.length; + for (var i = 0; i < l; i++) { + rv.push(i); + } + return rv; + } + + return goog.object.getKeys(col); +}; + + +/** + * Whether the collection contains the given value. This is O(n) and uses + * equals (==) to test the existence. + * @param {Object} col The collection-like object. + * @param {*} val The value to check for. + * @return {boolean} True if the map contains the value. + */ +goog.structs.contains = function(col, val) { + if (typeof col.contains == 'function') { + return col.contains(val); + } + if (typeof col.containsValue == 'function') { + return col.containsValue(val); + } + if (goog.isArrayLike(col) || goog.isString(col)) { + return goog.array.contains(/** @type {Array} */ (col), val); + } + return goog.object.containsValue(col, val); +}; + + +/** + * Whether the collection is empty. + * @param {Object} col The collection-like object. + * @return {boolean} True if empty. + */ +goog.structs.isEmpty = function(col) { + if (typeof col.isEmpty == 'function') { + return col.isEmpty(); + } + + // We do not use goog.string.isEmpty because here we treat the string as + // collection and as such even whitespace matters + + if (goog.isArrayLike(col) || goog.isString(col)) { + return goog.array.isEmpty(/** @type {Array} */ (col)); + } + return goog.object.isEmpty(col); +}; + + +/** + * Removes all the elements from the collection. + * @param {Object} col The collection-like object. + */ +goog.structs.clear = function(col) { + // NOTE(arv): This should not contain strings because strings are immutable + if (typeof col.clear == 'function') { + col.clear(); + } else if (goog.isArrayLike(col)) { + goog.array.clear((/** @type {goog.array.ArrayLike} */ col)); + } else { + goog.object.clear(col); + } +}; + + +/** + * Calls a function for each value in a collection. The function takes + * three arguments; the value, the key and the collection. + * + * @param {Object} col The collection-like object. + * @param {Function} f The function to call for every value. This function takes + * 3 arguments (the value, the key or undefined if the collection has no + * notion of keys, and the collection) and the return value is irrelevant. + * @param {Object=} opt_obj The object to be used as the value of 'this' + * within {@code f}. + */ +goog.structs.forEach = function(col, f, opt_obj) { + if (typeof col.forEach == 'function') { + col.forEach(f, opt_obj); + } else if (goog.isArrayLike(col) || goog.isString(col)) { + goog.array.forEach(/** @type {Array} */ (col), f, opt_obj); + } else { + var keys = goog.structs.getKeys(col); + var values = goog.structs.getValues(col); + var l = values.length; + for (var i = 0; i < l; i++) { + f.call(opt_obj, values[i], keys && keys[i], col); + } + } +}; + + +/** + * Calls a function for every value in the collection. When a call returns true, + * adds the value to a new collection (Array is returned by default). + * + * @param {Object} col The collection-like object. + * @param {Function} f The function to call for every value. This function takes + * 3 arguments (the value, the key or undefined if the collection has no + * notion of keys, and the collection) and should return a Boolean. If the + * return value is true the value is added to the result collection. If it + * is false the value is not included. + * @param {Object=} opt_obj The object to be used as the value of 'this' + * within {@code f}. + * @return {!Object|!Array} A new collection where the passed values are + * present. If col is a key-less collection an array is returned. If col + * has keys and values a plain old JS object is returned. + */ +goog.structs.filter = function(col, f, opt_obj) { + if (typeof col.filter == 'function') { + return col.filter(f, opt_obj); + } + if (goog.isArrayLike(col) || goog.isString(col)) { + return goog.array.filter(/** @type {!Array} */ (col), f, opt_obj); + } + + var rv; + var keys = goog.structs.getKeys(col); + var values = goog.structs.getValues(col); + var l = values.length; + if (keys) { + rv = {}; + for (var i = 0; i < l; i++) { + if (f.call(opt_obj, values[i], keys[i], col)) { + rv[keys[i]] = values[i]; + } + } + } else { + // We should not use goog.array.filter here since we want to make sure that + // the index is undefined as well as make sure that col is passed to the + // function. + rv = []; + for (var i = 0; i < l; i++) { + if (f.call(opt_obj, values[i], undefined, col)) { + rv.push(values[i]); + } + } + } + return rv; +}; + + +/** + * Calls a function for every value in the collection and adds the result into a + * new collection (defaults to creating a new Array). + * + * @param {Object} col The collection-like object. + * @param {Function} f The function to call for every value. This function + * takes 3 arguments (the value, the key or undefined if the collection has + * no notion of keys, and the collection) and should return something. The + * result will be used as the value in the new collection. + * @param {Object=} opt_obj The object to be used as the value of 'this' + * within {@code f}. + * @return {!Object|!Array} A new collection with the new values. If col is a + * key-less collection an array is returned. If col has keys and values a + * plain old JS object is returned. + */ +goog.structs.map = function(col, f, opt_obj) { + if (typeof col.map == 'function') { + return col.map(f, opt_obj); + } + if (goog.isArrayLike(col) || goog.isString(col)) { + return goog.array.map(/** @type {!Array} */ (col), f, opt_obj); + } + + var rv; + var keys = goog.structs.getKeys(col); + var values = goog.structs.getValues(col); + var l = values.length; + if (keys) { + rv = {}; + for (var i = 0; i < l; i++) { + rv[keys[i]] = f.call(opt_obj, values[i], keys[i], col); + } + } else { + // We should not use goog.array.map here since we want to make sure that + // the index is undefined as well as make sure that col is passed to the + // function. + rv = []; + for (var i = 0; i < l; i++) { + rv[i] = f.call(opt_obj, values[i], undefined, col); + } + } + return rv; +}; + + +/** + * Calls f for each value in a collection. If any call returns true this returns + * true (without checking the rest). If all returns false this returns false. + * + * @param {Object|Array|string} col The collection-like object. + * @param {Function} f The function to call for every value. This function takes + * 3 arguments (the value, the key or undefined if the collection has no + * notion of keys, and the collection) and should return a Boolean. + * @param {Object=} opt_obj The object to be used as the value of 'this' + * within {@code f}. + * @return {boolean} True if any value passes the test. + */ +goog.structs.some = function(col, f, opt_obj) { + if (typeof col.some == 'function') { + return col.some(f, opt_obj); + } + if (goog.isArrayLike(col) || goog.isString(col)) { + return goog.array.some(/** @type {!Array} */ (col), f, opt_obj); + } + var keys = goog.structs.getKeys(col); + var values = goog.structs.getValues(col); + var l = values.length; + for (var i = 0; i < l; i++) { + if (f.call(opt_obj, values[i], keys && keys[i], col)) { + return true; + } + } + return false; +}; + + +/** + * Calls f for each value in a collection. If all calls return true this return + * true this returns true. If any returns false this returns false at this point + * and does not continue to check the remaining values. + * + * @param {Object} col The collection-like object. + * @param {Function} f The function to call for every value. This function takes + * 3 arguments (the value, the key or undefined if the collection has no + * notion of keys, and the collection) and should return a Boolean. + * @param {Object=} opt_obj The object to be used as the value of 'this' + * within {@code f}. + * @return {boolean} True if all key-value pairs pass the test. + */ +goog.structs.every = function(col, f, opt_obj) { + if (typeof col.every == 'function') { + return col.every(f, opt_obj); + } + if (goog.isArrayLike(col) || goog.isString(col)) { + return goog.array.every(/** @type {!Array} */ (col), f, opt_obj); + } + var keys = goog.structs.getKeys(col); + var values = goog.structs.getValues(col); + var l = values.length; + for (var i = 0; i < l; i++) { + if (!f.call(opt_obj, values[i], keys && keys[i], col)) { + return false; + } + } + return true; +}; diff --git a/contexts/data/lib/closure-library/closure/goog/structs/structs_test.html b/contexts/data/lib/closure-library/closure/goog/structs/structs_test.html new file mode 100644 index 0000000..fb9fe78 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/structs_test.html @@ -0,0 +1,1050 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright 2006 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> +<head> +<meta http-equiv="X-UA-Compatible" content="IE=edge"> +<title>Closure Unit Tests - goog.structs</title> +<script src="../base.js"></script> +<script> + goog.require('goog.array'); + goog.require('goog.object'); + goog.require('goog.structs'); + goog.require('goog.structs.Set'); // needed for filter + goog.require('goog.structs.Map'); + goog.require('goog.testing.jsunit'); +</script> +</head> +<body> +<!-- test container with 10 elements inside, 1 hr and 1 h1 with id h1 --> +<div id="test"> + <hr> + <p>Paragraph 0</p> + <p>Paragraph 1</p> + <p>Paragraph 2</p> + <p>Paragraph 3</p> + <p>Paragraph 4</p> + <p>Paragraph 5</p> + <p>Paragraph 6</p> + <p>Paragraph 7</p> + <h1 id="h1">Header</h1> +</div> + + +<script> + +/* + + This one does not test Map or Set + It tests Array, Object, String and a NodeList + +*/ + + + +function stringifyObject(obj) { + var sb = []; + for (var key in obj) { + sb.push(key + obj[key]); + } + return sb.join(''); +} + + +function getTestElement() { + return document.getElementById('test'); +} + + +function getAll() { + return getTestElement().getElementsByTagName('*') +} + + +var node; + + +function addNode() { + node = document.createElement('span'); + getTestElement().appendChild(node); +} + + +function removeNode() { + getTestElement().removeChild(node); +} + + +function nodeNames(nl) { + var sb = []; + for (var i = 0, n; n = nl[i]; i++) { + sb.push(n.nodeName.toLowerCase()); + } + return sb.join(','); +} + + +var allTagNames1 = 'hr,p,p,p,p,p,p,p,p,h1'; +var allTagNames2 = allTagNames1 + ',span'; + + +function testGetCount() { + var arr = ['a', 'b', 'c']; + assertEquals('count, should be 3', 3, goog.structs.getCount(arr)); + arr.push('d'); + assertEquals('count, should be 4', 4, goog.structs.getCount(arr)); + goog.array.remove(arr, 'd'); + assertEquals('count, should be 3', 3, goog.structs.getCount(arr)); + + var obj = {a: 0, b: 1, c: 2}; + assertEquals('count, should be 3', 3, goog.structs.getCount(obj)); + obj.d = 3; + assertEquals('count, should be 4', 4, goog.structs.getCount(obj)); + delete obj.d; + assertEquals('count, should be 3', 3, goog.structs.getCount(obj)); + + var s = 'abc'; + assertEquals('count, should be 3', 3, goog.structs.getCount(s)); + s += 'd'; + assertEquals('count, should be 4', 4, goog.structs.getCount(s)); + + var all = getAll(); + assertEquals('count, should be 10', 10, goog.structs.getCount(all)); + addNode(); + assertEquals('count, should be 11', 11, goog.structs.getCount(all)); + removeNode(); + assertEquals('count, should be 10', 10, goog.structs.getCount(all)); + + var aMap = new goog.structs.Map({a: 0, b: 1, c: 2}); + assertEquals('count, should be 3', 3, goog.structs.getCount(aMap)); + aMap.set('d', 3); + assertEquals('count, should be 4', 4, goog.structs.getCount(aMap)); + aMap.remove('a'); + assertEquals('count, should be 3', 3, goog.structs.getCount(aMap)); + + var aSet = new goog.structs.Set('abc'); + assertEquals('count, should be 3', 3, goog.structs.getCount(aSet)); + aSet.add('d'); + assertEquals('count, should be 4', 4, goog.structs.getCount(aSet)); + aSet.remove('a'); + assertEquals('count, should be 3', 3, goog.structs.getCount(aSet)); +} + + +function testGetValues() { + var arr = ['a', 'b', 'c', 'd']; + assertEquals('abcd', goog.structs.getValues(arr).join('')); + + var obj = {a: 0, b: 1, c: 2, d: 3}; + assertEquals('0123', goog.structs.getValues(obj).join('')); + + var s = 'abc'; + assertEquals('abc', goog.structs.getValues(s).join('')); + s += 'd'; + assertEquals('abcd', goog.structs.getValues(s).join('')); + + var all = getAll(); + assertEquals(allTagNames1, nodeNames(goog.structs.getValues(all))); + addNode(); + assertEquals(allTagNames2, nodeNames(goog.structs.getValues(all))); + removeNode(); + assertEquals(allTagNames1, nodeNames(goog.structs.getValues(all))); + + var aMap = new goog.structs.Map({a: 1, b: 2, c: 3}); + assertEquals('123', goog.structs.getValues(aMap).join('')); + + var aSet = new goog.structs.Set([1, 2, 3]); + assertEquals('123', goog.structs.getValues(aMap).join('')); +} + + +function testGetKeys() { + var arr = ['a', 'b', 'c', 'd']; + assertEquals('0123', goog.structs.getKeys(arr).join('')); + + var obj = {a: 0, b: 1, c: 2, d: 3}; + assertEquals('abcd', goog.structs.getKeys(obj).join('')); + + var s = 'abc'; + assertEquals('012', goog.structs.getKeys(s).join('')); + s += 'd'; + assertEquals('0123', goog.structs.getKeys(s).join('')); + + var all = getAll(); + assertEquals('0123456789', goog.structs.getKeys(all).join('')); + addNode(); + assertEquals('012345678910', goog.structs.getKeys(all).join('')); + removeNode(); + assertEquals('0123456789', goog.structs.getKeys(all).join('')); + + var aMap = new goog.structs.Map({a: 1, b: 2, c: 3}); + assertEquals('abc', goog.structs.getKeys(aMap).join('')); + + var aSet = new goog.structs.Set([1, 2, 3]); + assertUndefined(goog.structs.getKeys(aSet)); +} + +function testContains() { + var arr = ['a', 'b', 'c', 'd']; + assertTrue("contains, Should contain 'a'", goog.structs.contains(arr, 'a')); + assertFalse("contains, Should not contain 'e'", goog.structs.contains(arr, 'e')); + + var obj = {a: 0, b: 1, c: 2, d: 3}; + assertTrue("contains, Should contain '0'", goog.structs.contains(obj, 0)); + assertFalse("contains, Should not contain '4'", goog.structs.contains(obj, 4)); + + var s = 'abc'; + assertTrue("contains, Should contain 'a'", goog.structs.contains(s, 'a')); + assertFalse("contains, Should not contain 'd'", goog.structs.contains(s, 'd')); + + var all = getAll(); + assertTrue("contains, Should contain 'h1'", + goog.structs.contains(all, document.getElementById('h1'))); + assertFalse("contains, Should not contain 'document.body'", + goog.structs.contains(all, document.body)); + + var aMap = new goog.structs.Map({a: 1, b: 2, c: 3}); + assertTrue("contains, Should contain '1'", goog.structs.contains(aMap, 1)); + assertFalse("contains, Should not contain '4'", goog.structs.contains(aMap, 4)); + + var aSet = new goog.structs.Set([1, 2, 3]); + assertTrue("contains, Should contain '1'", goog.structs.contains(aSet, 1)); + assertFalse("contains, Should not contain '4'", goog.structs.contains(aSet, 4)); +} + + +function testClear() { + var arr = ['a', 'b', 'c', 'd']; + goog.structs.clear(arr); + assertTrue('cleared so it should be empty', goog.structs.isEmpty(arr)); + assertFalse("cleared so it should not contain 'a'", goog.structs.contains(arr, 'a')); + + var obj = {a: 0, b: 1, c: 2, d: 3}; + goog.structs.clear(obj); + assertTrue('cleared so it should be empty', goog.structs.isEmpty(obj)); + assertFalse("cleared so it should not contain 'a' key", goog.structs.contains(obj, 0)); + + var aMap = new goog.structs.Map({a: 1, b: 2, c: 3}); + goog.structs.clear(aMap); + assertTrue('cleared map so it should be empty', goog.structs.isEmpty(aMap)); + assertFalse("cleared map so it should not contain '1' value", + goog.structs.contains(aMap, 1)); + + var aSet = new goog.structs.Set([1, 2, 3]); + goog.structs.clear(aSet); + assertTrue('cleared set so it should be empty', goog.structs.isEmpty(aSet)); + assertFalse("cleared set so it should not contain '1'", goog.structs.contains(aSet, 1)); + + // cannot clear a string or a NodeList +} + + + +// Map + +function testMap() { + var RV = {}; + var obj = { + map: function(g) { + assertEquals(f, g); + assertEquals(this, obj); + return RV; + } + }; + function f() {} + assertEquals(RV, goog.structs.map(obj, f)); +} + +function testMap2() { + var THIS_OBJ = {}; + var RV = {}; + var obj = { + map: function(g, obj2) { + assertEquals(f, g); + assertEquals(this, obj); + assertEquals(THIS_OBJ, obj2); + return RV; + } + }; + function f() {} + assertEquals(RV, goog.structs.map(obj, f, THIS_OBJ)); +} + +function testMapArrayLike() { + var col = [0, 1, 2]; + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + return v * v; + } + assertArrayEquals([0, 1, 4], goog.structs.map(col, f)); +} + +function testMapArrayLike2() { + var THIS_OBJ = {}; + var col = [0, 1, 2]; + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + assertEquals(THIS_OBJ, this); + return v * v; + } + assertArrayEquals([0, 1, 4], goog.structs.map(col, f, THIS_OBJ)); +} + +function testMapString() { + var col = '012'; + function f(v, i, col2) { + // Teh SpiderMonkey Array.map for strings turns the string into a String + // so we cannot use assertEquals because it uses ===. + assertTrue(col == col2); + assertEquals('number', typeof i); + return Number(v) * Number(v); + } + assertArrayEquals([0, 1, 4], goog.structs.map(col, f)); +} + +function testMapString2() { + var THIS_OBJ = {}; + var col = '012'; + function f(v, i, col2) { + // for some reason the strings are equal but identical??? + assertEquals(String(col), String(col2)); + assertEquals('number', typeof i); + assertEquals(THIS_OBJ, this); + return Number(v) * Number(v); + } + assertArrayEquals([0, 1, 4], goog.structs.map(col, f, THIS_OBJ)); +} + +function testMapMap() { + var col = new goog.structs.Map({a: 0, b: 1, c: 2}); + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('string', typeof key); + return v * v; + } + assertObjectEquals({a: 0, b: 1, c: 4}, goog.structs.map(col, f)); +} + +function testMapMap2() { + var THIS_OBJ = {}; + var col = new goog.structs.Map({a: 0, b: 1, c: 2}); + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('string', typeof key); + assertEquals(THIS_OBJ, this); + return v * v; + } + assertObjectEquals({a: 0, b: 1, c: 4}, goog.structs.map(col, f, THIS_OBJ)); +} + +function testMapSet() { + var col = new goog.structs.Set([0, 1, 2]); + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('undefined', typeof key); + return v * v; + } + assertArrayEquals([0, 1, 4], goog.structs.map(col, f)); +} + +function testMapSet2() { + var THIS_OBJ = {}; + var col = new goog.structs.Set([0, 1, 2]); + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('undefined', typeof key); + assertEquals(THIS_OBJ, this); + return v * v; + } + assertArrayEquals([0, 1, 4], goog.structs.map(col, f, THIS_OBJ)); +} + +function testMapNodeList() { + var col = getAll(); + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + return v.tagName; + } + assertEquals('HRPPPPPPPPH1', goog.structs.map(col, f).join('')); +} + +function testMapNodeList2() { + var THIS_OBJ = {}; + var col = getAll(); + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + assertEquals(THIS_OBJ, this); + return v.tagName; + } + assertEquals('HRPPPPPPPPH1', goog.structs.map(col, f, THIS_OBJ).join('')); +} + +// Filter + +function testFilter() { + var RV = {}; + var obj = { + filter: function(g) { + assertEquals(f, g); + assertEquals(this, obj); + return RV; + } + }; + function f() {} + assertEquals(RV, goog.structs.filter(obj, f)); +} + +function testFilter2() { + var THIS_OBJ = {}; + var RV = {}; + var obj = { + filter: function(g, obj2) { + assertEquals(f, g); + assertEquals(this, obj); + assertEquals(THIS_OBJ, obj2); + return RV; + } + }; + function f() {} + assertEquals(RV, goog.structs.filter(obj, f, THIS_OBJ)); +} + +function testFilterArrayLike() { + var col = [0, 1, 2]; + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + return v > 0; + } + assertArrayEquals([1, 2], goog.structs.filter(col, f)); +} + +function testFilterArrayLike2() { + var THIS_OBJ = {}; + var col = [0, 1, 2]; + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + assertEquals(THIS_OBJ, this); + return v > 0; + } + assertArrayEquals([1, 2], goog.structs.filter(col, f, THIS_OBJ)); +} + +function testFilterString() { + var col = '012'; + function f(v, i, col2) { + // for some reason the strings are equal but identical??? + assertEquals(String(col), String(col2)); + assertEquals('number', typeof i); + return Number(v) > 0; + } + assertArrayEquals(['1', '2'], goog.structs.filter(col, f)); +} + +function testFilterString2() { + var THIS_OBJ = {}; + var col = '012'; + function f(v, i, col2) { + // for some reason the strings are equal but identical??? + assertEquals(String(col), String(col2)); + assertEquals('number', typeof i); + assertEquals(THIS_OBJ, this); + return Number(v) > 0; + } + assertArrayEquals(['1', '2'], goog.structs.filter(col, f, THIS_OBJ)); +} + +function testFilterMap() { + var col = new goog.structs.Map({a: 0, b: 1, c: 2}); + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('string', typeof key); + return v > 0; + } + assertObjectEquals({b: 1, c: 2}, goog.structs.filter(col, f)); +} + +function testFilterMap2() { + var THIS_OBJ = {}; + var col = new goog.structs.Map({a: 0, b: 1, c: 2}); + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('string', typeof key); + assertEquals(THIS_OBJ, this); + return v > 0; + } + assertObjectEquals({b: 1, c: 2}, goog.structs.filter(col, f, THIS_OBJ)); +} + +function testFilterSet() { + var col = new goog.structs.Set([0, 1, 2]); + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('undefined', typeof key); + return v > 0; + } + assertArrayEquals([1, 2], goog.structs.filter(col, f)); +} + +function testFilterSet2() { + var THIS_OBJ = {}; + var col = new goog.structs.Set([0, 1, 2]); + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('undefined', typeof key); + assertEquals(THIS_OBJ, this); + return v > 0; + } + assertArrayEquals([1, 2], goog.structs.filter(col, f, THIS_OBJ)); +} + +function testFilterNodeList() { + var col = getAll(); + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + return v.tagName == 'P'; + } + assertEquals('p,p,p,p,p,p,p,p', + nodeNames(goog.structs.filter(col, f))); +} + +function testFilterNodeList2() { + var THIS_OBJ = {}; + var col = getAll(); + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + assertEquals(THIS_OBJ, this); + return v.tagName == 'P'; + } + assertEquals('p,p,p,p,p,p,p,p', + nodeNames(goog.structs.filter(col, f, THIS_OBJ))); +} + +// Some + +function testSome() { + var RV = {}; + var obj = { + some: function(g) { + assertEquals(f, g); + assertEquals(this, obj); + return RV; + } + }; + function f() {} + assertEquals(RV, goog.structs.some(obj, f)); +} + +function testSome2() { + var THIS_OBJ = {}; + var RV = {}; + var obj = { + some: function(g, obj2) { + assertEquals(f, g); + assertEquals(this, obj); + assertEquals(THIS_OBJ, obj2); + return RV; + } + }; + function f() {} + assertEquals(RV, goog.structs.some(obj, f, THIS_OBJ)); +} + +function testSomeArrayLike() { + var limit = 0; + var col = [0, 1, 2]; + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + return v > limit; + } + assertTrue(goog.structs.some(col, f)); + limit = 2; + assertFalse(goog.structs.some(col, f)); +} + +function testSomeArrayLike2() { + var THIS_OBJ = {}; + var limit = 0; + var col = [0, 1, 2]; + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + assertEquals(THIS_OBJ, this); + return v > limit; + } + assertTrue(goog.structs.some(col, f, THIS_OBJ)); + limit = 2; + assertFalse(goog.structs.some(col, f, THIS_OBJ)); +} + +function testSomeString() { + var limit = 0; + var col = '012'; + function f(v, i, col2) { + // for some reason the strings are equal but identical??? + assertEquals(String(col), String(col2)); + assertEquals('number', typeof i); + return Number(v) > limit; + } + assertTrue(goog.structs.some(col, f)); + limit = 2; + assertFalse(goog.structs.some(col, f)); +} + +function testSomeString2() { + var THIS_OBJ = {}; + var limit = 0; + var col = '012'; + function f(v, i, col2) { + // for some reason the strings are equal but identical??? + assertEquals(String(col), String(col2)); + assertEquals('number', typeof i); + assertEquals(THIS_OBJ, this); + return Number(v) > limit; + } + assertTrue(goog.structs.some(col, f, THIS_OBJ)); + limit = 2; + assertFalse(goog.structs.some(col, f, THIS_OBJ)); +} + +function testSomeMap() { + var limit = 0; + var col = new goog.structs.Map({a: 0, b: 1, c: 2}); + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('string', typeof key); + return v > limit; + } + assertObjectEquals(true, goog.structs.some(col, f)); + limit = 2; + assertFalse(goog.structs.some(col, f)); +} + +function testSomeMap2() { + var THIS_OBJ = {}; + var limit = 0; + var col = new goog.structs.Map({a: 0, b: 1, c: 2}); + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('string', typeof key); + assertEquals(THIS_OBJ, this); + return v > limit; + } + assertObjectEquals(true, goog.structs.some(col, f, THIS_OBJ)); + limit = 2; + assertFalse(goog.structs.some(col, f, THIS_OBJ)); +} + +function testSomeSet() { + var limit = 0; + var col = new goog.structs.Set([0, 1, 2]); + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('undefined', typeof key); + return v > limit; + } + assertTrue(goog.structs.some(col, f)); + limit = 2; + assertFalse(goog.structs.some(col, f)); +} + +function testSomeSet2() { + var THIS_OBJ = {}; + var limit = 0; + var col = new goog.structs.Set([0, 1, 2]); + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('undefined', typeof key); + assertEquals(THIS_OBJ, this); + return v > limit; + } + assertTrue(goog.structs.some(col, f, THIS_OBJ)); + limit = 2; + assertFalse(goog.structs.some(col, f, THIS_OBJ)); +} + +function testSomeNodeList() { + var tagName = 'P'; + var col = getAll(); + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + return v.tagName == tagName; + } + assertTrue(goog.structs.some(col, f)); + tagName = 'MARQUEE'; + assertFalse(goog.structs.some(col, f)); +} + +function testSomeNodeList2() { + var THIS_OBJ = {}; + var tagName = 'P'; + var col = getAll(); + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + assertEquals(THIS_OBJ, this); + return v.tagName == tagName; + } + assertTrue(goog.structs.some(col, f, THIS_OBJ)); + tagName = 'MARQUEE'; + assertFalse(goog.structs.some(col, f, THIS_OBJ)); +} + +// Every + +function testEvery() { + var RV = {}; + var obj = { + every: function(g) { + assertEquals(f, g); + assertEquals(this, obj); + return RV; + } + }; + function f() {} + assertEquals(RV, goog.structs.every(obj, f)); +} + +function testEvery2() { + var THIS_OBJ = {}; + var RV = {}; + var obj = { + every: function(g, obj2) { + assertEquals(f, g); + assertEquals(this, obj); + assertEquals(THIS_OBJ, obj2); + return RV; + } + }; + function f() {} + assertEquals(RV, goog.structs.every(obj, f, THIS_OBJ)); +} + +function testEveryArrayLike() { + var limit = -1; + var col = [0, 1, 2]; + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + return v > limit; + } + assertTrue(goog.structs.every(col, f)); + limit = 1; + assertFalse(goog.structs.every(col, f)); +} + +function testEveryArrayLike2() { + var THIS_OBJ = {}; + var limit = -1; + var col = [0, 1, 2]; + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + assertEquals(THIS_OBJ, this); + return v > limit; + } + assertTrue(goog.structs.every(col, f, THIS_OBJ)); + limit = 1; + assertFalse(goog.structs.every(col, f, THIS_OBJ)); +} + +function testEveryString() { + var limit = -1; + var col = '012'; + function f(v, i, col2) { + // for some reason the strings are equal but identical??? + assertEquals(String(col), String(col2)); + assertEquals('number', typeof i); + return Number(v) > limit; + } + assertTrue(goog.structs.every(col, f)); + limit = 1; + assertFalse(goog.structs.every(col, f)); +} + +function testEveryString2() { + var THIS_OBJ = {}; + var limit = -1; + var col = '012'; + function f(v, i, col2) { + // for some reason the strings are equal but identical??? + assertEquals(String(col), String(col2)); + assertEquals('number', typeof i); + assertEquals(THIS_OBJ, this); + return Number(v) > limit; + } + assertTrue(goog.structs.every(col, f, THIS_OBJ)); + limit = 1; + assertFalse(goog.structs.every(col, f, THIS_OBJ)); +} + +function testEveryMap() { + var limit = -1; + var col = new goog.structs.Map({a: 0, b: 1, c: 2}); + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('string', typeof key); + return v > limit; + } + assertObjectEquals(true, goog.structs.every(col, f)); + limit = 1; + assertFalse(goog.structs.every(col, f)); +} + +function testEveryMap2() { + var THIS_OBJ = {}; + var limit = -1; + var col = new goog.structs.Map({a: 0, b: 1, c: 2}); + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('string', typeof key); + assertEquals(THIS_OBJ, this); + return v > limit; + } + assertObjectEquals(true, goog.structs.every(col, f, THIS_OBJ)); + limit = 1; + assertFalse(goog.structs.every(col, f, THIS_OBJ)); +} + +function testEverySet() { + var limit = -1; + var col = new goog.structs.Set([0, 1, 2]); + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('undefined', typeof key); + return v > limit; + } + assertTrue(goog.structs.every(col, f)); + limit = 1; + assertFalse(goog.structs.every(col, f)); +} + +function testEverySet2() { + var THIS_OBJ = {}; + var limit = -1; + var col = new goog.structs.Set([0, 1, 2]); + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('undefined', typeof key); + assertEquals(THIS_OBJ, this); + return v > limit; + } + assertTrue(goog.structs.every(col, f, THIS_OBJ)); + limit = 1; + assertFalse(goog.structs.every(col, f, THIS_OBJ)); +} + +function testEveryNodeList() { + var nodeType = 1; // ELEMENT + var col = getAll(); + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + return v.nodeType == nodeType; + } + assertTrue(goog.structs.every(col, f)); + nodeType = 3; // TEXT + assertFalse(goog.structs.every(col, f)); +} + +function testEveryNodeList2() { + var THIS_OBJ = {}; + var nodeType = 1; // ELEMENT + var col = getAll(); + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + assertEquals(THIS_OBJ, this); + return v.nodeType == nodeType; + } + assertTrue(goog.structs.every(col, f, THIS_OBJ)); + nodeType = 3; // TEXT + assertFalse(goog.structs.every(col, f, THIS_OBJ)); +} + +// For each + +function testForEach() { + var called = false; + var obj = { + forEach: function(g) { + assertEquals(f, g); + assertEquals(this, obj); + called = true; + } + }; + function f() {} + goog.structs.forEach(obj, f); + assertTrue(called); +} + +function testForEach2() { + var called = false; + var THIS_OBJ = {}; + var obj = { + forEach: function(g, obj2) { + assertEquals(f, g); + assertEquals(this, obj); + assertEquals(THIS_OBJ, obj2); + called = true; + } + }; + function f() {} + goog.structs.forEach(obj, f, THIS_OBJ); + assertTrue(called); +} + +function testForEachArrayLike() { + var col = [0, 1, 2]; + var values = []; + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + values.push(v * v); + } + goog.structs.forEach(col, f) + assertArrayEquals([0, 1, 4], values); +} + +function testForEachArrayLike2() { + var THIS_OBJ = {}; + var col = [0, 1, 2]; + var values = []; + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + assertEquals(THIS_OBJ, this); + values.push(v * v); + } + goog.structs.forEach(col, f, THIS_OBJ); + assertArrayEquals([0, 1, 4], values); +} + +function testForEachString() { + var col = '012'; + var values = []; + function f(v, i, col2) { + // for some reason the strings are equal but identical??? + assertEquals(String(col), String(col2)); + assertEquals('number', typeof i); + values.push(Number(v) * Number(v)); + } + goog.structs.forEach(col, f); + assertArrayEquals([0, 1, 4], values); +} + +function testForEachString2() { + var THIS_OBJ = {}; + var col = '012'; + var values = []; + function f(v, i, col2) { + // for some reason the strings are equal but identical??? + assertEquals(String(col), String(col2)); + assertEquals('number', typeof i); + assertEquals(THIS_OBJ, this); + values.push(Number(v) * Number(v)); + } + goog.structs.forEach(col, f, THIS_OBJ); + assertArrayEquals([0, 1, 4], values); +} + +function testForEachMap() { + var col = new goog.structs.Map({a: 0, b: 1, c: 2}); + var values = []; + var keys = []; + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('string', typeof key); + values.push(v * v); + keys.push(key); + } + goog.structs.forEach(col, f); + assertArrayEquals([0, 1, 4], values); + assertArrayEquals(['a', 'b', 'c'], keys); +} + +function testForEachMap2() { + var THIS_OBJ = {}; + var col = new goog.structs.Map({a: 0, b: 1, c: 2}); + var values = []; + var keys = []; + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('string', typeof key); + assertEquals(THIS_OBJ, this); + values.push(v * v); + keys.push(key); + } + goog.structs.forEach(col, f, THIS_OBJ); + assertArrayEquals([0, 1, 4], values); + assertArrayEquals(['a', 'b', 'c'], keys); +} + +function testForEachSet() { + var col = new goog.structs.Set([0, 1, 2]); + var values = []; + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('undefined', typeof key); + values.push(v * v); + } + goog.structs.forEach(col, f); + assertArrayEquals([0, 1, 4], values); +} + +function testForEachSet2() { + var THIS_OBJ = {}; + var col = new goog.structs.Set([0, 1, 2]); + var values = []; + function f(v, key, col2) { + assertEquals(col, col2); + assertEquals('undefined', typeof key); + assertEquals(THIS_OBJ, this); + values.push(v * v); + } + goog.structs.forEach(col, f, THIS_OBJ); + assertArrayEquals([0, 1, 4], values); +} + +function testForEachNodeList() { + var values = []; + var col = getAll(); + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + values.push(v.tagName); + } + goog.structs.forEach(col, f); + assertEquals('HRPPPPPPPPH1', values.join('')); +} + +function testForEachNodeList2() { + var THIS_OBJ = {}; + var values = []; + var col = getAll(); + function f(v, i, col2) { + assertEquals(col, col2); + assertEquals('number', typeof i); + assertEquals(THIS_OBJ, this); + values.push(v.tagName); + } + goog.structs.forEach(col, f, THIS_OBJ); + assertEquals('HRPPPPPPPPH1', values.join('')); +} + +</script> +</body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/structs/treenode.js b/contexts/data/lib/closure-library/closure/goog/structs/treenode.js new file mode 100644 index 0000000..4d67ed4 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/treenode.js @@ -0,0 +1,427 @@ +// Copyright 2010 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Generic tree node data structure with arbitrary number of child + * nodes. + * + */ + +goog.provide('goog.structs.TreeNode'); + +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.structs.Node'); + + + +/** + * Generic tree node data structure with arbitrary number of child nodes. + * It is possible to create a dynamic tree structure by overriding + * {@link #getParent} and {@link #getChildren} in a subclass. All other getters + * will automatically work. + * + * @param {*} key Key. + * @param {*} value Value. + * @constructor + * @extends {goog.structs.Node} + */ +goog.structs.TreeNode = function(key, value) { + goog.structs.Node.call(this, key, value); +}; +goog.inherits(goog.structs.TreeNode, goog.structs.Node); + + +/** + * Constant for empty array to avoid unnecessary allocations. + * @private + */ +goog.structs.TreeNode.EMPTY_ARRAY_ = []; + + +/** + * Reference to the parent node or null if it has no parent. + * @type {goog.structs.TreeNode} + * @private + */ +goog.structs.TreeNode.prototype.parent_ = null; + + +/** + * Child nodes or null in case of leaf node. + * @type {Array.<!goog.structs.TreeNode>} + * @private + */ +goog.structs.TreeNode.prototype.children_ = null; + + +/** + * @return {!goog.structs.TreeNode} Clone of the tree node without its parent + * and child nodes. The key and the value are copied by reference. + */ +goog.structs.TreeNode.prototype.clone = function() { + return new goog.structs.TreeNode(this.getKey(), this.getValue()); +}; + + +/** + * @return {!goog.structs.TreeNode} Clone of the subtree with this node as root. + */ +goog.structs.TreeNode.prototype.deepClone = function() { + var clone = this.clone(); + this.forEachChild(function(child) { + clone.addChild(child.deepClone()); + }); + return clone; +}; + + +/** + * @return {goog.structs.TreeNode} Parent node or null if it has no parent. + */ +goog.structs.TreeNode.prototype.getParent = function() { + return this.parent_; +}; + + +/** + * @return {boolean} Whether the node is a leaf node. + */ +goog.structs.TreeNode.prototype.isLeaf = function() { + return !this.getChildCount(); +}; + + +/** + * Tells if the node is the last child of its parent. This method helps how to + * connect the tree nodes with lines: L shapes should be used before the last + * children and |- shapes before the rest. Schematic tree visualization: + * + * <pre> + * Node1 + * |-Node2 + * | L-Node3 + * | |-Node4 + * | L-Node5 + * L-Node6 + * </pre> + * + * @return {boolean} Whether the node has parent and is the last child of it. + */ +goog.structs.TreeNode.prototype.isLastChild = function() { + var parent = this.getParent(); + return Boolean(parent && this == goog.array.peek(parent.getChildren())); +}; + + +/** + * @return {!Array.<!goog.structs.TreeNode>} Immutable child nodes. + */ +goog.structs.TreeNode.prototype.getChildren = function() { + return this.children_ || goog.structs.TreeNode.EMPTY_ARRAY_; +}; + + +/** + * Gets the child node of this node at the given index. + * @param {number} index Child index. + * @return {goog.structs.TreeNode} The node at the given index or null if not + * found. + */ +goog.structs.TreeNode.prototype.getChildAt = function(index) { + return this.getChildren()[index] || null; +}; + + +/** + * @return {number} The number of children. + */ +goog.structs.TreeNode.prototype.getChildCount = function() { + return this.getChildren().length; +}; + + +/** + * @return {number} The number of ancestors of the node. + */ +goog.structs.TreeNode.prototype.getDepth = function() { + var depth = 0; + var node = this; + while (node.getParent()) { + depth++; + node = node.getParent(); + } + return depth; +}; + + +/** + * @return {!Array.<!goog.structs.TreeNode>} All ancestor nodes in bottom-up + * order. + */ +goog.structs.TreeNode.prototype.getAncestors = function() { + var ancestors = []; + var node = this.getParent(); + while (node) { + ancestors.push(node); + node = node.getParent(); + } + return ancestors; +}; + + +/** + * @return {!goog.structs.TreeNode} The root of the tree structure, i.e. the + * farthest ancestor of the node or the node itself if it has no parents. + */ +goog.structs.TreeNode.prototype.getRoot = function() { + var root = this; + while (root.getParent()) { + root = root.getParent(); + } + return root; +}; + + +/** + * Builds a nested array structure from the node keys in this node's subtree to + * facilitate testing tree operations that change the hierarchy. + * @return {!Array} The structure of this node's descendants as nested array + * of node keys. The number of unclosed opening brackets up to a particular + * node is proportional to the indentation of that node in the graphical + * representation of the tree. Example: + * <pre> + * this + * |- child1 + * | L- grandchild + * L- child2 + * </pre> + * is represented as ['child1', ['grandchild'], 'child2']. + */ +goog.structs.TreeNode.prototype.getSubtreeKeys = function() { + var ret = []; + this.forEachChild(function(child) { + ret.push(child.getKey()); + if (!child.isLeaf()) { + ret.push(child.getSubtreeKeys()); + } + }); + return ret; +}; + + +/** + * Tells whether this node is the ancestor of the given node. + * @param {!goog.structs.TreeNode} node A node. + * @return {boolean} Whether this node is the ancestor of {@code node}. + */ +goog.structs.TreeNode.prototype.contains = function(node) { + var current = node; + do { + current = current.getParent(); + } while (current && current != this); + return Boolean(current); +}; + + +/** + * Finds the deepest common ancestor of the given nodes. The concept of + * ancestor is not strict in this case, it includes the node itself. + * @param {...!goog.structs.TreeNode} var_args The nodes. + * @return {goog.structs.TreeNode} The common ancestor of the nodes or null if + * they are from different trees. + */ +goog.structs.TreeNode.findCommonAncestor = function(var_args) { + var ret = arguments[0]; + if (!ret) { + return null; + } + + var retDepth = ret.getDepth(); + for (var i = 1; i < arguments.length; i++) { + var node = arguments[i]; + var depth = node.getDepth(); + while (node != ret) { + if (depth <= retDepth) { + ret = ret.getParent(); + retDepth--; + } + if (depth > retDepth) { + node = node.getParent(); + depth--; + } + } + } + + return ret; +}; + + +/** + * Traverses all child nodes. + * @param {function(!goog.structs.TreeNode, number, + * !Array.<!goog.structs.TreeNode>)} f Callback function. It takes the + * node, its index and the array of all child nodes as arguments. + * @param {Object=} opt_this The object to be used as the value of {@code this} + * within {@code f}. + */ +goog.structs.TreeNode.prototype.forEachChild = function(f, opt_this) { + goog.array.forEach(this.getChildren(), f, opt_this); +}; + + +/** + * Traverses all child nodes recursively in preorder. + * @param {function(!goog.structs.TreeNode)} f Callback function. It takes the + * node as argument. + * @param {Object=} opt_this The object to be used as the value of {@code this} + * within {@code f}. + */ +goog.structs.TreeNode.prototype.forEachDescendant = function(f, opt_this) { + goog.array.forEach(this.getChildren(), function(child) { + f.call(opt_this, child); + child.forEachDescendant(f, opt_this); + }); +}; + + +/** + * Traverses the subtree with the possibility to skip branches. Starts with + * this node, and visits the descendant nodes depth-first, in preorder. + * @param {function(!goog.structs.TreeNode): (boolean|undefined)} f Callback + * function. It takes the node as argument. The children of this node will + * be visited if the callback returns true or undefined, and will be + * skipped if the callback returns false. + * @param {Object=} opt_this The object to be used as the value of {@code this} + * within {@code f}. + */ +goog.structs.TreeNode.prototype.traverse = function(f, opt_this) { + if (f.call(opt_this, this) !== false) { + goog.array.forEach(this.getChildren(), function(child) { + child.traverse(f, opt_this); + }); + } +}; + + +/** + * Sets the parent node of this node. The callers must ensure that the parent + * node and only that has this node among its children. + * @param {goog.structs.TreeNode} parent The parent to set. If null, the node + * will be detached from the tree. + * @protected + */ +goog.structs.TreeNode.prototype.setParent = function(parent) { + this.parent_ = parent; +}; + + +/** + * Appends a child node to this node. + * @param {!goog.structs.TreeNode} child Orphan child node. + */ +goog.structs.TreeNode.prototype.addChild = function(child) { + this.addChildAt(child, this.children_ ? this.children_.length : 0); +}; + + +/** + * Inserts a child node at the given index. + * @param {!goog.structs.TreeNode} child Orphan child node. + * @param {number} index The position to insert at. + */ +goog.structs.TreeNode.prototype.addChildAt = function(child, index) { + goog.asserts.assert(!child.getParent()); + child.setParent(this); + this.children_ = this.children_ || []; + goog.asserts.assert(index >= 0 && index <= this.children_.length); + goog.array.insertAt(this.children_, child, index); +}; + + +/** + * Replaces a child node at the given index. + * @param {!goog.structs.TreeNode} newChild Child node to set. It must not have + * parent node. + * @param {number} index Valid index of the old child to replace. + * @return {!goog.structs.TreeNode} The original child node, detached from its + * parent. + */ +goog.structs.TreeNode.prototype.replaceChildAt = function(newChild, index) { + goog.asserts.assert(!newChild.getParent(), + 'newChild must not have parent node'); + var children = this.getChildren(); + var oldChild = children[index]; + goog.asserts.assert(oldChild, 'Invalid child or child index is given.'); + oldChild.setParent(null); + children[index] = newChild; + newChild.setParent(this); + return oldChild; +}; + + +/** + * Replaces the given child node. + * @param {!goog.structs.TreeNode} newChild New node to replace + * {@code oldChild}. It must not have parent node. + * @param {!goog.structs.TreeNode} oldChild Existing child node to be replaced. + * @return {!goog.structs.TreeNode} The replaced child node detached from its + * parent. + */ +goog.structs.TreeNode.prototype.replaceChild = function(newChild, oldChild) { + return this.replaceChildAt(newChild, + goog.array.indexOf(this.getChildren(), oldChild)); +}; + + +/** + * Removes the child node at the given index. + * @param {number} index The position to remove from. + * @return {goog.structs.TreeNode} The removed node if any. + */ +goog.structs.TreeNode.prototype.removeChildAt = function(index) { + var child = this.children_ && this.children_[index]; + if (child) { + child.setParent(null); + goog.array.removeAt(this.children_, index); + if (this.children_.length == 0) { + delete this.children_; + } + return child; + } + return null; +}; + + +/** + * Removes the given child node of this node. + * @param {goog.structs.TreeNode} child The node to remove. + * @return {goog.structs.TreeNode} The removed node if any. + */ +goog.structs.TreeNode.prototype.removeChild = function(child) { + return this.removeChildAt(goog.array.indexOf(this.getChildren(), child)); +}; + + +/** + * Removes all child nodes of this node. + */ +goog.structs.TreeNode.prototype.removeChildren = function() { + if (this.children_) { + goog.array.forEach(this.children_, function(child) { + child.setParent(null); + }); + } + delete this.children_; +}; diff --git a/contexts/data/lib/closure-library/closure/goog/structs/treenode_test.html b/contexts/data/lib/closure-library/closure/goog/structs/treenode_test.html new file mode 100644 index 0000000..c858b29 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/treenode_test.html @@ -0,0 +1,370 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright 2010 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> +<!-- +--> +<head> +<meta http-equiv="X-UA-Compatible" content="IE=edge"> +<title>Closure Unit Tests - goog.structs.TreeNode</title> +<script src="../base.js"></script> +<script> + goog.require('goog.array'); + goog.require('goog.structs.TreeNode'); + goog.require('goog.testing.jsunit'); +</script> +</head> +<body> +<script> + +function testConstructor() { + var node = new goog.structs.TreeNode('key', 'value'); + assertEquals('key', 'key', node.getKey()); + assertEquals('value', 'value', node.getValue()); + assertNull('parent', node.getParent()); + assertArrayEquals('children', [], node.getChildren()); + assertTrue('leaf', node.isLeaf()); +} + +function testClone() { + var node1 = new goog.structs.TreeNode(1, '1'); + var node2 = new goog.structs.TreeNode(2, '2'); + var node3 = new goog.structs.TreeNode(3, '3'); + node1.addChild(node2); + node2.addChild(node3); + + var clone = node2.clone(); + assertEquals('key', 2, clone.getKey()); + assertEquals('value', '2', clone.getValue()); + assertNull('parent', clone.getParent()); + assertArrayEquals('children', [], clone.getChildren()); +} + +function testDeepClone() { + var node1 = new goog.structs.TreeNode(1, '1'); + var node2 = new goog.structs.TreeNode(2, '2'); + var node3 = new goog.structs.TreeNode(3, '3'); + node1.addChild(node2); + node2.addChild(node3); + + var clone = node2.deepClone(); + assertEquals('key', 2, clone.getKey()); + assertEquals('value', '2', clone.getValue()); + assertNull('parent', clone.getParent()); + assertEquals('number of children', 1, clone.getChildren().length); + assertEquals('first child key', 3, clone.getChildAt(0).getKey()); + assertNotEquals('first child has been cloned', node3, clone.getChildAt(0)); +} + +function testGetParent() { + var node1 = new goog.structs.TreeNode(1, null); + var node2 = new goog.structs.TreeNode(2, null); + node1.addChild(node2); + assertEquals('parent', node1, node2.getParent()); + assertNull('orphan', node1.getParent()); +} + +function testIsLeaf() { + var node1 = new goog.structs.TreeNode(1, null); + var node2 = new goog.structs.TreeNode(2, null); + node1.addChild(node2); + assertFalse('not leaf', node1.isLeaf()); + assertTrue('leaf', node2.isLeaf()); +} + +function testIsLastChild() { + var node1 = new goog.structs.TreeNode(1, '1'); + var node2 = new goog.structs.TreeNode(2, '2'); + var node3 = new goog.structs.TreeNode(3, '3'); + node1.addChild(node2); + node1.addChild(node3); + assertFalse('root', node1.isLastChild()); + assertFalse('first child out of the two', node2.isLastChild()); + assertTrue('second child out of the two', node3.isLastChild()); +} + +function testGetChildren() { + var node1 = new goog.structs.TreeNode(1, null); + var node2 = new goog.structs.TreeNode(2, null); + node1.addChild(node2); + assertArrayEquals('1 child', [node2], node1.getChildren()); + assertArrayEquals('no children', [], node2.getChildren()); +} + +function testGetChildAt() { + var node1 = new goog.structs.TreeNode(1, null); + var node2 = new goog.structs.TreeNode(2, null); + node1.addChild(node2); + assertNull('index too low', node1.getChildAt(-1)); + assertEquals('first child', node2, node1.getChildAt(0)); + assertNull('index too high', node1.getChildAt(1)); + assertNull('no children', node2.getChildAt(0)); +} + +function testGetChildCount() { + var node1 = new goog.structs.TreeNode(1, null); + var node2 = new goog.structs.TreeNode(2, null); + node1.addChild(node2); + assertEquals('child count of root node', 1, node1.getChildCount()); + assertEquals('child count of leaf node', 0, node2.getChildCount()); +} + +function testGetDepth() { + var node1 = new goog.structs.TreeNode(1, null); + var node2 = new goog.structs.TreeNode(2, null); + var node3 = new goog.structs.TreeNode(3, null); + node1.addChild(node2); + node2.addChild(node3); + assertEquals('no parent', 0, node1.getDepth()); + assertEquals('1 ancestor', 1, node2.getDepth()); + assertEquals('2 ancestors', 2, node3.getDepth()); +} + +function testGetAncestors() { + var node1 = new goog.structs.TreeNode(1, null); + var node2 = new goog.structs.TreeNode(2, null); + var node3 = new goog.structs.TreeNode(3, null); + node1.addChild(node2); + node2.addChild(node3); + assertArrayEquals('no ancestors', [], node1.getAncestors()); + assertArrayEquals('2 ancestors', [node2, node1], node3.getAncestors()); +} + +function testGetRoot() { + var node1 = new goog.structs.TreeNode(1, null); + var node2 = new goog.structs.TreeNode(2, null); + node1.addChild(node2); + assertEquals('no ancestors', node1, node1.getRoot()); + assertEquals('has ancestors', node1, node2.getRoot()); +} + +function testGetSubtreeKeys() { + var root = new goog.structs.TreeNode('root', null); + var child1 = new goog.structs.TreeNode('child1', null); + var child2 = new goog.structs.TreeNode('child2', null); + var grandchild = new goog.structs.TreeNode('grandchild', null); + root.addChild(child1); + root.addChild(child2); + child1.addChild(grandchild); + assertArrayEquals('node hierarchy', ['child1', ['grandchild'], 'child2'], + root.getSubtreeKeys()); +} + +function testContains() { + var node1 = new goog.structs.TreeNode(1, null); + var node2 = new goog.structs.TreeNode(2, null); + var node3 = new goog.structs.TreeNode(3, null); + var node4 = new goog.structs.TreeNode(4, null); + node1.addChild(node2); + node2.addChild(node3); + node2.addChild(node4); + + assertTrue('parent', node1.contains(node2)); + assertTrue('grandparent', node1.contains(node3)); + assertFalse('child', node2.contains(node1)); + assertFalse('grandchild', node3.contains(node1)); + assertFalse('sibling', node3.contains(node4)); +} + +function testFindCommonAncestor() { + var findCommonAncestor = goog.structs.TreeNode.findCommonAncestor; + var node1 = new goog.structs.TreeNode(1, null); + var node2 = new goog.structs.TreeNode(2, null); + var node3 = new goog.structs.TreeNode(3, null); + var node4 = new goog.structs.TreeNode(4, null); + var node5 = new goog.structs.TreeNode(5, null); + node1.addChild(node2); + node2.addChild(node3); + node1.addChild(node4); + + assertNull('0 nodes', findCommonAncestor()); + assertEquals('1 node', node2, findCommonAncestor(node2)); + assertEquals('same nodes', node3, findCommonAncestor(node3, node3)); + assertEquals('node and child node', node2, findCommonAncestor(node2, node3)); + assertEquals('node and parent node', node1, findCommonAncestor(node2, node1)); + assertEquals('siblings', node1, findCommonAncestor(node2, node4)); + assertEquals('all nodes', node1, + findCommonAncestor(node2, node3, node4, node1)); + assertNull('disconnected nodes', findCommonAncestor(node3, node5)); +} + +function testForEachChild() { + var node1 = new goog.structs.TreeNode(1, null); + var node2 = new goog.structs.TreeNode(2, null); + var node3 = new goog.structs.TreeNode(3, null); + node1.addChild(node2); + node1.addChild(node3); + + var thisContext = {}; + var visitedNodes = []; + var indices = []; + node1.forEachChild(function(node, index, children) { + assertEquals('value of this', thisContext, this); + visitedNodes.push(node); + indices.push(index); + assertArrayEquals('children argument', [node2, node3], children); + }, thisContext); + assertArrayEquals('visited nodes', [node2, node3], visitedNodes); + assertArrayEquals('index of visited nodes', [0, 1], indices); +} + +function testForEachDescendant() { + var node1 = new goog.structs.TreeNode(1, null); + var node2 = new goog.structs.TreeNode(2, null); + var node3 = new goog.structs.TreeNode(3, null); + var node4 = new goog.structs.TreeNode(4, null); + node1.addChild(node2); + node2.addChild(node3); + node2.addChild(node4); + + var thisContext = {}; + var visitedNodes = []; + node1.forEachDescendant(function(node) { + assertEquals('value of this', thisContext, this); + visitedNodes.push(node); + }, thisContext); + assertArrayEquals('visited nodes', [node2, node3, node4], visitedNodes); +} + +function testTraverse() { + var node1 = new goog.structs.TreeNode(1, null); + var node2 = new goog.structs.TreeNode(2, null); + var node3 = new goog.structs.TreeNode(3, null); + var node4 = new goog.structs.TreeNode(4, null); + node1.addChild(node2); + node2.addChild(node3); + node2.addChild(node4); + + var thisContext = {}; + var visitedNodes = []; + node1.traverse(function(node) { + assertEquals('value of this', thisContext, this); + visitedNodes.push(node); + }, thisContext); + assertArrayEquals('callback returns nothing => all nodes are visited', + [node1, node2, node3, node4], visitedNodes); + + visitedNodes = []; + node1.traverse(function(node) { + visitedNodes.push(node); + return node != node2; // Cut off at node2. + }); + assertArrayEquals('children of node2 are skipped', + [node1, node2], visitedNodes); +} + +function testAddChild() { + var node1 = new goog.structs.TreeNode(1, null); + var node2 = new goog.structs.TreeNode(2, null); + var node3 = new goog.structs.TreeNode(3, null); + assertArrayEquals('0 children', [], node1.getChildren()); + node1.addChild(node2); + assertArrayEquals('1 child', [node2], node1.getChildren()); + assertEquals('parent is set', node1, node2.getParent()); + node1.addChild(node3); + assertArrayEquals('2 children', [node2, node3], node1.getChildren()); +} + +function testAddChildAt() { + var node1 = new goog.structs.TreeNode(1, null); + var node2 = new goog.structs.TreeNode(2, null); + var node3 = new goog.structs.TreeNode(3, null); + var node4 = new goog.structs.TreeNode(4, null); + var node5 = new goog.structs.TreeNode(5, null); + node1.addChildAt(node2, 0); + assertArrayEquals('add first child', [node2], node1.getChildren()); + assertEquals('parent is set', node1, node2.getParent()); + node1.addChildAt(node3, 0); + assertArrayEquals('add to the front', [node3, node2], + node1.getChildren()); + node1.addChildAt(node4, 1); + assertArrayEquals('add to the middle', [node3, node4, node2], + node1.getChildren()); + node1.addChildAt(node5, 3); + assertArrayEquals('add to the end', [node3, node4, node2, node5], + node1.getChildren()); +} + +function testReplaceChildAt() { + var root = new goog.structs.TreeNode(0, null); + var node1 = new goog.structs.TreeNode(1, null); + root.addChild(node1); + + var node2 = new goog.structs.TreeNode(2, null); + assertEquals('original node', node1, root.replaceChildAt(node2, 0)); + assertEquals('parent is set', root, node2.getParent()); + assertArrayEquals('children are updated', [node2], root.getChildren()); + assertNull('old child node is detached', node1.getParent()); +} + +function testReplaceChild() { + var root = new goog.structs.TreeNode(0, null); + var node1 = new goog.structs.TreeNode(1, null); + root.addChild(node1); + + var node2 = new goog.structs.TreeNode(2, null); + assertEquals('original node', node1, root.replaceChild(node2, node1)); + assertEquals('parent is set', root, node2.getParent()); + assertArrayEquals('children are updated', [node2], root.getChildren()); + assertNull('old child node is detached', node1.getParent()); +} + +function testRemoveChildAt() { + var node1 = new goog.structs.TreeNode(1, null); + var node2 = new goog.structs.TreeNode(2, null); + var node3 = new goog.structs.TreeNode(3, null); + node1.addChild(node2); + node1.addChild(node3); + + assertNull('index too low', node1.removeChildAt(-1)); + assertNull('index too high', node1.removeChildAt(2)); + assertArrayEquals('node1 is intact', [node2, node3], node1.getChildren()); + + assertEquals('remove first child', node2, node1.removeChildAt(0)); + assertArrayEquals('remove from the front', [node3], node1.getChildren()); + assertNull('parent is unset', node2.getParent()); + + assertEquals('remove last child', node3, node1.removeChildAt(0)); + assertArrayEquals('remove last child', [], node1.getChildren()); + assertTrue('node1 became leaf', node1.isLeaf()); +} + +function testRemoveChild() { + var node1 = new goog.structs.TreeNode(1, null); + var node2 = new goog.structs.TreeNode(2, null); + var node3 = new goog.structs.TreeNode(3, null); + node1.addChild(node2); + node1.addChild(node3); + + assertNull('remove null', node1.removeChild(null)); + assertNull('remove non-child', node1.removeChild(node1)); + assertArrayEquals('node1 is intact', [node2, node3], node1.getChildren()); + + assertEquals('remove node3, return value', node3, node1.removeChild(node3)); + assertArrayEquals('node is removed', [node2], node1.getChildren()); +} + +function testRemoveChildren() { + var node1 = new goog.structs.TreeNode(1, null); + var node2 = new goog.structs.TreeNode(2, null); + var node3 = new goog.structs.TreeNode(3, null); + node1.addChild(node2); + node1.addChild(node3); + + node2.removeChildren(); + assertArrayEquals('removing a leaf node\'s children has no effect', [], + node2.getChildren()); + assertEquals('node still has parent', node1, node2.getParent()); + + node1.removeChildren(); + assertArrayEquals('children have been removed', [], node1.getChildren()); + assertNull('children\'s parents have been unset', node2.getParent()); +} + +</script> +</body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/structs/trie.js b/contexts/data/lib/closure-library/closure/goog/structs/trie.js new file mode 100644 index 0000000..bf365b0 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/trie.js @@ -0,0 +1,368 @@ +// Copyright 2007 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Datastructure: Trie. + * + * + * This file provides the implementation of a trie data structure. A trie is a + * data structure that stores key/value pairs in a prefix tree. See: + * http://en.wikipedia.org/wiki/Trie + */ + + +goog.provide('goog.structs.Trie'); + +goog.require('goog.object'); +goog.require('goog.structs'); + + + +/** + * Class for a Trie datastructure. Trie data structures are made out of trees + * of Trie classes. + * + * @param {Object=} opt_trie Optional goog.structs.Trie or Object to initialize + * trie with. + * @constructor + */ +goog.structs.Trie = function(opt_trie) { + /** + * This trie's child nodes. + * @private + * @type {Object.<goog.structs.Trie>} + */ + this.childNodes_ = {}; + + if (opt_trie) { + this.setAll(opt_trie); + } +}; + + +/** + * This trie's value. For the base trie, this will be the value of the + * empty key, if defined. + * @private + * @type {*} + */ +goog.structs.Trie.prototype.value_ = undefined; + + +/** + * Sets the given key/value pair in the trie. O(L), where L is the length + * of the key. + * @param {string} key The key. + * @param {*} value The value. + */ +goog.structs.Trie.prototype.set = function(key, value) { + this.setOrAdd_(key, value, false); +}; + + +/** + * Adds the given key/value pair in the trie. Throw an exception if the key + * already exists in the trie. O(L), where L is the length of the key. + * @param {string} key The key. + * @param {*} value The value. + */ +goog.structs.Trie.prototype.add = function(key, value) { + this.setOrAdd_(key, value, true); +}; + + +/** + * Helper function for set and add. Adds the given key/value pair to + * the trie, or, if the key already exists, sets the value of the key. If + * opt_add is true, then throws an exception if the key already has a value in + * the trie. O(L), where L is the length of the key. + * @param {string} key The key. + * @param {*} value The value. + * @param {boolean=} opt_add Throw exception if key is already in the trie. + * @private + */ +goog.structs.Trie.prototype.setOrAdd_ = function(key, value, opt_add) { + var node = this; + for (var characterPosition = 0; characterPosition < key.length; + characterPosition++) { + var currentCharacter = key.charAt(characterPosition); + if (!node.childNodes_[currentCharacter]) { + node.childNodes_[currentCharacter] = new goog.structs.Trie(); + } + node = node.childNodes_[currentCharacter]; + } + if (opt_add && node.value_ !== undefined) { + throw Error('The collection already contains the key "' + key + '"'); + } else { + node.value_ = value; + } +}; + + +/** + * Adds multiple key/value pairs from another goog.structs.Trie or Object. + * O(N) where N is the number of nodes in the trie. + * @param {Object|goog.structs.Trie} trie Object containing the data to add. + */ +goog.structs.Trie.prototype.setAll = function(trie) { + var keys = goog.structs.getKeys(trie); + var values = goog.structs.getValues(trie); + + for (var i = 0; i < keys.length; i++) { + this.set(keys[i], values[i]); + } +}; + + +/** + * Retrieves a value from the trie given a key. O(L), where L is the length of + * the key. + * @param {string} key The key to retrieve from the trie. + * @return {*} The value of the key in the trie, or undefined if the trie does + * not contain this key. + */ +goog.structs.Trie.prototype.get = function(key) { + var node = this; + for (var characterPosition = 0; characterPosition < key.length; + characterPosition++) { + var currentCharacter = key.charAt(characterPosition); + if (!node.childNodes_[currentCharacter]) { + return undefined; + } + node = node.childNodes_[currentCharacter]; + } + return node.value_; +}; + + +/** + * Retrieves all values from the trie that correspond to prefixes of the given + * input key. O(L), where L is the length of the key. + * + * @param {string} key The key to use for lookup. The given key as well as all + * prefixes of the key are retrieved. + * @param {?number=} opt_keyStartIndex Optional position in key to start lookup + * from. Defaults to 0 if not specified. + * @return {Object} Map of end index of matching prefixes and corresponding + * values. Empty if no match found. + */ +goog.structs.Trie.prototype.getKeyAndPrefixes = function(key, + opt_keyStartIndex) { + var node = this; + var matches = {}; + var characterPosition = opt_keyStartIndex || 0; + + if (node.value_ !== undefined) { + matches[characterPosition] = node.value_; + } + + for (; characterPosition < key.length; characterPosition++) { + var currentCharacter = key.charAt(characterPosition); + if (!(currentCharacter in node.childNodes_)) { + break; + } + node = node.childNodes_[currentCharacter]; + if (node.value_ !== undefined) { + matches[characterPosition] = node.value_; + } + } + + return matches; +}; + + +/** + * Gets the values of the trie. Not returned in any reliable order. O(N) where + * N is the number of nodes in the trie. Calls getValuesInternal_. + * @return {Array} The values in the trie. + */ +goog.structs.Trie.prototype.getValues = function() { + var allValues = []; + this.getValuesInternal_(allValues); + return allValues; +}; + + +/** + * Gets the values of the trie. Not returned in any reliable order. O(N) where + * N is the number of nodes in the trie. Builds the values as it goes. + * @param {Array.<string>} allValues Array to place values into. + * @private + */ +goog.structs.Trie.prototype.getValuesInternal_ = function(allValues) { + if (this.value_ !== undefined) { + allValues.push(this.value_); + } + for (var childNode in this.childNodes_) { + this.childNodes_[childNode].getValuesInternal_(allValues); + } +}; + + +/** + * Gets the keys of the trie. Not returned in any reliable order. O(N) where + * N is the number of nodes in the trie (or prefix subtree). + * @param {string=} opt_prefix Find only keys with this optional prefix. + * @return {Array} The keys in the trie. + */ +goog.structs.Trie.prototype.getKeys = function(opt_prefix) { + var allKeys = []; + if (opt_prefix) { + // Traverse to the given prefix, then call getKeysInternal_ to dump the + // keys below that point. + var node = this; + for (var characterPosition = 0; characterPosition < opt_prefix.length; + characterPosition++) { + var currentCharacter = opt_prefix.charAt(characterPosition); + if (!node.childNodes_[currentCharacter]) { + return []; + } + node = node.childNodes_[currentCharacter]; + } + node.getKeysInternal_(opt_prefix, allKeys); + } else { + this.getKeysInternal_('', allKeys); + } + return allKeys; +}; + + +/** + * Private method to get keys from the trie. Builds the keys as it goes. + * @param {string} keySoFar The partial key (prefix) traversed so far. + * @param {Array} allKeys The partially built array of keys seen so far. + * @private + */ +goog.structs.Trie.prototype.getKeysInternal_ = function(keySoFar, allKeys) { + if (this.value_ !== undefined) { + allKeys.push(keySoFar); + } + for (var childNode in this.childNodes_) { + this.childNodes_[childNode].getKeysInternal_(keySoFar + childNode, allKeys); + } +}; + + +/** + * Checks to see if a certain key is in the trie. O(L), where L is the length + * of the key. + * @param {string} key A key that may be in the trie. + * @return {boolean} Whether the trie contains key. + */ +goog.structs.Trie.prototype.containsKey = function(key) { + return this.get(key) !== undefined; +}; + + +/** + * Checks to see if a certain value is in the trie. Worst case is O(N) where + * N is the number of nodes in the trie. + * @param {*} value A value that may be in the trie. + * @return {boolean} Whether the trie contains the value. + */ +goog.structs.Trie.prototype.containsValue = function(value) { + if (this.value_ === value) { + return true; + } + for (var childNode in this.childNodes_) { + if (this.childNodes_[childNode].containsValue(value)) { + return true; + } + } + return false; +}; + + +/** + * Completely empties a trie of all keys and values. ~O(1) + */ +goog.structs.Trie.prototype.clear = function() { + this.childNodes_ = {}; + this.value_ = undefined; +}; + + +/** + * Removes a key from the trie or throws an exception if the key is not in the + * trie. O(L), where L is the length of the key. + * @param {string} key A key that should be removed from the trie. + * @return {*} The value whose key was removed. + */ +goog.structs.Trie.prototype.remove = function(key) { + var node = this; + var parents = []; + for (var characterPosition = 0; characterPosition < key.length; + characterPosition++) { + var currentCharacter = key.charAt(characterPosition); + if (!node.childNodes_[currentCharacter]) { + throw Error('The collection does not have the key "' + key + '"'); + } + + // Archive the current parent and child name (key in childNodes_) so that + // we may remove the following node and its parents if they are empty. + parents.push([node, currentCharacter]); + + node = node.childNodes_[currentCharacter]; + } + var oldValue = node.value_; + delete node.value_; + + while (parents.length > 0) { + var currentParentAndCharacter = parents.pop(); + var currentParent = currentParentAndCharacter[0]; + var currentCharacter = currentParentAndCharacter[1]; + if (goog.object.isEmpty( + currentParent.childNodes_[currentCharacter].childNodes_)) { + // If we have no child nodes, then remove this node. + delete currentParent.childNodes_[currentCharacter]; + } else { + // No point of traversing back any further, since we can't remove this + // path. + break; + } + } + return oldValue; +}; + + +/** + * Clones a trie and returns a new trie. O(N), where N is the number of nodes + * in the trie. + * @return {goog.structs.Trie} A new goog.structs.Trie with the same key value + * pairs. + */ +goog.structs.Trie.prototype.clone = function() { + return new goog.structs.Trie(this); +}; + + +/** + * Returns the number of key value pairs in the trie. O(N), where N is the + * number of nodes in the trie. + * TODO: This could be optimized by storing a weight (count below) in every + * node. + * @return {number} The number of pairs. + */ +goog.structs.Trie.prototype.getCount = function() { + return goog.structs.getCount(this.getValues()); +}; + + +/** + * Returns true if this trie contains no elements. ~O(1). + * @return {boolean} True iff this trie contains no elements. + */ +goog.structs.Trie.prototype.isEmpty = function() { + return this.value_ === undefined && goog.structs.isEmpty(this.childNodes_); +}; diff --git a/contexts/data/lib/closure-library/closure/goog/structs/trie_test.html b/contexts/data/lib/closure-library/closure/goog/structs/trie_test.html new file mode 100644 index 0000000..3b180a5 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/structs/trie_test.html @@ -0,0 +1,378 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright 2007 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> +<!-- +--> +<head> +<meta http-equiv="X-UA-Compatible" content="IE=edge"> +<title>Closure Unit Tests - goog.structs.Trie</title> +</script> +<script src="../base.js"></script> +<script> + goog.require('goog.object'); + goog.require('goog.structs'); + goog.require('goog.structs.Trie'); + goog.require('goog.testing.jsunit'); +</script> +</head> +<body> +<script> + +function makeTrie() { + var trie = new goog.structs.Trie(); + trie.add('hello', 1); + trie.add('hi', 'howdy'); + trie.add('', 'an empty string key'); + trie.add('empty value', ''); + trie.add('zero', 0); + trie.add('object', {}); + trie.add('null', null); + trie.add('hello, world', 2); + trie.add('world', {}); + return trie; +} + +function checkTrie(trie) { + assertEquals('get, should be 1', trie.get('hello'), 1); + assertEquals('get, should be "howdy"', trie.get('hi'), 'howdy'); + assertEquals('get, should be "an empty string key"', trie.get(''), + 'an empty string key'); + assertEquals('get, should be ""', trie.get('empty value'), ''); + assertEquals('get, should be ""', typeof trie.get('empty value'), 'string'); + assertEquals('get, should be an object', typeof trie.get('object'), 'object'); + assertEquals('get, should be 0', trie.get('zero'), 0); + assertEquals('get "null", should be null', trie.get('null'), null); + assertEquals('get, should be 2', trie.get('hello, world'), 2); + assertEquals('get, should be an object', typeof trie.get('world'), 'object'); +} + +function testTrieFormation() { + var t = makeTrie(); + checkTrie(t); +} + +function testFailureOfMultipleAdds() { + var t = new goog.structs.Trie(); + t.add('hello', 'testing'); + assertThrows('Error should be thrown when same key added twice.', function() { + t.add('hello', 'test'); + }); + + t = new goog.structs.Trie(); + t.add('null', null); + assertThrows('Error should be thrown when same key added twice.', function() { + t.add('null', 'hi!'); + }); + + t = new goog.structs.Trie(); + t.add('null', 'blah'); + assertThrows('Error should be thrown when same key added twice.', function() { + t.add('null', null); + }); +} + +function testTrieClone() { + var trieOne = makeTrie(); + var trieTwo = new goog.structs.Trie(trieOne); + checkTrie(trieTwo); +} + +function testTrieFromObject() { + var someObject = {'hello' : 1, + 'hi' : 'howdy', + '' : 'an empty string key', + 'empty value' : '', + 'object' : {}, + 'zero' : 0, + 'null' : null, + 'hello, world' : 2, + 'world' : {}}; + var trie = new goog.structs.Trie(someObject); + checkTrie(trie); +} + +function testTrieGetValues() { + var trie = makeTrie(); + var values = trie.getValues(); + assertTrue('getValues, should contain "howdy"', + goog.object.contains(values, 'howdy')); + assertTrue('getValues, should contain 1', goog.object.contains(values, 1)); + assertTrue('getValues, should contain 0', goog.object.contains(values, 0)); + assertTrue('getValues, should contain ""', goog.object.contains(values, '')); + assertTrue('getValues, should contain null', + goog.object.contains(values, null)); + assertEquals('goog.structs.getCount(getValues()) should be 9', + goog.structs.getCount(values), 9); +} + +function testTrieGetKeys() { + var trie = makeTrie(); + var keys = trie.getKeys(); + assertTrue('getKeys, should contain "hello"', + goog.object.contains(keys, 'hello')); + assertTrue('getKeys, should contain "empty value"', + goog.object.contains(keys, 'empty value')); + assertTrue('getKeys, should contain ""', goog.object.contains(keys, '')); + assertTrue('getKeys, should contain "zero"', + goog.object.contains(keys, 'zero')); + assertEquals('goog.structs.getCount(getKeys()) should be 9', + goog.structs.getCount(keys), 9); +} + + +function testTrieCount() { + var trieOne = makeTrie(); + var trieTwo = new goog.structs.Trie(); + assertEquals('count, should be 9', trieOne.getCount(), 9); + assertEquals('count, should be 0', trieTwo.getCount(), 0); +} + +function testRemoveKeyFromTrie() { + var trie = new goog.structs.Trie(); + trie.add('key1', 'value1'); + trie.add('key2', 'value2'); + trie.add('ke', 'value3'); + trie.add('zero', 0); + trie.remove('key2'); + assertEquals('get "key1", should be "value1"', trie.get('key1'), 'value1'); + assertUndefined('get "key2", should be undefined', trie.get('key2')); + trie.remove('zero'); + assertUndefined('get "zero", should be undefined', trie.get('zero')); + trie.remove('ke'); + assertUndefined('get "ke", should be undefined', trie.get('ke')); + assertEquals('get "key1", should be "value1"', trie.get('key1'), 'value1'); + trie.add('a', 'value4'); + assertTrue('testing internal structure, a should be a child', + 'a' in trie.childNodes_); + trie.remove('a'); + assertFalse('testing internal structure, a should no longer be a child', + 'a' in trie.childNodes_); + + trie.add('xyza', 'value'); + trie.remove('xyza', 'value'); + assertFalse('Should not have "x"', 'x' in trie.childNodes_); + + trie.add('xyza', null); + assertTrue('Should have "x"', 'x' in trie.childNodes_); + trie.remove('xyza'); + assertFalse('Should not have "x"', 'x' in trie.childNodes_); + + trie.add('xyza', 'value'); + trie.add('xb', 'value'); + trie.remove('xyza'); + assertTrue('get "x" should be defined', 'x' in trie.childNodes_); + assertFalse('get "y" should be undefined', + 'y' in trie.childNodes_['x'].childNodes_); +} + +function testRemoveKeyFromTrieWithNulls() { + var trie = new goog.structs.Trie(); + trie.add('key1', null); + trie.add('key2', 'value2'); + trie.add('ke', 'value3'); + trie.add('zero', 0); + trie.remove('key2'); + assertEquals('get "key1", should be null', trie.get('key1'), null); + assertUndefined('get "key2", should be undefined', trie.get('key2')); + trie.remove('zero'); + assertUndefined('get "zero", should be undefined', trie.get('zero')); + trie.remove('ke'); + assertUndefined('get "ke", should be undefined', trie.get('ke')); + assertEquals('get "key1", should be null', trie.get('key1'), null); + trie.add('a', 'value4'); + assertTrue('testing internal structure, a should be a child', + 'a' in trie.childNodes_); + trie.remove('a'); + assertFalse('testing internal structure, a should no longer be a child', + 'a' in trie.childNodes_); + + trie.add('xyza', null); + trie.add('xb', 'value'); + trie.remove('xyza'); + assertTrue('Should have "x"', 'x' in trie.childNodes_); + assertFalse('Should not have "y"', + 'y' in trie.childNodes_['x'].childNodes_); +} + +function testRemoveKeyException() { + var trie = new goog.structs.Trie(); + trie.add('abcdefg', 'value'); + trie.add('abcz', 'value'); + trie.add('abc', 'value'); + + assertThrows('Remove should throw an error on removal of non-existent key', + function() { + trie.remove('abcdefge'); + }); +} + +function testTrieIsEmpty() { + var trieOne = new goog.structs.Trie(); + var trieTwo = makeTrie(); + assertTrue('isEmpty, should be empty', trieOne.isEmpty()); + assertFalse('isEmpty, should not be empty', trieTwo.isEmpty()); + trieOne.add('', 1); + assertFalse('isEmpty, should not be empty', trieTwo.isEmpty()); + trieOne.remove(''); + assertTrue('isEmpty, should be empty', trieOne.isEmpty()); + trieOne.add('', 1); + trieOne.add('a', 1); + trieOne.remove('a'); + assertFalse('isEmpty, should not be empty', trieOne.isEmpty()); + trieOne.remove(''); + assertTrue('isEmpty, should be empty', trieOne.isEmpty()); + trieOne.add('', 1); + trieOne.add('a', 1); + trieOne.remove(''); + assertFalse('isEmpty, should not be empty', trieOne.isEmpty()); + trieOne.remove('a'); + assertTrue('isEmpty, should be empty', trieOne.isEmpty()); +} + +function testTrieClear() { + var trie = new goog.structs.Trie(); + trie.add('key1', 'value1'); + trie.add('key2', 'value2'); + trie.add('key3', null); + trie.clear(); + assertUndefined('get key1, should be undefined', trie.get('key1')); + assertUndefined('get key2, should be undefined', trie.get('key2')); + assertUndefined('get key3, should be undefined', trie.get('key3')); +} + +function testTrieContainsKey() { + var trie = makeTrie(); + assertTrue('containsKey, should contain "hello"', trie.containsKey('hello')); + assertTrue('containsKey, should contain "hi"', trie.containsKey('hi')); + assertTrue('containsKey, should contain ""', trie.containsKey('')); + assertTrue('containsKey, should contain "empty value"', + trie.containsKey('empty value')); + assertTrue('containsKey, should contain "object"', + trie.containsKey('object')); + assertTrue('containsKey, should contain "zero"', trie.containsKey('zero')); + assertTrue('containsKey, should contain "null"', trie.containsKey('null')); + assertFalse('containsKey, should not contain "blah"', + trie.containsKey('blah')); + trie.remove(''); + trie.remove('hi'); + trie.remove('zero'); + trie.remove('null'); + assertFalse('containsKey, should not contain "zero"', + trie.containsKey('zero')); + assertFalse('containsKey, should not contain ""', trie.containsKey('')); + assertFalse('containsKey, should not contain "hi"', trie.containsKey('hi')); + assertFalse('containsKey, should not contain "null"', + trie.containsKey('null')); +} + +function testTrieContainsValue() { + var trie = makeTrie(); + assertTrue('containsValue, should be true, should contain 1', + trie.containsValue(1)); + assertTrue('containsValue, should be true, should contain "howdy"', + trie.containsValue('howdy')); + assertTrue('containsValue, should be true, should contain ""', + trie.containsValue('')); + assertTrue('containsValue, should be true, should contain 0', + trie.containsValue(0)); + assertTrue('containsValue, should be true, should contain null', + trie.containsValue(null)); + assertTrue('containsValue, should be true, should ' + + 'contain "an empty string key"', + trie.containsValue('an empty string key')); + assertFalse('containsValue, should be false, should not contain "blah"', + trie.containsValue('blah')); + trie.remove('empty value'); + trie.remove('zero'); + assertFalse('containsValue, should be false, should not contain 0', + trie.containsValue(0)); + assertFalse('containsValue, should be false, should not contain ""', + trie.containsValue('')); +} + +function testTrieHandlingOfEmptyStrings() { + var trie = new goog.structs.Trie(); + assertEquals('get, should be undefined', trie.get(''), undefined); + assertFalse('containsValue, should be false', trie.containsValue('')); + assertFalse('containsKey, should be false', trie.containsKey('')); + trie.add('', 'test'); + trie.add('test2', ''); + assertTrue('containsValue, should be true', trie.containsValue('')); + assertTrue('containsKey, should be true', trie.containsKey('')); + assertEquals('get, should be "test"', trie.get(''), 'test'); + assertEquals('get, should be ""', trie.get('test2'), ''); + trie.remove(''); + trie.remove('test2'); + assertEquals('get, should be undefined', trie.get(''), undefined); + assertFalse('containsValue, should be false', trie.containsValue('')); + assertFalse('containsKey, should be false', trie.containsKey('')); +} + +function testPrefixOptionOnGetKeys() { + var trie = new goog.structs.Trie(); + trie.add('abcdefg', 'one'); + trie.add('abcdefghijk', 'two'); + trie.add('abcde', 'three'); + trie.add('abcq', null); + trie.add('abc', 'four'); + trie.add('xyz', 'five'); + assertEquals('getKeys, should be 1', trie.getKeys('xy').length, 1); + assertEquals('getKeys, should be 1', trie.getKeys('xyz').length, 1); + assertEquals('getKeys, should be 1', trie.getKeys('x').length, 1); + assertEquals('getKeys, should be 4', trie.getKeys('abc').length, 5); + assertEquals('getKeys, should be 2', trie.getKeys('abcdef').length, 2); + assertEquals('getKeys, should be 0', trie.getKeys('abcdefgi').length, 0); +} + +function testGetKeyAndPrefixes() { + var trie = makeTrie(); + // Note: trie has one of its keys as '' + assertEquals('getKeyAndPrefixes, should be 2', + 2, + goog.object.getCount(trie.getKeyAndPrefixes('world'))); + assertEquals('getKeyAndPrefixes, should be 2', + 2, + goog.object.getCount(trie.getKeyAndPrefixes('hello'))); + assertEquals('getKeyAndPrefixes, should be 2', + 2, + goog.object.getCount(trie.getKeyAndPrefixes('hello,'))); + assertEquals('getKeyAndPrefixes, should be 3', + 3, + goog.object.getCount(trie.getKeyAndPrefixes('hello, world'))); + assertEquals('getKeyAndPrefixes, should be 1', + 1, + goog.object.getCount(trie.getKeyAndPrefixes('hell'))); +} + +function testGetKeyAndPrefixesStartIndex() { + var trie = new goog.structs.Trie(); + trie.add('abcdefg', 'one'); + trie.add('bcdefg', 'two'); + trie.add('abcdefghijk', 'three'); + trie.add('abcde', 'four'); + trie.add('abcq', null); + trie.add('q', null); + trie.add('abc', 'five'); + trie.add('xyz', 'six'); + assertEquals('getKeyAndPrefixes, should be 3', + 3, + goog.object.getCount(trie.getKeyAndPrefixes('abcdefg', 0))); + assertEquals('getKeyAndPrefixes, should be 1', + 1, + goog.object.getCount(trie.getKeyAndPrefixes('abcdefg', 1))); + assertEquals('getKeyAndPrefixes, should be 1', + 1, + goog.object.getCount(trie.getKeyAndPrefixes('abcq', 3))); + assertEquals('getKeyAndPrefixes, should be 0', + 0, + goog.object.getCount(trie.getKeyAndPrefixes('abcd', 3))); +} + +</script> +</body> +</html> |