1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2018 VLC authors and VideoLAN
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
28 #include <vlc_input_item.h>
31 vlc_playlist_RequestInsert(vlc_playlist_t
*playlist
, size_t index
,
32 input_item_t
*const media
[], size_t count
)
34 vlc_playlist_AssertLocked(playlist
);
36 size_t size
= vlc_playlist_Count(playlist
);
40 return vlc_playlist_Insert(playlist
, index
, media
, count
);
44 vlc_playlist_FindRealIndex(vlc_playlist_t
*playlist
, vlc_playlist_item_t
*item
,
47 if (index_hint
!= -1 && (size_t) index_hint
< vlc_playlist_Count(playlist
))
49 if (item
== vlc_playlist_Get(playlist
, index_hint
))
54 /* we are unlucky, we need to find the item */
55 return vlc_playlist_IndexOf(playlist
, item
);
58 struct size_vector
VLC_VECTOR(size_t);
61 vlc_playlist_FindIndices(vlc_playlist_t
*playlist
,
62 vlc_playlist_item_t
*const items
[], size_t count
,
63 ssize_t index_hint
, struct size_vector
*out
)
65 for (size_t i
= 0; i
< count
; ++i
)
67 ssize_t real_index
= vlc_playlist_FindRealIndex(playlist
, items
[i
],
71 int ok
= vlc_vector_push(out
, real_index
);
72 assert(ok
); /* cannot fail, space had been reserved */
74 /* the next item is expected after this one */
75 index_hint
= real_index
+ 1;
81 vlc_playlist_RemoveBySlices(vlc_playlist_t
*playlist
, size_t sorted_indices
[],
85 size_t last_index
= sorted_indices
[count
- 1];
86 size_t slice_size
= 1;
87 /* size_t is unsigned, take care not to test for non-negativity */
88 for (size_t i
= count
- 1; i
!= 0; --i
)
90 size_t index
= sorted_indices
[i
- 1];
91 if (index
== last_index
- 1)
95 /* the previous slice is complete */
96 vlc_playlist_Remove(playlist
, last_index
, slice_size
);
101 /* remove the last slice */
102 vlc_playlist_Remove(playlist
, last_index
, slice_size
);
106 * Move all items specified by their indices to form a contiguous slice, in
109 * \param playlist the playlist
110 * \param indices the indices of the items to regroup
111 * \param head_index the index where to prepend the group
112 * \return the start index of the resulting slice
115 vlc_playlist_Regroup(vlc_playlist_t
*playlist
, size_t indices
[],
118 size_t head
= indices
[head_index
];
120 /* nothing to regroup */
123 size_t slice_size
= 1;
124 size_t last_index
= indices
[head_index
- 1];
126 /* size_t is unsigned, take care not to test for non-negativity */
127 for (size_t i
= head_index
- 1; i
!= 0; --i
)
129 size_t index
= indices
[i
- 1];
130 if (index
== last_index
- 1)
134 assert(last_index
!= head
);
135 if (last_index
< head
)
137 assert(head
>= slice_size
);
140 /* update index of items that will be moved as a side-effect */
141 for (size_t j
= 0; j
<= i
; ++j
)
142 if (indices
[j
] >= last_index
+ slice_size
&& indices
[j
] < head
)
143 indices
[j
] -= slice_size
;
147 /* update index of items that will be moved as a side-effect */
148 for (size_t j
= 0; j
<= i
; ++j
)
149 if (indices
[j
] >= head
&& indices
[j
] < last_index
)
150 indices
[j
] += slice_size
;
152 index
= indices
[i
- 1]; /* current index might have been updated */
154 /* the slice is complete, move it to build the unique slice */
155 vlc_playlist_Move(playlist
, last_index
, slice_size
, head
);
162 /* move the last slice to build the unique slice */
163 if (last_index
< head
)
165 assert(head
>= slice_size
);
168 vlc_playlist_Move(playlist
, last_index
, slice_size
, head
);
173 vlc_playlist_MoveBySlices(vlc_playlist_t
*playlist
, size_t indices
[],
174 size_t count
, size_t target
)
178 /* pass the last slice */
180 for (i
= count
- 1; i
!= 0; --i
)
181 if (indices
[i
- 1] != indices
[i
] - 1)
184 /* regroup items to form a unique slice */
185 size_t head
= vlc_playlist_Regroup(playlist
, indices
, i
);
187 /* move the unique slice to the requested target */
189 vlc_playlist_Move(playlist
, head
, count
, target
);
193 cmp_size(const void *lhs
, const void *rhs
)
195 size_t a
= *(size_t *) lhs
;
196 size_t b
= *(size_t *) rhs
;
205 vlc_playlist_RequestMove(vlc_playlist_t
*playlist
,
206 vlc_playlist_item_t
*const items
[], size_t count
,
207 size_t target
, ssize_t index_hint
)
209 vlc_playlist_AssertLocked(playlist
);
211 struct size_vector vector
= VLC_VECTOR_INITIALIZER
;
212 if (!vlc_vector_reserve(&vector
, count
))
215 vlc_playlist_FindIndices(playlist
, items
, count
, index_hint
, &vector
);
217 size_t move_count
= vector
.size
;
220 size_t size
= vlc_playlist_Count(playlist
);
221 assert(size
>= move_count
);
222 /* move at most to the end of the list */
223 if (target
+ move_count
> size
)
224 target
= size
- move_count
;
226 /* keep the items in the same order as the request (do not sort them) */
227 vlc_playlist_MoveBySlices(playlist
, vector
.data
, vector
.size
, target
);
230 vlc_vector_destroy(&vector
);
235 vlc_playlist_RequestRemove(vlc_playlist_t
*playlist
,
236 vlc_playlist_item_t
*const items
[], size_t count
,
239 vlc_playlist_AssertLocked(playlist
);
241 struct size_vector vector
= VLC_VECTOR_INITIALIZER
;
242 if (!vlc_vector_reserve(&vector
, count
))
245 vlc_playlist_FindIndices(playlist
, items
, count
, index_hint
, &vector
);
249 /* sort so that removing an item does not shift the other indices */
250 qsort(vector
.data
, vector
.size
, sizeof(vector
.data
[0]), cmp_size
);
252 vlc_playlist_RemoveBySlices(playlist
, vector
.data
, vector
.size
);
255 vlc_vector_destroy(&vector
);
260 vlc_playlist_RequestGoTo(vlc_playlist_t
*playlist
, vlc_playlist_item_t
*item
,
263 vlc_playlist_AssertLocked(playlist
);
264 ssize_t real_index
= item
265 ? vlc_playlist_FindRealIndex(playlist
, item
, index_hint
)
267 return vlc_playlist_GoTo(playlist
, real_index
);