|
@@ -4,58 +4,109 @@
|
|
new/0, top/1, bot/1, take/2, load/1, save/1, down/1, up/1,
|
|
new/0, top/1, bot/1, take/2, load/1, save/1, down/1, up/1,
|
|
check/0, seek/1, rewind/1, next/1, prev/1, add/2, remove/2 ]).
|
|
check/0, seek/1, rewind/1, next/1, prev/1, add/2, remove/2 ]).
|
|
|
|
|
|
-% PUBLIC
|
|
|
|
|
|
+% section: kvs_stream prelude
|
|
|
|
+
|
|
|
|
+se(X,Y,Z) -> setelement(X,Y,Z).
|
|
|
|
+e(X,Y) -> element(X,Y).
|
|
|
|
+cv(R,V) -> se(#cur.val, R, V).
|
|
|
|
+cb(R,V) -> se(#cur.bot, R, V).
|
|
|
|
+ct(R,V) -> se(#cur.top, R, V).
|
|
|
|
+cl(R,V) -> se(#cur.left, R, V).
|
|
|
|
+cr(R,V) -> se(#cur.right, R, V).
|
|
|
|
+cd(R,V) -> se(#cur.dir, R, V).
|
|
|
|
+sn(M,T) -> se(#iter.next, M, T).
|
|
|
|
+sp(M,T) -> se(#iter.prev, M, T).
|
|
|
|
+si(M,T) -> se(#iter.id, M, T).
|
|
|
|
+el(X,T) -> e(X, T).
|
|
|
|
+tab(T) -> e(1, T).
|
|
|
|
+et(T) -> e(#cur.top, T).
|
|
|
|
+eb(T) -> e(#cur.bot, T).
|
|
|
|
+id(T) -> e(#iter.id, T).
|
|
|
|
+en(T) -> e(#iter.next, T).
|
|
|
|
+ep(T) -> e(#iter.prev, T).
|
|
|
|
+dir(0) -> top;
|
|
|
|
+dir(1) -> bot.
|
|
|
|
+acc(0) -> prev;
|
|
|
|
+acc(1) -> next.
|
|
|
|
|
|
-new() -> #cur{id=kvs:next_id(cur,1)}.
|
|
|
|
-up(C) -> C#cur{dir=0}.
|
|
|
|
-down(C) -> C#cur{dir=1}.
|
|
|
|
-top(C) -> seek(up(C)).
|
|
|
|
-bot(C) -> seek(down(C)).
|
|
|
|
|
|
+% section: next, prev
|
|
|
|
|
|
-seek(#cur{val=[]}=C) -> C;
|
|
|
|
-seek(#cur{bot=X,pos=P,dir=0}=C) when element(2,P) == X -> C;
|
|
|
|
-seek(#cur{top=X,pos=P,dir=1}=C) when element(2,P) == X -> C;
|
|
|
|
-seek(#cur{top=T,bot=B,left=L,right=R,dir=0,pos=P}=C) -> C#cur{pos=id(kvs:get(tab(P),B)),left=0,right=L+R};
|
|
|
|
-seek(#cur{top=T,bot=B,left=L,right=R,dir=1,pos=P}=C) -> C#cur{pos=id(kvs:get(tab(P),T)),left=L+R,right=0}.
|
|
|
|
|
|
+next (#cur{pos=[]}=C) -> {error,[]};
|
|
|
|
+next (#cur{pos=B} =C) -> pos(kvs:get(tab(B),en(B)),C,right(C)).
|
|
|
|
+prev (#cur{pos=[]}=C) -> {error,[]};
|
|
|
|
+prev (#cur{pos=B} =C) -> pos(kvs:get(tab(B),ep(B)),C,left(C)).
|
|
|
|
+
|
|
|
|
+left (#cur{left=0,right=0,dir=D}) -> swap(D,{0, 0});
|
|
|
|
+left (#cur{left=0,right=R,dir=D}) -> swap(D,{0, R});
|
|
|
|
+left (#cur{left=L,right=R,dir=D}) -> swap(D,{L-1,R+1}).
|
|
|
|
+right(#cur{left=0,right=0,dir=D}) -> swap(D,{0, 0});
|
|
|
|
+right(#cur{left=L,right=0,dir=D}) -> swap(D,{L, 0});
|
|
|
|
+right(#cur{left=L,right=R,dir=D}) -> swap(D,{L+1,R-1}).
|
|
|
|
+
|
|
|
|
+swap(1,{L,R}) -> {R,L};
|
|
|
|
+swap(0,{L,R}) -> {L,R}.
|
|
|
|
+
|
|
|
|
+pos({ok,R},C,{X,Y}) -> C#cur{pos=R,left=X,right=Y};
|
|
|
|
+pos({error,X},C,_) -> {error,X}.
|
|
|
|
+
|
|
|
|
+% section: take
|
|
|
|
+
|
|
|
|
+take(N,#cur{dir=D}=C) -> take(acc(D),N,C,[]).
|
|
|
|
+
|
|
|
|
+take(_,_,{error,_},R) -> lists:flatten(R);
|
|
|
|
+take(_,0,_,R) -> lists:flatten(R);
|
|
|
|
+take(A,N,#cur{pos=B}=C,R) -> take(A,N-1,?MODULE:A(C),[B|R]).
|
|
|
|
+
|
|
|
|
+% rewind
|
|
|
|
|
|
rewind(#cur{val=[]}=C) -> {error,[]};
|
|
rewind(#cur{val=[]}=C) -> {error,[]};
|
|
-rewind(#cur{dir=D,top=T,bot=B,val=V}=C) -> C#cur{val=id(kvs:get(tab(V),select(D,T,B)))}.
|
|
|
|
|
|
+rewind(#cur{dir=D,top=T,bot=B,val=V}=C) ->
|
|
|
|
+ C#cur{val=id(kvs:get(tab(V),select(D,T,B)))}.
|
|
|
|
|
|
-add(M,#cur{dir=D}=C) when element(2,M) == [] -> add(dir(D),si(M,kvs:next_id(tab(M),1)),C);
|
|
|
|
-add(M,#cur{dir=D}=C) -> add(dir(D),M,C).
|
|
|
|
|
|
+select(0,T,B) -> T;
|
|
|
|
+select(1,T,B) -> B;
|
|
|
|
+select(P,P,X) -> X;
|
|
|
|
+select(P,N,X) -> N.
|
|
|
|
|
|
-save(C) -> kvs:put(C), C.
|
|
|
|
-load(K) -> case kvs:get(cur,K) of {ok,C} -> C; E -> E end.
|
|
|
|
|
|
+% seek
|
|
|
|
|
|
-next(#cur{pos=[]}=C) -> {error,[]};
|
|
|
|
-next(#cur{pos=B} =C) -> pos(kvs:get(tab(B),en(B)),C,right(C)).
|
|
|
|
-prev(#cur{pos=[]}=C) -> {error,[]};
|
|
|
|
-prev(#cur{pos=B} =C) -> pos(kvs:get(tab(B),ep(B)),C,left(C)).
|
|
|
|
|
|
+seek(#cur{val=[]}=C) -> C;
|
|
|
|
+seek(#cur{bot=X,pos=P,dir=0}=C) when element(2,P) == X -> C;
|
|
|
|
+seek(#cur{top=X,pos=P,dir=1}=C) when element(2,P) == X -> C;
|
|
|
|
+seek(#cur{top=T,bot=B,left=L,right=R,dir=0,pos=P}=C) ->
|
|
|
|
+ C#cur{pos=id(kvs:get(tab(P),B)),left=0,right=L+R};
|
|
|
|
+seek(#cur{top=T,bot=B,left=L,right=R,dir=1,pos=P}=C) ->
|
|
|
|
+ C#cur{pos=id(kvs:get(tab(P),T)),left=L+R,right=0}.
|
|
|
|
|
|
-take(N,#cur{dir=D}=C) -> take(acc(D),N,C,[]).
|
|
|
|
|
|
+% new, save, load, up, down, top, bot
|
|
|
|
|
|
-remove(I,#cur{val=[]}=C) -> {error,val};
|
|
|
|
-remove(I, #cur{val=B,pos=X}=C) -> {ok,R}=kvs:get(tab(B),I), kvs:delete(tab(B),I),
|
|
|
|
- join(I,[fix(tab(B),X)||X<-[ep(R),en(R)]],C).
|
|
|
|
|
|
+new () -> #cur{id=kvs:next_id(cur,1)}.
|
|
|
|
+save (C) -> kvs:put(C), C.
|
|
|
|
+load (K) -> case kvs:get(cur,K) of {ok,C} -> C; E -> E end.
|
|
|
|
+up (C) -> C#cur{dir=0}.
|
|
|
|
+down (C) -> C#cur{dir=1}.
|
|
|
|
+top (C) -> seek(up(C)).
|
|
|
|
+bot (C) -> seek(down(C)).
|
|
|
|
|
|
-% PRIVATE
|
|
|
|
|
|
+% add
|
|
|
|
|
|
-m(I,_,I,_,I,L,R,P,V) -> {R,R};
|
|
|
|
-m(_,I,I,_,I,L,R,P,V) -> {R,L};
|
|
|
|
-m(I,_,_,I,I,L,R,P,V) -> {L,R};
|
|
|
|
-m(_,I,_,I,I,L,R,P,V) -> {L,L};
|
|
|
|
-m(I,_,_,_,I,L,R,P,V) -> {sn(V,id(R)),P};
|
|
|
|
-m(_,I,_,_,I,L,R,P,V) -> {sp(V,id(R)),P};
|
|
|
|
-m(_,_,I,_,I,L,R,P,V) -> {V,sn(P,id(L))};
|
|
|
|
-m(_,_,_,I,I,L,R,P,V) -> {V,sp(P,id(L))};
|
|
|
|
-m(_,_,_,_,I,L,R,P,V) -> {V,P}.
|
|
|
|
|
|
+add(M,#cur{dir=D}=C) when element(2,M) == [] ->
|
|
|
|
+ add(dir(D),si(M,kvs:next_id(tab(M),1)),C);
|
|
|
|
+add(M,#cur{dir=D}=C) ->
|
|
|
|
+ add(dir(D),M,C).
|
|
|
|
+
|
|
|
|
+inc(#cur{left=L,right=R,dir=D}) -> swap(D,{L+1,R}).
|
|
|
|
|
|
add(bot,M,#cur{bot=T,val=[]}=C) ->
|
|
add(bot,M,#cur{bot=T,val=[]}=C) ->
|
|
- Id=id(M), N=sn(sp(M,T),[]), kvs:put(N),
|
|
|
|
|
|
+ Id=id(M),
|
|
|
|
+ N=sn(sp(M,T),[]),
|
|
|
|
+ kvs:put(N),
|
|
C#cur{val=N,pos=N,bot=Id,top=Id};
|
|
C#cur{val=N,pos=N,bot=Id,top=Id};
|
|
|
|
|
|
add(top,M,#cur{top=B,val=[]}=C) ->
|
|
add(top,M,#cur{top=B,val=[]}=C) ->
|
|
- Id=id(M), N=sp(sn(M,B),[]), kvs:put(N),
|
|
|
|
|
|
+ Id=id(M),
|
|
|
|
+ N=sp(sn(M,B),[]),
|
|
|
|
+ kvs:put(N),
|
|
C#cur{val=N,pos=N,top=Id,bot=Id};
|
|
C#cur{val=N,pos=N,top=Id,bot=Id};
|
|
|
|
|
|
add(top,M,#cur{top=T, val=V}=C) when element(2,V) /= T ->
|
|
add(top,M,#cur{top=T, val=V}=C) when element(2,V) /= T ->
|
|
@@ -65,88 +116,78 @@ add(bot,M,#cur{bot=B, val=V}=C) when element(2,V) /= B ->
|
|
add(bot, M, rewind(C));
|
|
add(bot, M, rewind(C));
|
|
|
|
|
|
add(bot,M,#cur{bot=T,val=V,pos=P}=C) ->
|
|
add(bot,M,#cur{bot=T,val=V,pos=P}=C) ->
|
|
- Id=id(M), H=sn(sp(M,T),[]), N=sn(V,Id),
|
|
|
|
- kvs:put([H,N]), {L,R} = inc(C),
|
|
|
|
|
|
+ Id=id(M),
|
|
|
|
+ H=sn(sp(M,T),[]),
|
|
|
|
+ N=sn(V,Id),
|
|
|
|
+ kvs:put([H,N]),
|
|
|
|
+ {L,R} = inc(C),
|
|
C#cur{pos=select(V,P,N),val=H,bot=Id,left=L,right=R};
|
|
C#cur{pos=select(V,P,N),val=H,bot=Id,left=L,right=R};
|
|
|
|
|
|
add(top,M,#cur{top=B,val=V,pos=P}=C) ->
|
|
add(top,M,#cur{top=B,val=V,pos=P}=C) ->
|
|
- Id=id(M), H=sp(sn(M,B),[]), N=sp(V,Id),
|
|
|
|
- kvs:put([H,N]), {L,R} = inc(C),
|
|
|
|
|
|
+ Id=id(M),
|
|
|
|
+ H=sp(sn(M,B),[]),
|
|
|
|
+ N=sp(V,Id),
|
|
|
|
+ kvs:put([H,N]),
|
|
|
|
+ {L,R} = inc(C),
|
|
C#cur{pos=select(V,P,N),val=H,top=Id,left=L,right=R}.
|
|
C#cur{pos=select(V,P,N),val=H,top=Id,left=L,right=R}.
|
|
|
|
|
|
|
|
+% remove
|
|
|
|
+
|
|
|
|
+remove(I,#cur{val=[]}=C) -> {error,val};
|
|
|
|
+remove(I,#cur{val=B,pos=X}=C) -> {ok,R}=kvs:get(tab(B),I), kvs:delete(tab(B),I),
|
|
|
|
+ join(I,[fix(tab(B),X)||X<-[ep(R),en(R)]],C).
|
|
|
|
+
|
|
|
|
+fix(M,[]) -> [];
|
|
|
|
+fix(M,X) -> fix(kvs:get(M,X)).
|
|
|
|
+fix({ok,O}) -> O;
|
|
|
|
+fix(_) -> [].
|
|
|
|
+
|
|
|
|
+dec(#cur{left=0,right=0,dir=D}) -> swap(D,{0, 0});
|
|
|
|
+dec(#cur{left=L,right=0,dir=D}) -> swap(D,{L-1,0});
|
|
|
|
+dec(#cur{left=0,right=R,dir=D}) -> swap(D,{0,R-1});
|
|
|
|
+dec(#cur{left=L,right=R,dir=D}) -> swap(D,{L-1,R}).
|
|
|
|
+
|
|
|
|
+m(I,_,I,_,I,L,R,P,V) -> {R,R};
|
|
|
|
+m(_,I,I,_,I,L,R,P,V) -> {R,L};
|
|
|
|
+m(I,_,_,I,I,L,R,P,V) -> {L,R};
|
|
|
|
+m(_,I,_,I,I,L,R,P,V) -> {L,L};
|
|
|
|
+m(I,_,_,_,I,L,R,P,V) -> {sn(V,id(R)),P};
|
|
|
|
+m(_,I,_,_,I,L,R,P,V) -> {sp(V,id(R)),P};
|
|
|
|
+m(_,_,I,_,I,L,R,P,V) -> {V,sn(P,id(L))};
|
|
|
|
+m(_,_,_,I,I,L,R,P,V) -> {V,sp(P,id(L))};
|
|
|
|
+m(_,_,_,_,I,L,R,P,V) -> {V,P}.
|
|
|
|
+
|
|
join(I,[[],[]],C) ->
|
|
join(I,[[],[]],C) ->
|
|
{X,Y} = dec(C),
|
|
{X,Y} = dec(C),
|
|
C#cur{top=[],bot=[],val=[],pos=[],left=X,right=Y};
|
|
C#cur{top=[],bot=[],val=[],pos=[],left=X,right=Y};
|
|
|
|
|
|
join(I,[[], R],#cur{pos=P,val=V}=Cur) ->
|
|
join(I,[[], R],#cur{pos=P,val=V}=Cur) ->
|
|
- N=sp(R,[]), kvs:put(N), {X,Y} = dec(Cur),
|
|
|
|
|
|
+ N=sp(R,[]),
|
|
|
|
+ kvs:put(N),
|
|
|
|
+ {X,Y} = dec(Cur),
|
|
[A,B,C,D] = [en(V),ep(V),en(P),ep(P)],
|
|
[A,B,C,D] = [en(V),ep(V),en(P),ep(P)],
|
|
{NV,NP} = m(A,B,C,D,I,[],N,P,V),
|
|
{NV,NP} = m(A,B,C,D,I,[],N,P,V),
|
|
Cur#cur{top=id(N), val=NV, pos=NP, left=X, right=Y};
|
|
Cur#cur{top=id(N), val=NV, pos=NP, left=X, right=Y};
|
|
|
|
|
|
join(I,[L, []],#cur{pos=P,val=V}=Cur) ->
|
|
join(I,[L, []],#cur{pos=P,val=V}=Cur) ->
|
|
- N=sn(L,[]), kvs:put(N), {X,Y} = dec(Cur),
|
|
|
|
|
|
+ N=sn(L,[]),
|
|
|
|
+ kvs:put(N),
|
|
|
|
+ {X,Y} = dec(Cur),
|
|
[A,B,C,D] = [en(V),ep(V),en(P),ep(P)],
|
|
[A,B,C,D] = [en(V),ep(V),en(P),ep(P)],
|
|
{NV,NP} = m(A,B,C,D,I,N,[],P,V),
|
|
{NV,NP} = m(A,B,C,D,I,N,[],P,V),
|
|
Cur#cur{bot=id(N), val=NV, left=X, pos=NP, right=Y};
|
|
Cur#cur{bot=id(N), val=NV, left=X, pos=NP, right=Y};
|
|
|
|
|
|
join(I,[L, R],#cur{pos=P,val=V}=Cur) ->
|
|
join(I,[L, R],#cur{pos=P,val=V}=Cur) ->
|
|
- N=sp(R,id(L)), M=sn(L,id(R)), kvs:put([N,M]), {X,Y} = dec(Cur),
|
|
|
|
|
|
+ N=sp(R,id(L)),
|
|
|
|
+ M=sn(L,id(R)),
|
|
|
|
+ kvs:put([N,M]),
|
|
|
|
+ {X,Y} = dec(Cur),
|
|
[A,B,C,D] = [en(V),ep(V),en(P),ep(P)],
|
|
[A,B,C,D] = [en(V),ep(V),en(P),ep(P)],
|
|
{NV,NP} = m(A,B,C,D,I,N,M,P,V),
|
|
{NV,NP} = m(A,B,C,D,I,N,M,P,V),
|
|
Cur#cur{left=X, pos=NP, val=NV, right=Y}.
|
|
Cur#cur{left=X, pos=NP, val=NV, right=Y}.
|
|
|
|
|
|
-cv(R,V) -> setelement(#cur.val, R, V).
|
|
|
|
-cb(R,V) -> setelement(#cur.bot, R, V).
|
|
|
|
-ct(R,V) -> setelement(#cur.top, R, V).
|
|
|
|
-cl(R,V) -> setelement(#cur.left, R, V).
|
|
|
|
-cr(R,V) -> setelement(#cur.right, R, V).
|
|
|
|
-cd(R,V) -> setelement(#cur.dir, R, V).
|
|
|
|
-sn(M,T) -> setelement(#iter.next, M, T).
|
|
|
|
-sp(M,T) -> setelement(#iter.prev, M, T).
|
|
|
|
-si(M,T) -> setelement(#iter.id, M, T).
|
|
|
|
-
|
|
|
|
-el(X,T) -> element(X, T).
|
|
|
|
-tab(T) -> element(1, T).
|
|
|
|
-et(T) -> element(#cur.top, T).
|
|
|
|
-eb(T) -> element(#cur.bot, T).
|
|
|
|
-id(T) -> element(#iter.id, T).
|
|
|
|
-en(T) -> element(#iter.next, T).
|
|
|
|
-ep(T) -> element(#iter.prev, T).
|
|
|
|
-dir(0) -> top;
|
|
|
|
-dir(1) -> bot.
|
|
|
|
-acc(0) -> prev;
|
|
|
|
-acc(1) -> next.
|
|
|
|
|
|
|
|
-select(0,T,B) -> T;
|
|
|
|
-select(1,T,B) -> B;
|
|
|
|
-select(P,P,X) -> X;
|
|
|
|
-select(P,N,X) -> N.
|
|
|
|
|
|
|
|
-fix(M,[]) -> [];
|
|
|
|
-fix(M,X) -> fix(kvs:get(M,X)).
|
|
|
|
-fix({ok,O}) -> O;
|
|
|
|
-fix(_) -> [].
|
|
|
|
-
|
|
|
|
-pos({ok,R},C,{X,Y}) -> C#cur{pos=R,left=X,right=Y};
|
|
|
|
-pos({error,X},C,_) -> {error,X}.
|
|
|
|
-take(_,_,{error,_},R) -> lists:flatten(R);
|
|
|
|
-take(_,0,_,R) -> lists:flatten(R);
|
|
|
|
-take(A,N,#cur{pos=B}=C,R) -> take(A,N-1,?MODULE:A(C),[B|R]).
|
|
|
|
-swap(1,{L,R}) -> {R,L};
|
|
|
|
-swap(0,{L,R}) -> {L,R}.
|
|
|
|
-
|
|
|
|
-inc(#cur{left=L,right=R,dir=D}) -> swap(D,{L+1,R}).
|
|
|
|
-dec(#cur{left=0,right=0,dir=D}) -> swap(D,{0,0});
|
|
|
|
-dec(#cur{left=L,right=0,dir=D}) -> swap(D,{L-1,0});
|
|
|
|
-dec(#cur{left=0,right=R,dir=D}) -> swap(D,{0,R-1});
|
|
|
|
-dec(#cur{left=L,right=R,dir=D}) -> swap(D,{L-1,R}).
|
|
|
|
-left(#cur{left=0,right=0,dir=D}) -> swap(D,{0,0});
|
|
|
|
-left(#cur{left=0,right=R,dir=D}) -> swap(D,{0,R});
|
|
|
|
-left(#cur{left=L,right=R,dir=D}) -> swap(D,{L-1,R+1}).
|
|
|
|
-right(#cur{left=0,right=0,dir=D}) -> swap(D,{0,0});
|
|
|
|
-right(#cur{left=L,right=0,dir=D}) -> swap(D,{L,0});
|
|
|
|
-right(#cur{left=L,right=R,dir=D}) -> swap(D,{L+1,R-1}).
|
|
|
|
|
|
|
|
% TESTS
|
|
% TESTS
|
|
|
|
|
|
@@ -248,19 +289,19 @@ test1() ->
|
|
L = length(X).
|
|
L = length(X).
|
|
|
|
|
|
te_remove() ->
|
|
te_remove() ->
|
|
- #cur{id=S}=kvs_stream:save(kvs_stream:new()),
|
|
|
|
|
|
+ #cur{id=S}=save(new()),
|
|
P = {'user2',[],[],[],[],[],[],[],[]},
|
|
P = {'user2',[],[],[],[],[],[],[],[]},
|
|
- S1 = kvs_stream:save(
|
|
|
|
- kvs_stream:add(P,
|
|
|
|
- kvs_stream:add(P,
|
|
|
|
- kvs_stream:add(P,
|
|
|
|
- kvs_stream:add(P,
|
|
|
|
- kvs_stream:load(S)))))),
|
|
|
|
- 4 = length(kvs_stream:take(-1,S1)),
|
|
|
|
- S2 = kvs_stream:save(kvs_stream:top(S1)),
|
|
|
|
- S3 = kvs_stream:save(kvs_stream:remove(S2#cur.top-1,S2)),
|
|
|
|
- List = kvs_stream:take(-1,kvs_stream:top(S3)),
|
|
|
|
- Rev = kvs_stream:take(-1,kvs_stream:bot(S3)),
|
|
|
|
|
|
+ S1 = save(
|
|
|
|
+ add(P,
|
|
|
|
+ add(P,
|
|
|
|
+ add(P,
|
|
|
|
+ add(P,
|
|
|
|
+ load(S)))))),
|
|
|
|
+ 4 = length(take(-1,S1)),
|
|
|
|
+ S2 = save(top(S1)),
|
|
|
|
+ S3 = save(remove(S2#cur.top-1,S2)),
|
|
|
|
+ List = take(-1,top(S3)),
|
|
|
|
+ Rev = take(-1,bot(S3)),
|
|
List = lists:reverse(Rev),
|
|
List = lists:reverse(Rev),
|
|
3 = length(List),
|
|
3 = length(List),
|
|
{S3,List}.
|
|
{S3,List}.
|