spcompat.pl

来自「SRI international 发布的OAA框架软件」· PL 代码 · 共 1,075 行 · 第 1/3 页

PL
1,075
字号
% are structures of the form timeval(Seconds,Microseconds). Which is a bit
% of a pain, but there we are.

tcp_now(timeval(Secs,Micros)) :-
  statistics(walltime,[Millis|_]),
  Secs is Millis // 1000,
  Micros is 1000*(Millis-1000*Secs).

tcp_time_plus(TV1,Delta,TV2) :-
  ground(TV1),
  ground(Delta),
  !,
  TV1=timeval(Secs1,Micros1),
  Micros1a is Micros1+integer(0.5+Delta*1000000),
  Secs2 is Secs1 + Micros1a // 1000000,
  Micros2 is Micros1a - 1000000*(Secs2-Secs1),
  TV2=timeval(Secs2,Micros2).
tcp_time_plus(TV1,Delta,TV2) :-
  ground(TV2),
  ground(Delta),
  !,
  TV2=timeval(Secs2,Micros2),
  Micros2a is Micros2-integer(0.5+Delta*1000000),
  (Micros2a >= 0 -> 
     TV1=timeval(Secs2,Micros2a);
   Secs1 is Secs2 + (Micros2a+1) // 1000000 -1,
     Micros1 is Micros2a + 1000000*(Secs2-Secs1),
     TV1=timeval(Secs1,Micros1)).
tcp_time_plus(TV1,Delta,TV2) :-
  ground(TV1),
  ground(TV2),
  !,
  TV1=timeval(Secs1,Micros1),
  TV2=timeval(Secs2,Micros2),
  Delta is Secs2-Secs1 + (Micros2-Micros1)/1000000.
% This should probably raise another exception...
tcp_time_plus(TV1,Delta,TV2) :-
  raise_exception(bad_arguments(tcp_time_plus(TV1,Delta,TV2))).

% We maintain the wakeups in a sorted list so tcp_scheduled_wakeup
% (and tcp_select) are relatively efficient. The price is that
% scheduling and cancelling wakeups is a bit less efficient, but
% we assume checking will be more frequent than setting.

tcp_schedule_wakeup(Timeval,Term) :-
  (retract(tcp_scheduled_wakeups(Existing)) ->
     sort([wakeup(Timeval,Term)|Existing],New);
   New=[wakeup(Timeval,Term)]),
  assert(tcp_scheduled_wakeups(New)).

tcp_scheduled_wakeup(Timeval,Term) :-
  tcp_scheduled_wakeups(List),
  member(wakeup(Timeval,Term),List).

tcp_cancel_wakeup(Timeval,Term) :-
  tcp_scheduled_wakeups(Existing),
  append(Pre,[wakeup(Timeval,Term)|Post],Existing),
  !,
  retract(tcp_scheduled_wakeups(_)),
  append(Pre,Post,New),
  assert(tcp_scheduled_wakeups(New)).

tcp_cancel_wakeups :-
  retractall(tcp_scheduled_wakeups(_)).

% This can be used to test wakeups are working. A call such as
%   tcp_test_wakeup_mechanism(2.8,11.2).
% sets a wakeup for 2.8 seconds time, then calls tcp_select with a
% timeout of 11.2 seconds. X should get returned as wakeup(foo), not
% timeout, after 2.8 seconds. If the numbers are reversed, we should
% get a timeout instead.

tcp_test_wakeup_mechanism(WakeupSecs,TimeoutSecs) :-
  (bad_timeout_value(WakeupSecs);
   bad_timeout_value(TimeoutSecs)),
  !.
tcp_test_wakeup_mechanism(WakeupSecs,TimeoutSecs) :-
  format('~N~nTesting Sicstus TCP wakeup mechanism emulator.~n',[]),
  format('~NWakeup time is ~w, and timeout time is ~w.~n',
         [WakeupSecs,TimeoutSecs]),
  (TimeoutSecs = 0 ->
     format('~NA timeout time of 0 seconds means no timeout.~n',[]);
   true),
  (WakeupSecs > TimeoutSecs, TimeoutSecs > 0 -> 
     format('~NHmm...we expect a timeout, as it precedes the wakeup.~n',[]),
     MinSecs=TimeoutSecs,
     Expect=timeout;
   MinSecs=WakeupSecs,
     format('~NHmm...we expect a wakeup, as it precedes the timeout.~n',[]),
     Expect=wakeup(foo)),
  format('Setting the wakeup...~n',[]),
  tcp_cancel_wakeups,
  tcp_now(Now),
  tcp_time_plus(Now,WakeupSecs,Then),
  tcp_schedule_wakeup(Then,foo),
  format('~NCalling tcp_select/2, which should return "~w".~n',[Expect]),
  format('Please wait ~w seconds...~n',[MinSecs]),
  tcp_select(TimeoutSecs,X),
  format('~Ntcp_select/2 returned "~w".~n',[X]),
  (X == Expect -> format('~NGood, that''s what I expected.~n',[]);
   format('That''s bad. It should have returned "~w"~n',[Expect])),
  !.
