d3_rails 2.8.0 → 2.8.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/.DS_Store +0 -0
  2. data/README.md +27 -5
  3. data/lib/d3_rails/version.rb +1 -1
  4. data/vendor/.DS_Store +0 -0
  5. data/vendor/assets/.DS_Store +0 -0
  6. data/vendor/assets/javascripts/.DS_Store +0 -0
  7. data/vendor/assets/javascripts/d3.v2.js +99 -80
  8. data/vendor/assets/javascripts/morris.js +1 -0
  9. data/vendor/assets/javascripts/morris/.DS_Store +0 -0
  10. data/vendor/assets/javascripts/morris/Makefile +10 -0
  11. data/vendor/assets/javascripts/morris/README.md +87 -0
  12. data/vendor/assets/javascripts/morris/examples/_template.html +18 -0
  13. data/vendor/assets/javascripts/morris/examples/days.html +36 -0
  14. data/vendor/assets/javascripts/morris/examples/decimal.html +31 -0
  15. data/vendor/assets/javascripts/morris/examples/lib/example.css +13 -0
  16. data/vendor/assets/javascripts/morris/examples/lib/example.js +4 -0
  17. data/vendor/assets/javascripts/morris/examples/lib/prettify.css +1 -0
  18. data/vendor/assets/javascripts/morris/examples/lib/prettify.js +28 -0
  19. data/vendor/assets/javascripts/morris/examples/months-no-smooth.html +37 -0
  20. data/vendor/assets/javascripts/morris/examples/negative.html +35 -0
  21. data/vendor/assets/javascripts/morris/examples/non-date.html +36 -0
  22. data/vendor/assets/javascripts/morris/examples/quarters.html +53 -0
  23. data/vendor/assets/javascripts/morris/examples/timestamps.html +37 -0
  24. data/vendor/assets/javascripts/morris/examples/weeks.html +52 -0
  25. data/vendor/assets/javascripts/morris/morris.coffee +444 -0
  26. data/vendor/assets/javascripts/morris/morris.js +493 -0
  27. data/vendor/assets/javascripts/morris/morris.min.js +1 -0
  28. data/vendor/assets/javascripts/tesseract.js +1 -0
  29. data/vendor/assets/javascripts/tesseract/.gitignore +2 -0
  30. data/vendor/assets/javascripts/tesseract/LICENSE +12 -0
  31. data/vendor/assets/javascripts/tesseract/Makefile +48 -0
  32. data/vendor/assets/javascripts/tesseract/README.md +11 -0
  33. data/vendor/assets/javascripts/tesseract/index.js +1 -0
  34. data/vendor/assets/javascripts/tesseract/lib/dart/AUTHORS +9 -0
  35. data/vendor/assets/javascripts/tesseract/lib/dart/LICENSE +25 -0
  36. data/vendor/assets/javascripts/tesseract/lib/dart/dual_pivot_quicksort.dart +342 -0
  37. data/vendor/assets/javascripts/tesseract/package.json +11 -0
  38. data/vendor/assets/javascripts/tesseract/src/array.js +32 -0
  39. data/vendor/assets/javascripts/tesseract/src/bisect.js +44 -0
  40. data/vendor/assets/javascripts/tesseract/src/filter.js +19 -0
  41. data/vendor/assets/javascripts/tesseract/src/heap.js +44 -0
  42. data/vendor/assets/javascripts/tesseract/src/heapselect.js +36 -0
  43. data/vendor/assets/javascripts/tesseract/src/identity.js +3 -0
  44. data/vendor/assets/javascripts/tesseract/src/insertionsort.js +18 -0
  45. data/vendor/assets/javascripts/tesseract/src/null.js +3 -0
  46. data/vendor/assets/javascripts/tesseract/src/package.js +14 -0
  47. data/vendor/assets/javascripts/tesseract/src/permute.js +8 -0
  48. data/vendor/assets/javascripts/tesseract/src/quicksort.js +282 -0
  49. data/vendor/assets/javascripts/tesseract/src/reduce.js +19 -0
  50. data/vendor/assets/javascripts/tesseract/src/tesseract.js +663 -0
  51. data/vendor/assets/javascripts/tesseract/src/version.js +1 -0
  52. data/vendor/assets/javascripts/tesseract/src/zero.js +3 -0
  53. data/vendor/assets/javascripts/tesseract/tesseract.js +1177 -0
  54. data/vendor/assets/javascripts/tesseract/tesseract.min.js +1 -0
  55. data/vendor/assets/javascripts/tesseract/test/benchmark.js +177 -0
  56. data/vendor/assets/javascripts/tesseract/test/bisect-test.js +206 -0
  57. data/vendor/assets/javascripts/tesseract/test/heap-test.js +44 -0
  58. data/vendor/assets/javascripts/tesseract/test/permute-test.js +51 -0
  59. data/vendor/assets/javascripts/tesseract/test/select-test.js +63 -0
  60. data/vendor/assets/javascripts/tesseract/test/sort-test.js +83 -0
  61. data/vendor/assets/javascripts/tesseract/test/tesseract-test.js +655 -0
  62. data/vendor/assets/javascripts/tesseract/test/version-test.js +16 -0
  63. metadata +63 -8
