|
|
|
|
#pike __REAL_VERSION__ |
|
#define zero int(0..0) |
|
program SuperTimeRange=cSuperTimeRange; |
|
string calendar_name() { return "TimeRanges"; } |
|
object calendar_object=this; |
|
string _sprintf(int t) { return (t=='O')?calendar_name():0; } |
|
Calendar.Ruleset default_rules=Calendar.default_rules; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TimeRange |
{ |
constant is_timerange=1; |
|
Calendar.Ruleset rules; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void create_unixtime(int unixtime,int len); |
static void create_unixtime_default(int unixtime); |
static void create_julian_day(int jd); |
|
void create(mixed ...args) |
{ |
if (sizeof(args)) switch (args[0]) |
{ |
case "unix": |
if (sizeof(args)==2) |
create_unixtime_default(args[1]); |
else if (sizeof(args)>2) |
create_unixtime(@args[1..]); |
else break; |
return; |
case "unix_r": |
if (sizeof(args)==3) |
{ |
rules=args[2]; |
create_unixtime_default(args[1]); |
} |
else if (sizeof(args)>2) |
{ |
rules=args[3]; |
create_unixtime(args[1],args[2]); |
} |
else break; |
return; |
case "julian": |
if (sizeof(args)==2) |
{ |
create_julian_day(args[1]); |
return; |
} |
break; |
case "julian_r": |
if (sizeof(args)==3) |
{ |
rules=args[2]; |
create_julian_day(args[1]); |
return; |
} |
break; |
|
default: |
if (objectp(args[0]) && args[0]->is_timerange) |
{ |
convert_from([object(TimeRange)]args[0]); |
return; |
} |
break; |
} |
|
error("%O.%O: Illegal parameters %O,%O,%O...\n", |
function_object(this_program), |
this_program,@args,0,0,0); |
} |
|
static void convert_from(TimeRange other) |
{ |
|
if (other->unix_time) { |
rules = other->ruleset(); |
create_unixtime_default(other->unix_time()); |
} else if (other->julian_day) { |
rules = other->ruleset(); |
create_julian_day(other->julian_day()); |
} else |
error("Can't convert %O->%s.%O\n",other, |
calendar_name(), this_program); |
} |
|
|
|
|
|
|
|
|
|
|
|
static TimeRange _set_size(int n,TimeRange x); |
|
TimeRange set_size(function|TimeRange|int(0..0x7fffffff) a, |
void|function|TimeRange b) |
{ |
function|object(TimeRange) x; |
int(0..0x7fffffff) n; |
if (!b) |
if (intp(a)) |
x=this,n=[int(0..0x7fffffff)]a; |
else |
x=a,n=1; |
else |
x=b,n=a; |
if (functionp(x)) x=promote_program(x); |
if (n<0) |
error("Negative size (%d)\n",n); |
return _set_size(n,[object(TimeRange)]x); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static this_program _add(int n,this_program step); |
|
this_program add(function|this_program|int a, |
void|function|this_program b) |
{ |
function|object(this_program) x; |
int n; |
if (!b) |
if (intp(a)) |
x=this,n=[int]a; |
else |
x=a,n=1; |
else |
x=b,n=a; |
if (functionp(x)) x=promote_program(x); |
return _add(n,[object(this_program)]x); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
TimeRange place(TimeRange what,void|int force); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TimeRange `+(program|this_program|int n) |
{ |
if (objectp(n)) return add(1,n); |
return add(n); |
} |
|
TimeRange ``+(int n) |
{ |
return add(n); |
} |
|
TimeRange `-(TimeRange|program|int n) |
{ |
if (objectp(n)) return add(-1,n); |
return add(-n); |
} |
|
|
|
|
|
|
|
TimeRange next() |
{ |
return this+1; |
} |
|
TimeRange prev() |
{ |
return this-1; |
} |
|
|
|
|
|
|
function ``* = `*; |
TimeRange `*(int|float n) |
{ |
return set_size((int)n,this); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
array(TimeRange) split(int|float n, void|function|TimeRange with); |
|
int how_many(function|TimeRange with) |
{ |
if (functionp(with)) with=promote_program(with); |
|
|
TimeRange start=beginning(); |
TimeRange end=end(); |
|
|
int nn=16; |
int low,high; |
|
TimeRange t=start+with*nn; |
if (t==end) return nn; |
if (t>end) |
{ |
for (;;) |
{ |
nn>>=1; |
t=start+with*nn; |
if (t==end) return nn; |
if (t<end) |
{ |
low=nn; |
high=nn*2-1; |
break; |
} |
if (nn==1) return 0; |
} |
} |
else |
{ |
|
TimeRange q=start+with*(nn+1); |
if (q==t) error("Result is infinite - argument is zero range\n"); |
for (;;) |
{ |
nn<<=1; |
t=start+with*nn; |
if (t==end) return nn; |
if (t>end) |
{ |
low=(nn>>1); |
high=nn-1; |
break; |
} |
|
} |
} |
|
for (;;) |
{ |
nn=(low+high)/2; |
|
t=start+with*nn; |
if (t==end) return nn; |
if (t<end) low=nn+1; |
else high=nn-1; |
|
if (low>high) return high; |
} |
} |
|
array(TimeRange)|int `/(TimeRange|program|int|float x) |
{ |
if (intp(x) || floatp(x)) return split(x); |
else return how_many(x); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
int offset_to(TimeRange x) |
{ |
if (x==this) return 0; |
if (x<this) |
return -(x->distance(this)/this); |
return this->distance(x)/this; |
} |
|
|
|
|
|
|
|
|
|
TimeRange beginning(); |
TimeRange end(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TimeRange distance(TimeRange to); |
|
TimeRange range(TimeRange with) |
{ |
return distance(with->end()); |
} |
|
TimeRange space(TimeRange to) |
{ |
return end()->distance(to->beginning()); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
array(int(-1..1)) _compare(TimeRange what) |
{ |
if (objectp(what) && what->is_supertimerange) |
{ |
array(int(-1..1)) cmp=what->_compare(this); |
|
return ({-cmp[0], |
-cmp[2], |
-cmp[1], |
-cmp[3]}); |
} |
return ({-1,-1,-1,-1}); |
|
|
} |
|
string _describe_compare(array(int(-1..1)) c,TimeRange a,TimeRange b) |
{ |
mapping desc=([-1:"<",0:"=",1:">"]); |
return sprintf("%O start %s %O start\n" |
"%O start %s %O end\n" |
"%O end %s %O start\n" |
"%O end %s %O end\n", |
a,desc[c[0]],b, |
a,desc[c[1]],b, |
a,desc[c[2]],b, |
a,desc[c[3]],b); |
} |
|
#define BEGIN_BEGIN 0 |
#define BEGIN_END 1 |
#define END_BEGIN 2 |
#define END_END 3 |
|
int(0..1) strictly_preceeds(TimeRange what) |
{ |
array(int(-1..1)) a=_compare(what); |
return a[END_BEGIN]<0; |
} |
|
int(0..1) preceeds(TimeRange what) |
{ |
array(int(-1..1)) a=_compare(what); |
return a[BEGIN_BEGIN]<0; |
} |
|
int(0..1) is_previous_to(TimeRange what) |
{ |
array(int(-1..1)) a=_compare(what); |
return a[END_BEGIN]==0; |
} |
|
int(0..1) overlaps(TimeRange what) |
{ |
array(int(-1..1)) a=_compare(what); |
return (a[END_BEGIN]>0 && a[BEGIN_END]<0); |
} |
|
int(0..1) contains(TimeRange what) |
{ |
array(int(-1..1)) a=_compare(what); |
return a[BEGIN_BEGIN]<=0 && a[END_END]>=0; |
} |
|
int(0..1) equals(TimeRange what) |
{ |
if (!objectp(what)) return 0; |
array(int(-1..1)) a=_compare(what); |
return a[BEGIN_BEGIN]==0 && a[END_END]==0; |
} |
|
int(0..1) is_next_to(TimeRange what) |
{ |
array(int(-1..1)) a=_compare(what); |
return a[END_BEGIN]==0; |
} |
|
int(0..1) succeeds(TimeRange what) |
{ |
array(int(-1..1)) a=_compare(what); |
return a[END_END]>0; |
} |
|
int(0..1) strictly_succeeds(TimeRange what) |
{ |
array(int(-1..1)) a=_compare(what); |
return a[BEGIN_END]>0; |
} |
|
int(0..1) touches(TimeRange what) |
{ |
array(int(-1..1)) a=_compare(what); |
return |
(a[BEGIN_END]<=0 && a[END_END]>=0) || |
(a[END_BEGIN]>=0 && a[BEGIN_BEGIN]<=0); |
} |
|
int (0..1) starts_with(TimeRange what) |
{ |
array(int(-1..1)) a=_compare(what); |
return !a[BEGIN_BEGIN]; |
} |
|
int (0..1) ends_with(TimeRange what) |
{ |
array(int(-1..1)) a=_compare(what); |
return !a[END_END]; |
} |
|
|
|
|
|
|
|
|
int(0..1) `<(TimeRange compared_to) |
{ |
array(int(-1..1)) a=_compare(compared_to); |
if (a[0]<0) return 1; |
if (a[0]>0) return 0; |
if (a[3]<0) return 1; |
return 0; |
} |
|
int(0..1) `>(TimeRange compared_to) |
{ |
array(int(-1..1)) a=_compare(compared_to); |
if (a[0]>0) return 1; |
if (a[0]<0) return 0; |
if (a[3]>0) return 1; |
return 0; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int(0..1) `==(mixed what) |
{ |
return objectp(what) && functionp(what->ruleset) && |
what->ruleset()==ruleset() && equals(what); |
} |
|
int __hash(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function ``& = `&; |
TimeRange|zero `&(TimeRange with, mixed ...extra) |
{ |
if (with->is_nulltimerange) |
return with; |
array(int(-1..1)) a=_compare(with); |
if (a[END_BEGIN]<0 || a[BEGIN_END]>0) |
return nulltimerange; |
|
if (with->is_supertimerange) |
return predef::`&(with,this,@extra); |
|
TimeRange from,to; |
|
|
if (a[BEGIN_BEGIN]>0) from=beginning(); else from=with->beginning(); |
|
|
if (a[END_END]<0) to=end(); else to=with->end(); |
|
|
TimeRange res=from->distance(to); |
if (sizeof(extra)) return predef::`&(res,@extra); |
return res; |
} |
|
|
|
|
|
|
|
|
|
|
|
function ``| = `|; |
TimeRange `|(TimeRange with,mixed ...extra) |
{ |
if (with->is_nulltimerange) |
return sizeof(extra)?`|(@extra):this; |
array(int(-1..1)) a=_compare(with); |
TimeRange from,to; |
|
if (a[END_BEGIN]<0 || a[BEGIN_END]>0) |
from=SuperTimeRange( sort(({this,with})) ); |
else |
{ |
if (with->is_supertimerange) |
return predef::`|(with,this,@extra); |
|
|
if (a[BEGIN_BEGIN]<0) from=this; else from=with; |
|
|
if (a[END_END]>0) to=this; else to=with; |
|
from=from->range(to); |
} |
if (sizeof(extra)) return predef::`|(from,@extra); |
return from; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
function ``^ = `^; |
TimeRange `^(TimeRange with,mixed ... extra) |
{ |
if (with->is_supertimerange) |
return `^(with,this,@extra); |
if (with->is_nulltimerange) |
return sizeof(extra)?`^(@extra):this; |
|
TimeRange res; |
|
array(int(-1..1)) a=_compare(with); |
|
|
|
TimeRange first,second; |
if (a[END_BEGIN]<0 || a[BEGIN_END]>0) |
res=SuperTimeRange( sort(({this,with})) ); |
else if (a[BEGIN_END]==0 || a[END_BEGIN]==0) |
if (a[BEGIN_BEGIN]<0) |
res=range(with); |
else |
res=with->range(this); |
else if (a[BEGIN_BEGIN]==0 && a[END_END]==0) |
return sizeof(extra)?predef::`^(nulltimerange,@extra):nulltimerange; |
else |
{ |
|
if (a[BEGIN_BEGIN]<0) |
first=distance(with); |
else |
first=with->distance(this); |
|
|
if (a[END_END]<0) |
second=end()->range(with); |
else |
second=with->end()->range(this); |
res=first|second; |
} |
|
if (sizeof(extra)) return `^(res,@extra); |
return res; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TimeRange subtract(TimeRange what,mixed ... extra) |
{ |
array(int(-1..1)) a=_compare(what); |
|
if (a[END_BEGIN]<=0 || a[BEGIN_END]>=0) |
return sizeof(extra)?subtract(@extra):this; |
|
if (what->is_supertimerange) |
{ |
array res=map(what->parts+extra,subtract)-({nulltimerange}); |
switch (sizeof(res)) |
{ |
case 0: return nulltimerange; |
case 1: return res[0]; |
default: return predef::`&(@res); |
} |
} |
|
TimeRange res; |
|
|
|
if (a[BEGIN_BEGIN]>=0) |
if (a[END_END]<=0) |
return nulltimerange; |
else |
res=what->end()->range(this); |
else if (a[END_END]<=0) |
res=distance(what); |
else |
{ |
|
|
|
|
res=predef::`|(distance(what), |
what->end()->range(this)); |
} |
if (sizeof(extra)) return res->subtract(@extra); |
return res; |
} |
|
|
|
|
|
|
|
|
this_program set_ruleset(Calendar.Ruleset r); |
Calendar.Ruleset ruleset() |
{ |
return rules; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this_program set_timezone(string|Calendar.Rule.Timezone tz) |
{ |
return set_ruleset(rules->set_timezone(tz)); |
} |
|
Calendar.Rule.Timezone timezone() |
{ |
return rules->timezone; |
} |
|
|
|
|
|
|
this_program set_language(string|Calendar.Rule.Language lang) |
{ |
return set_ruleset(rules->set_language(lang)); |
} |
|
Calendar.Rule.Language language() |
{ |
return rules->language; |
} |
|
|
|
|
|
object calendar() |
{ |
return calendar_object; |
} |
|
|
string _sprintf(int t,mapping m) |
{ |
switch (t) |
{ |
case 'O': |
return "TimeRange()"; |
case 't': |
return "Calendar."+calendar_name()+".TimeRange"; |
default: |
return 0; |
} |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
class cSuperTimeRange |
{ |
inherit TimeRange; |
|
constant is_supertimerange=1; |
|
array parts; |
|
|
|
|
|
|
void create(array(TimeRange) _parts) |
{ |
if (sizeof(_parts->is_supertimerange-({0}))) |
error("one part is super\n%O\n",_parts); |
if (sizeof(_parts)<2) |
error("SuperTimeRange: Too few time periods to constructor\n"); |
parts=_parts; |
} |
|
TimeRange beginning() |
{ |
return parts[0]->beginning(); |
} |
|
TimeRange end() |
{ |
return parts[-1]->end(); |
} |
|
TimeRange distance(TimeRange to) |
{ |
return beginning()->distance(to); |
} |
|
TimeRange mend_overlap(array parts) |
{ |
switch (sizeof(parts)) |
{ |
case 0: return nulltimerange; |
case 1: return parts[0]; |
} |
array res=({}); |
TimeRange last=parts[0]; |
foreach (parts[1..],TimeRange part) |
{ |
if (last->strictly_preceeds(part)) |
{ |
res+=({last}); |
last=part; |
} |
else |
last=last|part; |
} |
if (!sizeof(res)) return last; |
return SuperTimeRange(res+({last})); |
} |
|
TimeRange `&(TimeRange with,mixed... extra) |
{ |
array r=({}); |
foreach (parts,TimeRange part) |
{ |
TimeRange tmp=predef::`&(part,with,@extra); |
if (tmp) |
if (tmp->is_supertimerange) r+=tmp->parts; |
else if (!tmp->is_nulltimerange) r+=({tmp}); |
} |
switch (sizeof(r)) |
{ |
case 0: return nulltimerange; |
case 1: return r[0]; |
default: return SuperTimeRange(r); |
} |
} |
|
TimeRange `|(TimeRange with,mixed ...extra) |
{ |
TimeRange res; |
if (with->is_supertimerange) |
res=mend_overlap(sort(with->parts+parts)); |
else if (with->is_nulltimerange) |
return this; |
else |
res=mend_overlap(sort( ({with})+parts )); |
if (sizeof(extra)) |
return predef::`|(res,@extra); |
return res; |
} |
|
TimeRange subtract(TimeRange with,mixed ...extra) |
{ |
array r=({}); |
foreach (parts,TimeRange part) |
r+=({part->subtract(part,with,@extra)}); |
return predef::`|(@r); |
} |
|
TimeRange `^(TimeRange with,mixed ...extra) |
{ |
|
|
|
TimeRange r=`|(with)->subtract(`&(with)); |
if (sizeof(extra)) return predef::`^(r,@extra); |
return r; |
} |
|
|
|
int `==(TimeRange with,mixed ...extra) |
{ |
if (!with->is_supertimerange) |
return 0; |
if (sizeof(parts)!=sizeof(with->parts)) |
return 0; |
for (int i=0; i<sizeof(parts); i++) |
if (parts[i]!=with->parts[i]) return 0; |
return sizeof(extra)?predef::`==(with,@extra):1; |
} |
|
|
array(int(-1..1)) _compare(TimeRange what) |
{ |
array(int(-1..1)) a,b; |
a=parts[0]->_compare(what); |
b=parts[-1]->_compare(what); |
return ({a[0],a[1],b[2],b[3]}); |
} |
|
|
|
|
int(0..1) `<(TimeRange with) |
{ |
array(int(-1..1)) a=_compare(with); |
if (a[0]<0) return 1; |
if (a[0]>0) return 0; |
if (a[3]<0) return 1; |
if (a[3]>0) return 0; |
if (!with->is_supertimerange) return 1; |
if (sizeof(parts)>sizeof(with->parts)) return 1; |
if (sizeof(parts)<sizeof(with->parts)) return 0; |
for (int i=0; i<sizeof(parts); i++) |
if (parts[i]<with->parts[i]) return 1; |
return 0; |
} |
|
int(0..1) `>(TimeRange with) |
{ |
array(int(-1..1)) a=_compare(with); |
if (a[0]>0) return 1; |
if (a[0]<0) return 0; |
if (a[3]>0) return 1; |
if (a[3]<0) return 0; |
if (!with->is_supertimerange) return 0; |
if (sizeof(parts)<sizeof(with->parts)) return 1; |
if (sizeof(parts)>sizeof(with->parts)) return 0; |
for (int i=0; i<sizeof(parts); i++) |
if (parts[i]>with->parts[i]) return 1; |
return 0; |
} |
|
int __hash() |
{ |
return predef::`+(@map(parts,"__hash")); |
} |
|
string _sprintf(int t,mapping m) |
{ |
switch (t) |
{ |
case 'O': |
return "SuperTimeRange("+ |
map(parts,"_sprintf",'O')*", "+")"; |
case 't': |
return "SuperTimeRange("+ |
map(parts,"_sprintf",'t')*", "+")"; |
} |
return ::_sprintf(t,m); |
} |
|
TimeRange set_timezone(string|Calendar.Rule.Timezone tz) |
{ |
|
return `|(@map(parts,"set_timezone",tz)); |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
program NullTimeRange=cNullTimeRange; |
static class cNullTimeRange |
{ |
inherit TimeRange; |
|
constant is_nulltimerange=1; |
|
|
void create() |
{ |
} |
|
TimeRange set_size(TimeRange|int(0..0x7fffffff) a,void|TimeRange b) |
{ |
return this; |
} |
|
TimeRange place(TimeRange what,void|int force) |
{ |
return this; |
} |
|
array(TimeRange) split(int n) |
{ |
return allocate(n,this); |
} |
|
TimeRange beginning() { return this; } |
TimeRange end() { return this; } |
|
TimeRange distance(TimeRange to) |
{ |
if (to==this) return this; |
error("Can't distance/space/range with the null timerange\n"); |
} |
|
array(int(-1..1)) _compare(TimeRange with) |
{ |
if (with==this) return ({0,0,0,0}); |
return ({-1,-1,-1,-1}); |
} |
|
int(0..1) `<(TimeRange with) |
{ |
return !(with==this); |
} |
|
int(0..1) `>(TimeRange with) |
{ |
return 0; |
} |
|
int(0..1) `==(TimeRange with) |
{ |
return objectp(with) && with->is_nulltimerange; |
} |
|
int(0..1) equals(TimeRange with) |
{ |
return objectp(with) && with->is_nulltimerange; |
} |
|
TimeRange `&(TimeRange with, mixed ...extra) |
{ |
return predef::`&(with,this,@extra); |
} |
|
TimeRange `|(TimeRange with, mixed ...extra) |
{ |
return predef::`|(with,this,@extra); |
} |
|
TimeRange `^(TimeRange with, mixed ...extra) |
{ |
return predef::`^(with,this,@extra); |
} |
|
this_program subtract(TimeRange with, mixed ...extra) |
{ |
return this; |
} |
|
int(1..1) `!() |
{ |
return 1; |
} |
|
string _sprintf(int t,mapping m) |
{ |
switch (t) |
{ |
case 'O': return "NullTimeRange"; |
case 't': return "Calendar."+calendar_name()+".NullTimeRange"; |
default: return ::_sprintf(t,m); |
} |
} |
} |
|
cNullTimeRange nulltimerange=NullTimeRange(); |
|
|
|
static mapping(function:TimeRange) program2stuff=([]); |
|
static TimeRange promote_program(function p) |
{ |
TimeRange x; |
if ( (x=program2stuff[p]) ) return x; |
x=[object(TimeRange)]p(); |
if (!x->is_timerange) |
error("Not a timerange program: %O\n",p); |
return program2stuff[p]=x; |
} |
|
|