Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 210 lines (195 sloc) 7.845 kb
69c06cc @evanmiller Filters galore! Thanks to Drew Gulino
evanmiller authored
1 -module(erlydtl_slice).
2
ae6bf4b @evanmiller Integrate new filters and tests from dgulino
evanmiller authored
3 -export([slice/2,slice_input_cases/7]).
69c06cc @evanmiller Filters galore! Thanks to Drew Gulino
evanmiller authored
4
5 -define(TEST,"").
6 -define(NOTEST,1).
7 % remark out NODEBUG when running tests; unremark when debugging indivdual use cases
8 -define(NODEBUG,1).
9 -include_lib("eunit/include/eunit.hrl").
10
11 slice(List,":") ->
12 List;
13 slice(List,Index) ->
14 ListLength = erlang:length(List),
15 {Start,End,C1,C2,Step} = parse_index(Index),
16 try
17 slice_input_cases(List,ListLength,Start,C1,End,C2,Step)
18 catch
19 throw:outOfBounds ->
20 [];
21 throw:indexError ->
22 indexError
23 end.
24
25 slice_input_cases(_List,ListLength,Start,false,[],false,[]) when Start > 0, Start >= ListLength ->
26 throw(indexError);
27 slice_input_cases(_List,ListLength,Start,false,[],false,[]) when Start < 0, Start < -ListLength ->
28 throw(indexError);
29 %[-1]
30 slice_input_cases(List,ListLength,Start,false,[],false,[]) when Start<0 ->
ae6bf4b @evanmiller Integrate new filters and tests from dgulino
evanmiller authored
31 S = start_transform(ListLength,Start+ListLength+1),
69c06cc @evanmiller Filters galore! Thanks to Drew Gulino
evanmiller authored
32 LowerBound = single_index_bounds(S),
ae6bf4b @evanmiller Integrate new filters and tests from dgulino
evanmiller authored
33 ?debugFmt("slice_transform exit: ~p, ~p, ~p~n",[List,S,LowerBound]),
34 %[Result] = lists:sublist(List,LowerBound,Step),
35 lists:nth(LowerBound,List);
69c06cc @evanmiller Filters galore! Thanks to Drew Gulino
evanmiller authored
36 %[1]
37 slice_input_cases(List,ListLength,Start,false,[],false,[]) ->
ae6bf4b @evanmiller Integrate new filters and tests from dgulino
evanmiller authored
38 %S = start_transform(ListLength,Start+1),
69c06cc @evanmiller Filters galore! Thanks to Drew Gulino
evanmiller authored
39 %E = end_transform(ListLength,Start+2),
ae6bf4b @evanmiller Integrate new filters and tests from dgulino
evanmiller authored
40 Step = 1,
41 End = Start + 1,
42 {Start1,End1,Step1} = index_defaults(ListLength,Start,End,Step),
43 S = start_transform(ListLength,Start1),
44 E = end_transform(ListLength,End1),
45 ?debugFmt("slice_transform: S,E,Step1: ~p,~p,~p~n",[S,E,Step1]),
46 [Result] = slice_list(List,ListLength,S,false,E,false,Step1),
69c06cc @evanmiller Filters galore! Thanks to Drew Gulino
evanmiller authored
47 Result;
48 %slice_transform(List, ListLength, Start, C1, End, C2, Step) when End < 0, Step > 0 ->
49 % [];
50 %slice_transform(List, ListLength, Start, C1, End, C2, Step) when End > 0, Step < 0 ->
51 % [];
52 %[::-1]
53 slice_input_cases(List,ListLength,[],true,[],true,Step) when Step < 0 ->
54 ?debugMsg("here"),
55 slice_transform(List,ListLength,ListLength,true,-2*(ListLength+1),true,Step);
56 %[::1]
57 slice_input_cases(List,ListLength,[],true,[],true,Step) when Step > 0 ->
58 slice_transform(List,ListLength,0,true,ListLength,true,Step);
59 slice_input_cases(List,ListLength,Start,C1,End,C2,Step) ->
60 slice_transform(List,ListLength,Start,C1,End,C2,Step).
61
62 %[N:N:N]
63 slice_transform(List,ListLength,Start,C1,End,C2,Step) ->
64 {Start1,End1,Step1} = index_defaults(ListLength,Start,End,Step),
65 S = start_transform(ListLength,Start1),
66 E = end_transform(ListLength,End1),
67 ?debugFmt("slice_transform: S,C1,E,C2,Step1: ~p,~p,~p,~p,~p~n",[S,C1,E,C2,Step1]),
68 slice_list(List,ListLength,S,C1,E,C2,Step1).
69
70 %[N:N:N]
71 slice_list(_List,_ListLength,Start,_C1,End,_C2,Step) when Start > End, Step > 0 ->
72 throw(outOfBounds);
73 slice_list(_List,_ListLength,Start,_C1,End,_C2,Step) when Start < End andalso Step < 0 ->
74 throw(outOfBounds);
75 slice_list(_List,_ListLength,Start,_C1,End,_C2,_Step) when Start < 0 andalso End < 0 ->
76 throw(outOfBounds);
77 slice_list(_List,ListLength,Start,_C1,End,_C2,_Step) when Start > ListLength andalso End > ListLength-1 ->
78 throw(outOfBounds);
79 slice_list(List,ListLength,Start,_C1,End,_C2,Step) when Step > 0 ->
80 {LowerBound,UpperBound} = index_bounds(Step,ListLength,Start,End),
81 ?debugFmt("LowerBound+1, UpperBound+1, UpperBound - LowerBound + 1: ~p, ~p, ~p~n",[LowerBound+1,UpperBound,UpperBound-LowerBound]),
82 BoundList = lists:sublist(List,LowerBound+1,UpperBound-LowerBound),
83 SequenceList = lists:seq(1,erlang:length(BoundList),Step),
84 lists:map(fun (N) -> lists:nth(N,BoundList) end,SequenceList);
85 slice_list(List,ListLength,Start,_C1,End,_C2,Step) when Step < 0 ->
86 {LowerBound,UpperBound} = index_bounds(Step,ListLength,Start,End),
87 %S1 = S0 - 1,
88 ?debugFmt("Start,End: ~p, ~p~n",[Start,End]),
89 case erlang:abs(End) > ListLength of
90 true ->
91 ?debugFmt("LowerBound, UpperBound, UpperBound - LowerBound + 1: ~p, ~p, ~p~n",[LowerBound+1,UpperBound,UpperBound-LowerBound+1]),
92 BoundList = lists:sublist(List, LowerBound+1, UpperBound - LowerBound + 1);
93 false ->
94 ?debugFmt("LowerBound+2, UpperBound, UpperBound - LowerBound: ~p, ~p, ~p~n",[LowerBound+2,UpperBound,UpperBound-LowerBound]),
95 BoundList = lists:sublist(List, LowerBound+2, UpperBound - LowerBound)
96 end,
97 ?debugFmt("BoundList: ~p~n",[BoundList]),
98 SequenceList = lists:seq(erlang:length(BoundList),1,Step),
99 ?debugFmt("SequenceList: ~p~n",[SequenceList]),
100 lists:map(fun (N) -> lists:nth(N,BoundList) end,SequenceList).
101
102 index_defaults(ListLength, Start, End, Step) ->
103 case Start==[] of
104 true -> Start1 = 0;
105 false -> Start1 = Start
106 end,
107 case End==[] of
108 true -> End1 = ListLength;
109 false -> End1 = End
110 end,
111 case Step==[] of
112 true -> Step1 = 1;
113 false -> Step1 = Step
114 end,
115 {Start1, End1, Step1}.
116
117 single_index_bounds(S) ->
118 if
119 S >= 0 -> LowerBound = S;
120 S < 0 -> LowerBound = 0
121 end,
122 LowerBound.
123
124 index_bounds(Step1, ListLength, S, E) ->
125 AbsListLength = erlang:abs(ListLength),
126 case Step1 < 0 of
127 true ->
128 ?debugMsg("true"),
129 if
130 S > AbsListLength -> UpperBound = ListLength;
131 S =< AbsListLength -> UpperBound = S
132 end,
133 if
134 E >= 0 ->
135 LowerBound = E;
136 %List1 = tl(List);
137 E < 0 ->
138 LowerBound = 0
139 %List1 = List
140 end;
141 false ->
142 ?debugMsg("false"),
143 if
144 S >= 0 -> LowerBound = S;
145 S < 0 -> LowerBound = 0
146 end,
147 if
148 E > AbsListLength -> UpperBound = ListLength;
149 E =< AbsListLength -> UpperBound = E
150 end
151 end,
152 ?debugFmt("index_bounds: LowerBound,UpperBound: ~p,~p~n",[LowerBound,UpperBound]),
153 {LowerBound, UpperBound}.
154
155 parse_index(Index) ->
156 ParsedIndex = re:replace(Index, "([0-9\-]+)?(:)?([0-9\-]+)?(:)?([0-9\-]+)?", "\\1 ,\\2 ,\\3 ,\\4 ,\\5 ", [{return,list}]),
157 ParsedIndex1 = lists:map(fun(X) -> string:strip(X) end, string:tokens(ParsedIndex, ",")),
158 [Start, D1, End, D2, Step] = ParsedIndex1,
159 Start1 = cast_to_integer(Start),
160 End1 = cast_to_integer(End),
161 C1 = parse_colon(D1),
162 C2 = parse_colon(D2),
163 Step1 = cast_to_integer(Step),
164 ?debugFmt("Parsed: Start1, End1, C1, C2, Step1: ~p, ~p, ~p, ~p, ~p~n",[Start1, End1, C1, C2, Step1]),
165 {Start1, End1, C1, C2, Step1}.
166
167 start_transform(_ListLength, []) ->
168 ?debugFmt("start_transform: ~p~n", [0]),
169 0;
170 start_transform(ListLength, Start) ->
171 case Start >= 0 orelse erlang:abs(Start) > ListLength of
172 true ->
173 ?debugFmt("start_transform: ~p~n", [Start]),
174 Start;
175 false ->
176 ?debugFmt("start_transform: ~p~n", [ListLength + Start]),
177 ListLength + Start
178 end.
179
180 end_transform(ListLength, []) ->
181 ?debugFmt("end_transform: ~p~n", [ListLength]),
182 ListLength;
183 end_transform(ListLength, End) ->
184 case End >= 0 orelse erlang:abs(End) > ListLength of
185 true ->
186 ?debugFmt("end_transform: ~p~n", [End]),
187 End;
188 false ->
189 ?debugFmt("end_transform: ~p~n", [ListLength + End]),
190 ListLength + End
191 end.
192
193 cast_to_integer([]) ->
194 [];
195 cast_to_integer(Input) when is_list(Input)->
196 case lists:member($., Input) of
197 true ->
198 erlang:round(erlang:list_to_float(Input));
199 false ->
200 erlang:list_to_integer(Input)
201 end.
202
203 parse_colon([]) ->
204 false;
205 parse_colon(Colon) ->
206 case Colon of
207 ":" -> true;
208 _ -> false
209 end.
Something went wrong with that request. Please try again.