@@ -0,0 +1 @@
1
+ ((function(){var a,b,c=function(a,b){return function(){return a.apply(b,arguments)}};a=jQuery,b={},b.Line=function(){function d(d){this.updateHilight=c(this.updateHilight,this),this.hilight=c(this.hilight,this),this.updateHover=c(this.updateHover,this),this.transY=c(this.transY,this),this.transX=c(this.transX,this);if(!(this instanceof b.Line))return new b.Line(d);typeof d.element=="string"?this.el=a(document.getElementById(d.element)):this.el=a(d.element),this.options=a.extend({},this.defaults,d);if(this.options.data===void 0||this.options.data.length===0)return;this.el.addClass("graph-initialised"),this.precalc(),this.redraw()}return d.prototype.defaults={lineWidth:3,pointSize:4,lineColors:["#0b62a4","#7A92A3","#4da74d","#afd8f8","#edc240","#cb4b4b","#9440ed"],ymax:"auto",ymin:"auto 0",marginTop:25,marginRight:25,marginBottom:30,marginLeft:25,numLines:5,gridLineColor:"#aaa",gridTextColor:"#888",gridTextSize:12,gridStrokeWidth:.5,hoverPaddingX:10,hoverPaddingY:5,hoverMargin:10,hoverFillColor:"#fff",hoverBorderColor:"#ccc",hoverBorderWidth:2,hoverOpacity:.95,hoverLabelColor:"#444",hoverFontSize:12,smooth:!0,hideHover:!1,parseTime:!0,units:"",dateFormat:function(a){return(new Date(a)).toString()}},d.prototype.precalc=function(){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q=this;this.options.data.sort(function(a,b){return(a[q.options.xkey]<b[q.options.xkey])-(b[q.options.xkey]<a[q.options.xkey])}),this.columnLabels=a.map(this.options.data,function(a){return a[q.options.xkey]}),this.seriesLabels=this.options.labels,this.series=[],m=this.options.ykeys;for(h=0,k=m.length;h<k;h++){e=m[h],c=[],n=this.options.data;for(i=0,l=n.length;i<l;i++)b=n[i],c.push(b[e]);this.series.push(c)}return this.options.parseTime?this.xvals=a.map(this.columnLabels,function(a){return q.parseYear(a)}):this.xvals=function(){p=[];for(var a=o=this.columnLabels.length-1;o<=0?a<=0:a>=0;o<=0?a++:a--)p.push(a);return p}.apply(this),this.options.parseTime&&(this.columnLabels=a.map(this.columnLabels,function(a){return typeof a=="number"?q.options.dateFormat(a):a})),this.xmin=Math.min.apply(null,this.xvals),this.xmax=Math.max.apply(null,this.xvals),this.xmin===this.xmax&&(this.xmin-=1,this.xmax+=1),typeof this.options.ymax=="string"&&this.options.ymax.slice(0,4)==="auto"&&(f=Math.max.apply(null,Array.prototype.concat.apply([],this.series)),this.options.ymax.length>5?this.options.ymax=Math.max(parseInt(this.options.ymax.slice(5),10),f):this.options.ymax=f),typeof this.options.ymin=="string"&&this.options.ymin.slice(0,4)==="auto"&&(g=Math.min.apply(null,Array.prototype.concat.apply([],this.series)),this.options.ymin.length>5?this.options.ymin=Math.min(parseInt(this.options.ymin.slice(5),10),g):this.options.ymin=g),this.pointGrow=Raphael.animation({r:this.options.pointSize+3},25,"linear"),this.pointShrink=Raphael.animation({r:this.options.pointSize},25,"linear"),this.elementWidth=null,this.elementHeight=null,this.prevHilight=null,this.el.mousemove(function(a){return q.updateHilight(a.pageX)}),this.options.hideHover&&this.el.mouseout(function(a){return q.hilight(null)}),d=function(a){var b;return b=a.originalEvent.touches[0]||a.originalEvent.changedTouches[0],q.updateHilight(b.pageX),b},this.el.bind("touchstart",d),this.el.bind("touchmove",d),this.el.bind("touchend",d)},d.prototype.calc=function(){var b,c,d,e,f,g,h,i,j=this;e=this.el.width(),b=this.el.height();if(this.elementWidth!==e||this.elementHeight!==b){this.maxYLabelWidth=Math.max(this.measureText(this.options.ymin+this.options.units,this.options.gridTextSize).width,this.measureText(this.options.ymax+this.options.units,this.options.gridTextSize).width),this.left=this.maxYLabelWidth+this.options.marginLeft,this.width=this.el.width()-this.left-this.options.marginRight,this.height=this.el.height()-this.options.marginTop-this.options.marginBottom,this.dx=this.width/(this.xmax-this.xmin),this.dy=this.height/(this.options.ymax-this.options.ymin),this.columns=function(){var a,b,c,d;c=this.xvals,d=[];for(a=0,b=c.length;a<b;a++)f=c[a],d.push(this.transX(f));return d}.call(this),this.seriesCoords=[],i=this.series;for(g=0,h=i.length;g<h;g++)c=i[g],d=[],a.each(c,function(a,b){return b===null?d.push(null):d.push({x:j.columns[a],y:j.transY(b)})}),this.seriesCoords.push(d);return this.hoverMargins=a.map(this.columns.slice(1),function(a,b){return(a+j.columns[b])/2})}},d.prototype.transX=function(a){return this.xvals.length===1?this.left+this.width/2:this.left+(a-this.xmin)*this.dx},d.prototype.transY=function(a){return this.options.marginTop+this.height-(a-this.options.ymin)*this.dy},d.prototype.redraw=function(){return this.el.empty(),this.r=new Raphael(this.el[0]),this.calc(),this.drawGrid(),this.drawSeries(),this.drawHover(),this.hilight(this.options.hideHover?null:0)},d.prototype.drawGrid=function(){var a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p;o=(this.options.ymax-this.options.ymin)/(this.options.numLines-1),a=Math.ceil(this.options.ymin/o)*o,f=Math.floor(this.options.ymax/o)*o;for(g=a;a<=f?g<=f:g>=f;g+=o)i=Math.floor(g),n=this.transY(i),this.r.text(this.left-this.options.marginLeft/2,n,this.commas(i)+this.options.units).attr("font-size",this.options.gridTextSize).attr("fill",this.options.gridTextColor).attr("text-anchor","end"),this.r.path("M"+this.left+","+n+"H"+(this.left+this.width)).attr("stroke",this.options.gridLineColor).attr("stroke-width",this.options.gridStrokeWidth);h=null,l=50,this.options.parseTime?(j=(new Date(this.xmin)).getFullYear(),k=(new Date(this.xmax)).getFullYear()):(j=this.xmin,k=this.xmax),p=[];for(b=j;j<=k?b<=k:b>=k;j<=k?b++:b--){if(this.options.parseTime){m=(new Date(b,0,1)).getTime();if(m<this.xmin)continue}else m=b;e=this.options.parseTime?b:this.columnLabels[this.columnLabels.length-b-1],c=this.r.text(this.transX(m),this.options.marginTop+this.height+this.options.marginBottom/2,e).attr("font-size",this.options.gridTextSize).attr("fill",this.options.gridTextColor),d=c.getBBox(),h===null||h<=d.x?p.push(h=d.x+d.width+l):p.push(c.remove())}return p},d.prototype.drawSeries=function(){var a,b,c,d,e,f,g,h;for(d=f=this.seriesCoords.length-1;f<=0?d<=0:d>=0;f<=0?d++:d--)c=this.seriesCoords[d],c.length>1&&(e=this.createPath(c,this.options.marginTop,this.left,this.options.marginTop+this.height,this.left+this.width),this.r.path(e).attr("stroke",this.options.lineColors[d]).attr("stroke-width",this.options.lineWidth));this.seriesPoints=function(){var a,b;b=[];for(d=0,a=this.seriesCoords.length-1;0<=a?d<=a:d>=a;0<=a?d++:d--)b.push([]);return b}.call(this),h=[];for(d=g=this.seriesCoords.length-1;g<=0?d<=0:d>=0;g<=0?d++:d--)h.push(function(){var c,e,f,g;f=this.seriesCoords[d],g=[];for(c=0,e=f.length;c<e;c++)a=f[c],a===null?b=null:b=this.r.circle(a.x,a.y,this.options.pointSize).attr("fill",this.options.lineColors[d]).attr("stroke-width",1).attr("stroke","#ffffff"),g.push(this.seriesPoints[d].push(b));return g}.call(this));return h},d.prototype.createPath=function(b,c,d,e,f){var g,h,i,j,k,l,m,n,o,p,q,r,s,t;o="",h=a.map(b,function(a){return a});if(this.options.smooth){j=this.gradients(h);for(k=0,t=h.length-1;0<=t?k<=t:k>=t;0<=t?k++:k--)g=h[k],k===0?o+="M"+g.x+","+g.y:(i=j[k],m=h[k-1],n=j[k-1],l=(g.x-m.x)/4,p=m.x+l,r=Math.min(e,m.y+l*n),q=g.x-l,s=Math.min(e,g.y-l*i),o+="C"+p+","+r+","+q+","+s+","+g.x+","+g.y)}else o="M"+a.map(h,function(a){return""+a.x+","+a.y}).join("L");return o},d.prototype.gradients=function(b){return a.map(b,function(a,c){return c===0?(b[1].y-a.y)/(b[1].x-a.x):c===b.length-1?(a.y-b[c-1].y)/(a.x-b[c-1].x):(b[c+1].y-b[c-1].y)/(b[c+1].x-b[c-1].x)})},d.prototype.drawHover=function(){var a,b,c,d;this.hoverHeight=this.options.hoverFontSize*1.5*(this.series.length+1),this.hover=this.r.rect(-10,-this.hoverHeight/2-this.options.hoverPaddingY,20,this.hoverHeight+this.options.hoverPaddingY*2,10).attr("fill",this.options.hoverFillColor).attr("stroke",this.options.hoverBorderColor).attr("stroke-width",this.options.hoverBorderWidth).attr("opacity",this.options.hoverOpacity),this.xLabel=this.r.text(0,this.options.hoverFontSize*.75-this.hoverHeight/2,"").attr("fill",this.options.hoverLabelColor).attr("font-weight","bold").attr("font-size",this.options.hoverFontSize),this.hoverSet=this.r.set(),this.hoverSet.push(this.hover),this.hoverSet.push(this.xLabel),this.yLabels=[],d=[];for(a=0,c=this.series.length-1;0<=c?a<=c:a>=c;0<=c?a++:a--)b=this.r.text(0,this.options.hoverFontSize*1.5*(a+1.5)-this.hoverHeight/2,"").attr("fill",this.options.lineColors[a]).attr("font-size",this.options.hoverFontSize),this.yLabels.push(b),d.push(this.hoverSet.push(b));return d},d.prototype.updateHover=function(b){var c,d,e,f,g,h=this;this.hoverSet.show(),this.xLabel.attr("text",this.columnLabels[b]);for(c=0,g=this.series.length-1;0<=g?c<=g:c>=g;0<=g?c++:c--)this.yLabels[c].attr("text",""+this.seriesLabels[c]+": "+this.commas(this.series[c][b])+this.options.units);return d=Math.max.apply(null,a.map(this.yLabels,function(a){return a.getBBox().width})),d=Math.max(d,this.xLabel.getBBox().width),this.hover.attr("width",d+this.options.hoverPaddingX*2),this.hover.attr("x",-this.options.hoverPaddingX-d/2),f=Math.min.apply(null,a.map(this.series,function(a){return h.transY(a[b])})),f>this.hoverHeight+this.options.hoverPaddingY*2+this.options.hoverMargin+this.options.marginTop?f=f-this.hoverHeight/2-this.options.hoverPaddingY-this.options.hoverMargin:f=f+this.hoverHeight/2+this.options.hoverPaddingY+this.options.hoverMargin,f=Math.max(this.options.marginTop+this.hoverHeight/2+this.options.hoverPaddingY,f),f=Math.min(this.options.marginTop+this.height-this.hoverHeight/2-this.options.hoverPaddingY,f),e=Math.min(this.left+this.width-d/2-this.options.hoverPaddingX,this.columns[b]),e=Math.max(this.left+d/2+this.options.hoverPaddingX,e),this.hoverSet.attr("transform","t"+e+","+f)},d.prototype.hideHover=function(){return this.hoverSet.hide()},d.prototype.hilight=function(a){var b,c,d;if(this.prevHilight!==null&&this.prevHilight!==a)for(b=0,c=this.seriesPoints.length-1;0<=c?b<=c:b>=c;0<=c?b++:b--)this.seriesPoints[b][this.prevHilight]&&this.seriesPoints[b][this.prevHilight].animate(this.pointShrink);if(a!==null&&this.prevHilight!==a){for(b=0,d=this.seriesPoints.length-1;0<=d?b<=d:b>=d;0<=d?b++:b--)this.seriesPoints[b][a]&&this.seriesPoints[b][a].animate(this.pointGrow);this.updateHover(a)}this.prevHilight=a;if(a===null)return this.hideHover()},d.prototype.updateHilight=function(a){var b,c,d;a-=this.el.offset().left,d=[];for(b=c=this.hoverMargins.length;c<=0?b<=0:b>=0;c<=0?b++:b--){if(b===0||this.hoverMargins[b-1]>a){this.hilight(b);break}d.push(void 0)}return d},d.prototype.measureText=function(a,b){var c,d;return b==null&&(b=12),d=this.r.text(100,100,a).attr("font-size",b),c=d.getBBox(),d.remove(),c},d.prototype.parseYear=function(a){var b,c,d,e,f,g,h,i,j,k;return typeof a=="number"?a:(c=a.match(/^(\d+) Q(\d)$/),e=a.match(/^(\d+)-(\d+)$/),f=a.match(/^(\d+)-(\d+)-(\d+)$/),g=a.match(/^(\d+) W(\d+)$/),h=a.match(/^(\d+)-(\d+)-(\d+) (\d+):(\d+)$/),i=a.match(/^(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+(\.\d+)?)$/),c?(new Date(parseInt(c[1],10),parseInt(c[2],10)*3-1,1)).getTime():e?(new Date(parseInt(e[1],10),parseInt(e[2],10)-1,1)).getTime():f?(new Date(parseInt(f[1],10),parseInt(f[2],10)-1,parseInt(f[3],10))).getTime():g?(j=new Date(parseInt(g[1],10),0,1),j.getDay()!==4&&j.setMonth(0,1+(4-j.getDay()+7)%7),j.getTime()+parseInt(g[2],10)*6048e5):h?(new Date(parseInt(h[1],10),parseInt(h[2],10)-1,parseInt(h[3],10),parseInt(h[4],10),parseInt(h[5],10))).getTime():i?(k=parseFloat(i[6]),b=Math.floor(k),d=Math.floor((k-b)*1e3),(new Date(parseInt(i[1],10),parseInt(i[2],10)-1,parseInt(i[3],10),parseInt(i[4],10),parseInt(i[5],10),b,d)).getTime()):new Date(parseInt(a,10),0,1))},d.prototype.commas=function(a){var b,c,d,e;return a===null?"n/a":(d=a<0?"-":"",b=Math.abs(a),c=Math.floor(b).toFixed(0),d+=c.replace(/(?=(?:\d{3})+$)(?!^)/g,","),e=b.toString(),e.length>c.length&&(d+=e.slice(c.length)),d)},d}(),window.Morris=b})).call(this);
@@ -0,0 +1 @@
1
+ //= require tesseract/tesseract
@@ -0,0 +1,2 @@
1
+ .DS_Store
2
+ node_modules
@@ -0,0 +1,12 @@
1
+ Copyright 2012 Square, Inc.
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License"); you may not use
4
+ this file except in compliance with the License. You may obtain a copy of the
5
+ License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software distributed
10
+ under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
11
+ CONDITIONS OF ANY KIND, either express or implied. See the License for the
12
+ specific language governing permissions and limitations under the License.
@@ -0,0 +1,48 @@
1
+ JS_TESTER = ./node_modules/vows/bin/vows
2
+ JS_COMPILER = ./node_modules/uglify-js/bin/uglifyjs
3
+
4
+ .PHONY: test benchmark
5
+
6
+ all: tesseract.min.js package.json
7
+
8
+ tesseract.js: \
9
+ src/version.js \
10
+ src/identity.js \
11
+ src/permute.js \
12
+ src/bisect.js \
13
+ src/heap.js \
14
+ src/heapselect.js \
15
+ src/insertionsort.js \
16
+ src/quicksort.js \
17
+ src/array.js \
18
+ src/filter.js \
19
+ src/null.js \
20
+ src/zero.js \
21
+ src/reduce.js \
22
+ src/tesseract.js \
23
+ Makefile
24
+
25
+ %.min.js: %.js Makefile
26
+ @rm -f $@
27
+ $(JS_COMPILER) < $< > $@
28
+
29
+ %.js:
30
+ @rm -f $@
31
+ @echo '(function(exports){' > $@
32
+ cat $(filter %.js,$^) >> $@
33
+ @echo '})(this);' >> $@
34
+ @chmod a-w $@
35
+
36
+ package.json: tesseract.js src/package.js
37
+ @rm -f $@
38
+ node src/package.js > $@
39
+ @chmod a-w $@
40
+
41
+ clean:
42
+ rm -f tesseract.js tesseract.min.js package.json
43
+
44
+ test: all
45
+ @$(JS_TESTER)
46
+
47
+ benchmark: all
48
+ @node test/benchmark.js
@@ -0,0 +1,11 @@
1
+ # Tesseract
2
+
3
+ Fast *n*-dimensional filtering and grouping of records in JavaScript.
4
+
5
+ See <http://square.github.com/tesseract/> for an interactive example.
6
+
7
+ See <https://github.com/square/tesseract/wiki/API-Reference> for documentation.
8
+
9
+ ## Contributing
10
+
11
+ We'd love for you to participate in the development of Tesseract. Before we can accept your pull request, please sign our [Individual Contributor License Agreement](https://spreadsheets.google.com/spreadsheet/viewform?formkey=dDViT2xzUHAwRkI3X3k5Z0lQM091OGc6MQ&ndplr=1). It's a short form that covers our bases and makes sure you're eligible to contribute. Thank you!
@@ -0,0 +1 @@
1
+ module.exports = require("./tesseract").tesseract;
@@ -0,0 +1,9 @@
1
+ # Below is a list of people and organizations that have contributed
2
+ # to the Dart project. Names should be added to the list like so:
3
+ #
4
+ # Name/Organization <email address>
5
+
6
+ Google Inc.
7
+
8
+ Ola Martin Bini <ola.bini@gmail.com>
9
+ Michael Haubenwallner <michael.haubenwallner@gmail.com>
@@ -0,0 +1,25 @@
1
+ Copyright 2012, the Dart project authors. All rights reserved. Redistribution
2
+ and use in source and binary forms, with or without modification, are permitted
3
+ provided that the following conditions are met:
4
+
5
+ * Redistributions of source code must retain the above copyright notice, this
6
+ list of conditions and the following disclaimer.
7
+
8
+ * Redistributions in binary form must reproduce the above copyright notice,
9
+ this list of conditions and the following disclaimer in the documentation
10
+ and/or other materials provided with the distribution.
11
+
12
+ * Neither the name of Google Inc. nor the names of its contributors may be
13
+ used to endorse or promote products derived from this software without
14
+ specific prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
23
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,342 @@
1
+ // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
2
+ // for details. All rights reserved. Use of this source code is governed by a
3
+ // BSD-style license that can be found in the LICENSE file.
4
+
5
+ /**
6
+ * Dual-Pivot Quicksort algorithm.
7
+ *
8
+ * This class implements the dual-pivot quicksort algorithm as presented in
9
+ * Vladimir Yaroslavskiy's paper.
10
+ *
11
+ * Some improvements have been copied from Android's implementation.
12
+ */
13
+ class DualPivotQuicksort {
14
+ // When a list has less then [:_INSERTION_SORT_THRESHOLD:] elements it will
15
+ // be sorted by an insertion sort.
16
+ static final int _INSERTION_SORT_THRESHOLD = 32;
17
+
18
+ /**
19
+ * Sorts all elements of the given list [:a:] according to the given
20
+ * [:compare:] function.
21
+ *
22
+ * The [:compare:] function takes two arguments [:x:] and [:y:] and returns
23
+ * -1 if [:x < y:],
24
+ * 0 if [:x == y:], and
25
+ * 1 if [:x > y:].
26
+ *
27
+ * The function's behavior must be consistent. It must not return different
28
+ * results for the same values.
29
+ */
30
+ static void sort(List a, int compare(a, b)) {
31
+ _doSort(a, 0, a.length - 1, compare);
32
+ }
33
+
34
+ /**
35
+ * Sorts all elements in the range [:from:] (inclusive) to [:to:] (exclusive)
36
+ * of the given list [:a:].
37
+ *
38
+ * If the given range is invalid an "OutOfRange" error is raised.
39
+ * TODO(floitsch): do we want an error?
40
+ *
41
+ * See [:sort:] for requirements of the [:compare:] function.
42
+ */
43
+ static void sortRange(List a, int from, int to, int compare(a, b)) {
44
+ if ((from < 0) || (to > a.length) || (to < from)) {
45
+ throw "OutOfRange";
46
+ }
47
+ _doSort(a, from, to - 1, compare);
48
+ }
49
+
50
+ /**
51
+ * Sorts the list in the interval [:left:] to [:right:] (both inclusive).
52
+ */
53
+ static void _doSort(List a, int left, int right, int compare(a, b)) {
54
+ if ((right - left) <= _INSERTION_SORT_THRESHOLD) {
55
+ insertionSort_(a, left, right, compare);
56
+ } else {
57
+ _dualPivotQuicksort(a, left, right, compare);
58
+ }
59
+ }
60
+
61
+ static void insertionSort_(List a, int left, int right, int compare(a, b)) {
62
+ for (int i = left + 1; i <= right; i++) {
63
+ var el = a[i];
64
+ int j = i;
65
+ while ((j > left) && (compare(a[j - 1], el) > 0)) {
66
+ a[j] = a[j - 1];
67
+ j--;
68
+ }
69
+ a[j] = el;
70
+ }
71
+ }
72
+
73
+ static void _dualPivotQuicksort(List a,
74
+ int left, int right,
75
+ int compare(a, b)) {
76
+ assert(right - left > _INSERTION_SORT_THRESHOLD);
77
+
78
+ // Compute the two pivots by looking at 5 elements.
79
+ int sixth = (right - left + 1) ~/ 6;
80
+ int index1 = left + sixth;
81
+ int index5 = right - sixth;
82
+ int index3 = (left + right) ~/ 2; // The midpoint.
83
+ int index2 = index3 - sixth;
84
+ int index4 = index3 + sixth;
85
+
86
+ var el1 = a[index1];
87
+ var el2 = a[index2];
88
+ var el3 = a[index3];
89
+ var el4 = a[index4];
90
+ var el5 = a[index5];
91
+
92
+ // Sort the selected 5 elements using a sorting network.
93
+ if (compare(el1, el2) > 0) { var t = el1; el1 = el2; el2 = t; }
94
+ if (compare(el4, el5) > 0) { var t = el4; el4 = el5; el5 = t; }
95
+ if (compare(el1, el3) > 0) { var t = el1; el1 = el3; el3 = t; }
96
+ if (compare(el2, el3) > 0) { var t = el2; el2 = el3; el3 = t; }
97
+ if (compare(el1, el4) > 0) { var t = el1; el1 = el4; el4 = t; }
98
+ if (compare(el3, el4) > 0) { var t = el3; el3 = el4; el4 = t; }
99
+ if (compare(el2, el5) > 0) { var t = el2; el2 = el5; el5 = t; }
100
+ if (compare(el2, el3) > 0) { var t = el2; el2 = el3; el3 = t; }
101
+ if (compare(el4, el5) > 0) { var t = el4; el4 = el5; el5 = t; }
102
+
103
+ var pivot1 = el2;
104
+ var pivot2 = el4;
105
+
106
+ // el2 and el4 have been saved in the pivot variables. They will be written
107
+ // back, once the partioning is finished.
108
+ a[index1] = el1;
109
+ a[index3] = el3;
110
+ a[index5] = el5;
111
+
112
+ a[index2] = a[left];
113
+ a[index4] = a[right];
114
+
115
+ int less = left + 1; // First element in the middle partition.
116
+ int great = right - 1; // Last element in the middle partition.
117
+
118
+ bool pivots_are_equal = (compare(pivot1, pivot2) == 0);
119
+ if (pivots_are_equal) {
120
+ var pivot = pivot1;
121
+ // Degenerated case where the partioning becomes a dutch national flag
122
+ // problem.
123
+ //
124
+ // [ | < pivot | == pivot | unpartitioned | > pivot | ]
125
+ // ^ ^ ^ ^ ^
126
+ // left less k great right
127
+ //
128
+ // a[left] and a[right] are undefined and are filled after the
129
+ // partitioning.
130
+ //
131
+ // Invariants:
132
+ // 1) for x in ]left, less[ : x < pivot.
133
+ // 2) for x in [less, k[ : x == pivot.
134
+ // 3) for x in ]great, right[ : x > pivot.
135
+ for (int k = less; k <= great; k++) {
136
+ var ak = a[k];
137
+ int comp = compare(ak, pivot);
138
+ if (comp == 0) continue;
139
+ if (comp < 0) {
140
+ if (k != less) {
141
+ a[k] = a[less];
142
+ a[less] = ak;
143
+ }
144
+ less++;
145
+ } else {
146
+ // comp > 0.
147
+ //
148
+ // Find the first element <= pivot in the range [k - 1, great] and
149
+ // put [:ak:] there. We know that such an element must exist:
150
+ // When k == less, then el3 (which is equal to pivot) lies in the
151
+ // interval. Otherwise a[k - 1] == pivot and the search stops at k-1.
152
+ // Note that in the latter case invariant 2 will be violated for a
153
+ // short amount of time. The invariant will be restored when the
154
+ // pivots are put into their final positions.
155
+ while (true) {
156
+ comp = compare(a[great], pivot);
157
+ if (comp > 0) {
158
+ great--;
159
+ // This is the only location in the while-loop where a new
160
+ // iteration is started.
161
+ continue;
162
+ } else if (comp < 0) {
163
+ // Triple exchange.
164
+ a[k] = a[less];
165
+ a[less++] = a[great];
166
+ a[great--] = ak;
167
+ break;
168
+ } else {
169
+ // comp == 0;
170
+ a[k] = a[great];
171
+ a[great--] = ak;
172
+ // Note: if great < k then we will exit the outer loop and fix
173
+ // invariant 2 (which we just violated).
174
+ break;
175
+ }
176
+ }
177
+ }
178
+ }
179
+ } else {
180
+ // We partition the list into three parts:
181
+ // 1. < pivot1
182
+ // 2. >= pivot1 && <= pivot2
183
+ // 3. > pivot2
184
+ //
185
+ // During the loop we have:
186
+ // [ | < pivot1 | >= pivot1 && <= pivot2 | unpartitioned | > pivot2 | ]
187
+ // ^ ^ ^ ^ ^
188
+ // left less k great right
189
+ //
190
+ // a[left] and a[right] are undefined and are filled after the
191
+ // partitioning.
192
+ //
193
+ // Invariants:
194
+ // 1. for x in ]left, less[ : x < pivot1
195
+ // 2. for x in [less, k[ : pivot1 <= x && x <= pivot2
196
+ // 3. for x in ]great, right[ : x > pivot2
197
+ for (int k = less; k <= great; k++) {
198
+ var ak = a[k];
199
+ int comp_pivot1 = compare(ak, pivot1);
200
+ if (comp_pivot1 < 0) {
201
+ if (k != less) {
202
+ a[k] = a[less];
203
+ a[less] = ak;
204
+ }
205
+ less++;
206
+ } else {
207
+ int comp_pivot2 = compare(ak, pivot2);
208
+ if (comp_pivot2 > 0) {
209
+ while (true) {
210
+ int comp = compare(a[great], pivot2);
211
+ if (comp > 0) {
212
+ great--;
213
+ if (great < k) break;
214
+ // This is the only location inside the loop where a new
215
+ // iteration is started.
216
+ continue;
217
+ } else {
218
+ // a[great] <= pivot2.
219
+ comp = compare(a[great], pivot1);
220
+ if (comp < 0) {
221
+ // Triple exchange.
222
+ a[k] = a[less];
223
+ a[less++] = a[great];
224
+ a[great--] = ak;
225
+ } else {
226
+ // a[great] >= pivot1.
227
+ a[k] = a[great];
228
+ a[great--] = ak;
229
+ }
230
+ break;
231
+ }
232
+ }
233
+ }
234
+ }
235
+ }
236
+ }
237
+
238
+ // Move pivots into their final positions.
239
+ // We shrunk the list from both sides (a[left] and a[right] have
240
+ // meaningless values in them) and now we move elements from the first
241
+ // and third partition into these locations so that we can store the
242
+ // pivots.
243
+ a[left] = a[less - 1];
244
+ a[less - 1] = pivot1;
245
+ a[right] = a[great + 1];
246
+ a[great + 1] = pivot2;
247
+
248
+ // The list is now partitioned into three partitions:
249
+ // [ < pivot1 | >= pivot1 && <= pivot2 | > pivot2 ]
250
+ // ^ ^ ^ ^
251
+ // left less great right
252
+
253
+ // Recursive descent. (Don't include the pivot values.)
254
+ _doSort(a, left, less - 2, compare);
255
+ _doSort(a, great + 2, right, compare);
256
+
257
+ if (pivots_are_equal) {
258
+ // All elements in the second partition are equal to the pivot. No
259
+ // need to sort them.
260
+ return;
261
+ }
262
+
263
+ // In theory it should be enough to call _doSort recursively on the second
264
+ // partition.
265
+ // The Android source however removes the pivot elements from the recursive
266
+ // call if the second partition is too large (more than 2/3 of the list).
267
+ if (less < index1 && great > index5) {
268
+ while (compare(a[less], pivot1) == 0) { less++; }
269
+ while (compare(a[great], pivot2) == 0) { great--; }
270
+
271
+ // Copy paste of the previous 3-way partitioning with adaptions.
272
+ //
273
+ // We partition the list into three parts:
274
+ // 1. == pivot1
275
+ // 2. > pivot1 && < pivot2
276
+ // 3. == pivot2
277
+ //
278
+ // During the loop we have:
279
+ // [ == pivot1 | > pivot1 && < pivot2 | unpartitioned | == pivot2 ]
280
+ // ^ ^ ^
281
+ // less k great
282
+ //
283
+ // Invariants:
284
+ // 1. for x in [ *, less[ : x == pivot1
285
+ // 2. for x in [less, k[ : pivot1 < x && x < pivot2
286
+ // 3. for x in ]great, * ] : x == pivot2
287
+ for (int k = less; k <= great; k++) {
288
+ var ak = a[k];
289
+ int comp_pivot1 = compare(ak, pivot1);
290
+ if (comp_pivot1 == 0) {
291
+ if (k != less) {
292
+ a[k] = a[less];
293
+ a[less] = ak;
294
+ }
295
+ less++;
296
+ } else {
297
+ int comp_pivot2 = compare(ak, pivot2);
298
+ if (comp_pivot2 == 0) {
299
+ while (true) {
300
+ int comp = compare(a[great], pivot2);
301
+ if (comp == 0) {
302
+ great--;
303
+ if (great < k) break;
304
+ // This is the only location inside the loop where a new
305
+ // iteration is started.
306
+ continue;
307
+ } else {
308
+ // a[great] < pivot2.
309
+ comp = compare(a[great], pivot1);
310
+ if (comp < 0) {
311
+ // Triple exchange.
312
+ a[k] = a[less];
313
+ a[less++] = a[great];
314
+ a[great--] = ak;
315
+ } else {
316
+ // a[great] == pivot1.
317
+ a[k] = a[great];
318
+ a[great--] = ak;
319
+ }
320
+ break;
321
+ }
322
+ }
323
+ }
324
+ }
325
+ }
326
+ // The second partition has now been cleared of pivot elements and looks
327
+ // as follows:
328
+ // [ * | > pivot1 && < pivot2 | * ]
329
+ // ^ ^
330
+ // less great
331
+ // Sort the second partition using recursive descent.
332
+ _doSort(a, less, great, compare);
333
+ } else {
334
+ // The second partition looks as follows:
335
+ // [ * | >= pivot1 && <= pivot2 | * ]
336
+ // ^ ^
337
+ // less great
338
+ // Simply sort it by recursive descent.
339
+ _doSort(a, less, great, compare);
340
+ }
341
+ }
342
+ }