tcp_test_wakeup_mechanism(_,_) :-
  format('~NOh, dear. This predicate really shouldn''t fail.~n',[]),
  fail.

% Check the times offered are sensible...

bad_timeout_value(Val) :-
  \+((number(Val),Val>=0)),
  !,
  format('~NBad value "~w": it should be a positive number (of seconds).',[Val]).
bad_timeout_value(Val) :-
  Val > 500,
  !,
  format('~NBad value "~w": do you really want to wait for ~w seconds?~n',
         [Val,Val]).

% ------------------------------------------------------------------------

% Part of Quintus library(strings)...

concat(X, Y, Z) :-
  atom_chars(X, XCs),
  atom_chars(Y, YCs),
  append(XCs, YCs, ZCs),
  atom_chars(Z, ZCs).

:- dynamic gensym_ctr/1.
gensym_ctr(0).

gensym(Prefix, Sym) :-
  gensym_ctr(N),
  M is N + 1,
  retractall(gensym_ctr(_)),
  assert(gensym_ctr(M)),
  number_chars(M, NChars),
  atom_chars(Prefix, PChars),
  append(PChars, NChars, Chars),
  atom_chars(Sym, Chars).

% @@Needs to be completed!
span_trim(X, X).

% ------------------------------------------------------------------------

% Part of Quintus library(system)...

unix(argv(Args)) :-
  prolog_flag(argv,Args).

% ------------------------------------------------------------------------

% Simulate the effect of Quintus load_files(File,[all_dynamic(true)]).

load_all_dynamic(File) :-
  open(File,read,S),
  % Character escapes (e.g., \n) are *not* employed in ICL expressions.
  % (icldataq, among other things, depends on this.)
  % We assume that files loaded here might contain ICL expressions,
  % and so should follow the same convention.
  prolog_flag(character_escapes,CE,off),
  repeat,
  read(S,Term),
  (Term == end_of_file;
   Term = (:- multifile(_)) -> fail;
   Term = (:- dynamic(_)) -> fail;
   Term = (:-(Goal)) -> call(Goal),fail;
   assertz(Term),fail),
   prolog_flag(character_escapes,_,CE),
  !.

% ------------------------------------------------------------------------

% Emulate ask_oneof/3 in Quintus library ask.pl.

ask_oneof(Prompt,Constants,Answer) :-
  current_output(CO),
  format('~N~w: ',[Prompt]),
  flush_output(CO),
  read_line_of_chars(Chars),
  findall(Constant,
          (member(Constant,Constants),
           atom_chars(Constant,CChars),
           append(Chars,_,CChars)),
          Matches),
  (Matches=[Answer] -> true;
   ask_oneof(Prompt,Constants,Answer)).

read_line_of_chars(Chars) :-
  get0(C),
  (C = 10 -> Chars=[];
   C < 0 -> Chars=[];
   Chars=[C|Rest],
     read_line_of_chars(Rest)).

ask_number(Prompt,Default,Answer) :-
    current_output(CO),
  format('~N~w [~w]: ',[Prompt,Default]),
  flush_output(CO),
  read_line_of_chars(Chars),
  (number_chars(Answer,Chars) -> true;
   ask_number(Prompt,Default,Answer)).

% ------------------------------------------------------------------------

% Emulate part of Quintus library(sets)...

union([List],List) :-
  !.
union([List|Lists],Union) :-
  union(Lists,Union1),
  union(List,Union1,Union).

union([],Set,Set).
union([E|Set1],Set2,[E|Set12]) :-
  \+(memberchk(E,Set2)),
  !,
  union(Set1,Set2,Set12).
union([_|Set1],Set2,Set12) :-
  union(Set1,Set2,Set12).

%   intersect(+Set1, +Set2)
%   is true when the two sets have a member in common.
%   You should ensure that the arguments are proper lists.

intersect(Set1, Set2) :-
        member(Element, Set1),          %  generates Elements from Set1
        memberchk(Element, Set2),       %  tests them against Set2
        !.                              %  if it succeeds once, is enough.

%   intersection(+Set1, +Set2, ?Intersection)
%   is true when all three arguments are lists representing sets,
%   and Intersection contains every element of Set1 which is also
%   an element of Set2, the order of elements in Intersection
%   being the same as in Set1.  

