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.
- data/.DS_Store +0 -0
- data/README.md +27 -5
- data/lib/d3_rails/version.rb +1 -1
- data/vendor/.DS_Store +0 -0
- data/vendor/assets/.DS_Store +0 -0
- data/vendor/assets/javascripts/.DS_Store +0 -0
- data/vendor/assets/javascripts/d3.v2.js +99 -80
- data/vendor/assets/javascripts/morris.js +1 -0
- data/vendor/assets/javascripts/morris/.DS_Store +0 -0
- data/vendor/assets/javascripts/morris/Makefile +10 -0
- data/vendor/assets/javascripts/morris/README.md +87 -0
- data/vendor/assets/javascripts/morris/examples/_template.html +18 -0
- data/vendor/assets/javascripts/morris/examples/days.html +36 -0
- data/vendor/assets/javascripts/morris/examples/decimal.html +31 -0
- data/vendor/assets/javascripts/morris/examples/lib/example.css +13 -0
- data/vendor/assets/javascripts/morris/examples/lib/example.js +4 -0
- data/vendor/assets/javascripts/morris/examples/lib/prettify.css +1 -0
- data/vendor/assets/javascripts/morris/examples/lib/prettify.js +28 -0
- data/vendor/assets/javascripts/morris/examples/months-no-smooth.html +37 -0
- data/vendor/assets/javascripts/morris/examples/negative.html +35 -0
- data/vendor/assets/javascripts/morris/examples/non-date.html +36 -0
- data/vendor/assets/javascripts/morris/examples/quarters.html +53 -0
- data/vendor/assets/javascripts/morris/examples/timestamps.html +37 -0
- data/vendor/assets/javascripts/morris/examples/weeks.html +52 -0
- data/vendor/assets/javascripts/morris/morris.coffee +444 -0
- data/vendor/assets/javascripts/morris/morris.js +493 -0
- data/vendor/assets/javascripts/morris/morris.min.js +1 -0
- data/vendor/assets/javascripts/tesseract.js +1 -0
- data/vendor/assets/javascripts/tesseract/.gitignore +2 -0
- data/vendor/assets/javascripts/tesseract/LICENSE +12 -0
- data/vendor/assets/javascripts/tesseract/Makefile +48 -0
- data/vendor/assets/javascripts/tesseract/README.md +11 -0
- data/vendor/assets/javascripts/tesseract/index.js +1 -0
- data/vendor/assets/javascripts/tesseract/lib/dart/AUTHORS +9 -0
- data/vendor/assets/javascripts/tesseract/lib/dart/LICENSE +25 -0
- data/vendor/assets/javascripts/tesseract/lib/dart/dual_pivot_quicksort.dart +342 -0
- data/vendor/assets/javascripts/tesseract/package.json +11 -0
- data/vendor/assets/javascripts/tesseract/src/array.js +32 -0
- data/vendor/assets/javascripts/tesseract/src/bisect.js +44 -0
- data/vendor/assets/javascripts/tesseract/src/filter.js +19 -0
- data/vendor/assets/javascripts/tesseract/src/heap.js +44 -0
- data/vendor/assets/javascripts/tesseract/src/heapselect.js +36 -0
- data/vendor/assets/javascripts/tesseract/src/identity.js +3 -0
- data/vendor/assets/javascripts/tesseract/src/insertionsort.js +18 -0
- data/vendor/assets/javascripts/tesseract/src/null.js +3 -0
- data/vendor/assets/javascripts/tesseract/src/package.js +14 -0
- data/vendor/assets/javascripts/tesseract/src/permute.js +8 -0
- data/vendor/assets/javascripts/tesseract/src/quicksort.js +282 -0
- data/vendor/assets/javascripts/tesseract/src/reduce.js +19 -0
- data/vendor/assets/javascripts/tesseract/src/tesseract.js +663 -0
- data/vendor/assets/javascripts/tesseract/src/version.js +1 -0
- data/vendor/assets/javascripts/tesseract/src/zero.js +3 -0
- data/vendor/assets/javascripts/tesseract/tesseract.js +1177 -0
- data/vendor/assets/javascripts/tesseract/tesseract.min.js +1 -0
- data/vendor/assets/javascripts/tesseract/test/benchmark.js +177 -0
- data/vendor/assets/javascripts/tesseract/test/bisect-test.js +206 -0
- data/vendor/assets/javascripts/tesseract/test/heap-test.js +44 -0
- data/vendor/assets/javascripts/tesseract/test/permute-test.js +51 -0
- data/vendor/assets/javascripts/tesseract/test/select-test.js +63 -0
- data/vendor/assets/javascripts/tesseract/test/sort-test.js +83 -0
- data/vendor/assets/javascripts/tesseract/test/tesseract-test.js +655 -0
- data/vendor/assets/javascripts/tesseract/test/version-test.js +16 -0
- 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,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
|
+
}
|