intersection([], _, []).
intersection([Element|Elements], Set, Intersection) :-
        memberchk(Element, Set),
        !,
        Intersection = [Element|Rest],
        intersection(Elements, Set, Rest).
intersection([_|Elements], Set, Intersection) :-
        intersection(Elements, Set, Intersection).


%   intersection(+ListOfSets, ?Intersection)
%   is true when Intersection is the intersection of all the sets in
%   ListOfSets.  The order of elements in Intersection is taken from
%   the first set in ListOfSets.

intersection([Set|Sets], Intersection) :-
        intersection1(Set, Sets, Intersection).

intersection1([], _, []).
intersection1([Element|Elements], Sets, Intersection) :-
        memberchk_all(Sets, Element),
        !,
        Intersection = [Element|Rest],
        intersection1(Elements, Sets, Rest).
intersection1([_|Elements], Sets, Intersection) :-
        intersection1(Elements, Sets, Intersection).

memberchk_all([], _).
memberchk_all([Set|Sets], Element) :-
        memberchk(Element, Set),
        memberchk_all(Sets, Element).

%   subtract(+Set1, +Set2, ?Difference)
%   is like intersection, but this time it is the elements of Set1 which
%   *are* in Set2 that are deleted.

subtract([], _, []).
subtract([Element|Residue], Set, Difference) :-
        memberchk(Element, Set), !,
        subtract(Residue, Set, Difference).
subtract([Element|Residue], Set, [Element|Difference]) :-
        subtract(Residue, Set, Difference).

subset([], _).
subset([Element|Residue], Set) :-
    memberchk(Element, Set),
    subset(Residue, Set).

%# EXTRA STUFF FOR OAA V2

tcp_inet_addr(Host,IPNum) :-
  hostname_address(Host,IPNum).

%# NOTE: there is an incompatibility here. now/1 under Quintus returns
%# the number of seconds since January 1st 1970. But this is only used
%# to provide the third argument of oaa_data_ref/3, and that argument
%# never seems to be used. So I'm providing an increasing function of time
%# as a lazy way out. DMC.

/* Now provided by Sicstus (starting with 3.9.0) */
:- ( current_predicate(now, system:now(_)) ->
        true
   | otherwise ->
        assert((now(When) :-
	        statistics(walltime,[When|_])))
   ).  

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%   samsort(+Compare, +List, ?Sorted)
%     Derived from Richard O'Keefe's samsort routine, which was
%     placed in the public domain as part of the Edinburgh Prolog Tools.
%     Compare is the functor of a 2-argument predicate, which 
%     succeeds IFF Arg1 =< Arg2.

samsort(Compare, List, Sorted) :-
        samsort(List, Compare, [], 0, Sorted).

samsort([], Compare, Stack, _, Sorted) :-
        samfuse(Stack, Compare, Sorted).
samsort([Head|Tail], Compare, Stack, R, Sorted) :-
        sam_run(Tail, [Head|Queue], [Head|Queue], Compare, Run, Rest),
        S is R+1,
        samfuse(Stack, Run, Compare, S, NewStack),
        samsort(Rest, Compare, NewStack, S, Sorted).


samfuse([], _, []).
samfuse([Run|Stack], Compare, Sorted) :-
        samfuse(Stack, Run, Compare, 0, [Sorted]).

samfuse([B|Rest], A, Compare, K, Ans) :-
        0 is K /\ 1,
        !,
        J is K >> 1,
        sammerge(B, A, Compare, C),
        samfuse(Rest, C, Compare, J, Ans).
samfuse(Stack, Run, _, _, [Run|Stack]).

sam_run([], Run, [_], _, Run, []).
sam_run([Head|Tail], QH, QT, Compare, Run, Rest) :-
        sam_run(QH, QT, Head, Tail, Compare, Run, Rest).

sam_run(Qh, [Last|Qt], Head, Tail, Compare, Run, Rest) :-
        call_compare(Compare, Last, Head),
        !,
        Qt = [Head|_],
        sam_run(Tail, Qh, Qt, Compare, Run, Rest).
sam_run(Run, [_], Head, Tail, Compare, Run, [Head|Tail]) :-
        Run = [H|_],
	call_compare(Compare, H, Head),
        !.
sam_run(Qh, Qt, Head, Tail, Compare, Run, Rest) :-
        sam_run(Tail, [Head|Qh], Qt, Compare, Run, Rest).

sammerge(List1, [], _, List1) :- !.
sammerge([], List2, _, List2) :- !.
sammerge([Head1|Tail1], [Head2|Tail2], Compare, [Head1|Merged]) :-
        call_compare(Compare, Head1, Head2),
        !,
        sammerge(Tail1, [Head2|Tail2], Compare, Merged).
sammerge(List1, [Head2|Tail2], Compare, [Head2|Merged]) :-

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?