1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 */
16
17 /** \file
18 * \ingroup bmesh
19 *
20 * Functions to abstract looping over bmesh data structures.
21 *
22 * See: bmesh_iterators_inlin.c too, some functions are here for speed reasons.
23 */
24
25 #include "MEM_guardedalloc.h"
26
27 #include "BLI_bitmap.h"
28 #include "BLI_utildefines.h"
29
30 #include "bmesh.h"
31 #include "intern/bmesh_private.h"
32
33 const char bm_iter_itype_htype_map[BM_ITYPE_MAX] = {
34 '\0',
35 BM_VERT, /* BM_VERTS_OF_MESH */
36 BM_EDGE, /* BM_EDGES_OF_MESH */
37 BM_FACE, /* BM_FACES_OF_MESH */
38 BM_EDGE, /* BM_EDGES_OF_VERT */
39 BM_FACE, /* BM_FACES_OF_VERT */
40 BM_LOOP, /* BM_LOOPS_OF_VERT */
41 BM_VERT, /* BM_VERTS_OF_EDGE */
42 BM_FACE, /* BM_FACES_OF_EDGE */
43 BM_VERT, /* BM_VERTS_OF_FACE */
44 BM_EDGE, /* BM_EDGES_OF_FACE */
45 BM_LOOP, /* BM_LOOPS_OF_FACE */
46 BM_LOOP, /* BM_LOOPS_OF_LOOP */
47 BM_LOOP, /* BM_LOOPS_OF_EDGE */
48 };
49
50 /**
51 * Utility function.
52 */
BM_iter_mesh_count(const char itype,BMesh * bm)53 int BM_iter_mesh_count(const char itype, BMesh *bm)
54 {
55 int count;
56
57 switch (itype) {
58 case BM_VERTS_OF_MESH:
59 count = bm->totvert;
60 break;
61 case BM_EDGES_OF_MESH:
62 count = bm->totedge;
63 break;
64 case BM_FACES_OF_MESH:
65 count = bm->totface;
66 break;
67 default:
68 count = 0;
69 BLI_assert(0);
70 break;
71 }
72
73 return count;
74 }
75
76 /**
77 * \note Use #BM_vert_at_index / #BM_edge_at_index / #BM_face_at_index for mesh arrays.
78 */
BM_iter_at_index(BMesh * bm,const char itype,void * data,int index)79 void *BM_iter_at_index(BMesh *bm, const char itype, void *data, int index)
80 {
81 BMIter iter;
82 void *val;
83 int i;
84
85 /* sanity check */
86 if (index < 0) {
87 return NULL;
88 }
89
90 val = BM_iter_new(&iter, bm, itype, data);
91
92 i = 0;
93 while (i < index) {
94 val = BM_iter_step(&iter);
95 i++;
96 }
97
98 return val;
99 }
100
101 /**
102 * \brief Iterator as Array
103 *
104 * Sometimes its convenient to get the iterator as an array
105 * to avoid multiple calls to #BM_iter_at_index.
106 */
BM_iter_as_array(BMesh * bm,const char itype,void * data,void ** array,const int len)107 int BM_iter_as_array(BMesh *bm, const char itype, void *data, void **array, const int len)
108 {
109 int i = 0;
110
111 /* sanity check */
112 if (len > 0) {
113 BMIter iter;
114 void *ele;
115
116 for (ele = BM_iter_new(&iter, bm, itype, data); ele; ele = BM_iter_step(&iter)) {
117 array[i] = ele;
118 i++;
119 if (i == len) {
120 return len;
121 }
122 }
123 }
124
125 return i;
126 }
127 /**
128 * \brief Operator Iterator as Array
129 *
130 * Sometimes its convenient to get the iterator as an array.
131 */
BMO_iter_as_array(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * slot_name,const char restrictmask,void ** array,const int len)132 int BMO_iter_as_array(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
133 const char *slot_name,
134 const char restrictmask,
135 void **array,
136 const int len)
137 {
138 int i = 0;
139
140 /* sanity check */
141 if (len > 0) {
142 BMOIter oiter;
143 void *ele;
144
145 for (ele = BMO_iter_new(&oiter, slot_args, slot_name, restrictmask); ele;
146 ele = BMO_iter_step(&oiter)) {
147 array[i] = ele;
148 i++;
149 if (i == len) {
150 return len;
151 }
152 }
153 }
154
155 return i;
156 }
157
158 /**
159 * \brief Iterator as Array
160 *
161 * Allocates a new array, has the advantage that you dont need to know the size ahead of time.
162 *
163 * Takes advantage of less common iterator usage to avoid counting twice,
164 * which you might end up doing when #BM_iter_as_array is used.
165 *
166 * Caller needs to free the array.
167 */
BM_iter_as_arrayN(BMesh * bm,const char itype,void * data,int * r_len,void ** stack_array,int stack_array_size)168 void *BM_iter_as_arrayN(BMesh *bm,
169 const char itype,
170 void *data,
171 int *r_len,
172 /* optional args to avoid an alloc (normally stack array) */
173 void **stack_array,
174 int stack_array_size)
175 {
176 BMIter iter;
177
178 BLI_assert(stack_array_size == 0 || (stack_array_size && stack_array));
179
180 /* we can't rely on coun't being set */
181 switch (itype) {
182 case BM_VERTS_OF_MESH:
183 iter.count = bm->totvert;
184 break;
185 case BM_EDGES_OF_MESH:
186 iter.count = bm->totedge;
187 break;
188 case BM_FACES_OF_MESH:
189 iter.count = bm->totface;
190 break;
191 default:
192 break;
193 }
194
195 if (BM_iter_init(&iter, bm, itype, data) && iter.count > 0) {
196 BMElem *ele;
197 BMElem **array = iter.count > stack_array_size ?
198 MEM_mallocN(sizeof(ele) * iter.count, __func__) :
199 stack_array;
200 int i = 0;
201
202 *r_len = iter.count; /* set before iterating */
203
204 while ((ele = BM_iter_step(&iter))) {
205 array[i++] = ele;
206 }
207 return array;
208 }
209
210 *r_len = 0;
211 return NULL;
212 }
213
BMO_iter_as_arrayN(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * slot_name,const char restrictmask,int * r_len,void ** stack_array,int stack_array_size)214 void *BMO_iter_as_arrayN(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
215 const char *slot_name,
216 const char restrictmask,
217 int *r_len,
218 /* optional args to avoid an alloc (normally stack array) */
219 void **stack_array,
220 int stack_array_size)
221 {
222 BMOIter iter;
223 BMElem *ele;
224 int count = BMO_slot_buffer_count(slot_args, slot_name);
225
226 BLI_assert(stack_array_size == 0 || (stack_array_size && stack_array));
227
228 if ((ele = BMO_iter_new(&iter, slot_args, slot_name, restrictmask)) && count > 0) {
229 BMElem **array = count > stack_array_size ? MEM_mallocN(sizeof(ele) * count, __func__) :
230 stack_array;
231 int i = 0;
232
233 do {
234 array[i++] = ele;
235 } while ((ele = BMO_iter_step(&iter)));
236 BLI_assert(i <= count);
237
238 if (i != count) {
239 if ((void **)array != stack_array) {
240 array = MEM_reallocN(array, sizeof(ele) * i);
241 }
242 }
243 *r_len = i;
244 return array;
245 }
246
247 *r_len = 0;
248 return NULL;
249 }
250
BM_iter_mesh_bitmap_from_filter(const char itype,BMesh * bm,BLI_bitmap * bitmap,bool (* test_fn)(BMElem *,void * user_data),void * user_data)251 int BM_iter_mesh_bitmap_from_filter(const char itype,
252 BMesh *bm,
253 BLI_bitmap *bitmap,
254 bool (*test_fn)(BMElem *, void *user_data),
255 void *user_data)
256 {
257 BMIter iter;
258 BMElem *ele;
259 int i;
260 int bitmap_enabled = 0;
261
262 BM_ITER_MESH_INDEX (ele, &iter, bm, itype, i) {
263 if (test_fn(ele, user_data)) {
264 BLI_BITMAP_ENABLE(bitmap, i);
265 bitmap_enabled++;
266 }
267 else {
268 BLI_BITMAP_DISABLE(bitmap, i);
269 }
270 }
271
272 return bitmap_enabled;
273 }
274
275 /**
276 * Needed when we want to check faces, but return a loop aligned array.
277 */
BM_iter_mesh_bitmap_from_filter_tessface(BMesh * bm,BLI_bitmap * bitmap,bool (* test_fn)(BMFace *,void * user_data),void * user_data)278 int BM_iter_mesh_bitmap_from_filter_tessface(BMesh *bm,
279 BLI_bitmap *bitmap,
280 bool (*test_fn)(BMFace *, void *user_data),
281 void *user_data)
282 {
283 BMIter iter;
284 BMFace *f;
285 int i;
286 int j = 0;
287 int bitmap_enabled = 0;
288
289 BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, i) {
290 if (test_fn(f, user_data)) {
291 for (int tri = 2; tri < f->len; tri++) {
292 BLI_BITMAP_ENABLE(bitmap, j);
293 bitmap_enabled++;
294 j++;
295 }
296 }
297 else {
298 for (int tri = 2; tri < f->len; tri++) {
299 BLI_BITMAP_DISABLE(bitmap, j);
300 j++;
301 }
302 }
303 }
304
305 return bitmap_enabled;
306 }
307
308 /**
309 * \brief Elem Iter Flag Count
310 *
311 * Counts how many flagged / unflagged items are found in this element.
312 */
BM_iter_elem_count_flag(const char itype,void * data,const char hflag,const bool value)313 int BM_iter_elem_count_flag(const char itype, void *data, const char hflag, const bool value)
314 {
315 BMIter iter;
316 BMElem *ele;
317 int count = 0;
318
319 BM_ITER_ELEM (ele, &iter, data, itype) {
320 if (BM_elem_flag_test_bool(ele, hflag) == value) {
321 count++;
322 }
323 }
324
325 return count;
326 }
327
328 /**
329 * \brief Elem Iter Tool Flag Count
330 *
331 * Counts how many flagged / unflagged items are found in this element.
332 */
BMO_iter_elem_count_flag(BMesh * bm,const char itype,void * data,const short oflag,const bool value)333 int BMO_iter_elem_count_flag(
334 BMesh *bm, const char itype, void *data, const short oflag, const bool value)
335 {
336 BMIter iter;
337 int count = 0;
338
339 /* loops have no header flags */
340 BLI_assert(bm_iter_itype_htype_map[itype] != BM_LOOP);
341
342 switch (bm_iter_itype_htype_map[itype]) {
343 case BM_VERT: {
344 BMVert *ele;
345 BM_ITER_ELEM (ele, &iter, data, itype) {
346 if (BMO_vert_flag_test_bool(bm, ele, oflag) == value) {
347 count++;
348 }
349 }
350 break;
351 }
352 case BM_EDGE: {
353 BMEdge *ele;
354 BM_ITER_ELEM (ele, &iter, data, itype) {
355 if (BMO_edge_flag_test_bool(bm, ele, oflag) == value) {
356 count++;
357 }
358 }
359 break;
360 }
361 case BM_FACE: {
362 BMFace *ele;
363 BM_ITER_ELEM (ele, &iter, data, itype) {
364 if (BMO_face_flag_test_bool(bm, ele, oflag) == value) {
365 count++;
366 }
367 }
368 break;
369 }
370 }
371 return count;
372 }
373
374 /**
375 * \brief Mesh Iter Flag Count
376 *
377 * Counts how many flagged / unflagged items are found in this mesh.
378 */
BM_iter_mesh_count_flag(const char itype,BMesh * bm,const char hflag,const bool value)379 int BM_iter_mesh_count_flag(const char itype, BMesh *bm, const char hflag, const bool value)
380 {
381 BMIter iter;
382 BMElem *ele;
383 int count = 0;
384
385 BM_ITER_MESH (ele, &iter, bm, itype) {
386 if (BM_elem_flag_test_bool(ele, hflag) == value) {
387 count++;
388 }
389 }
390
391 return count;
392 }
393
394 /**
395 * Notes on iterator implementation:
396 *
397 * Iterators keep track of the next element in a sequence.
398 * When a step() callback is invoked the current value of 'next'
399 * is stored to be returned later and the next variable is incremented.
400 *
401 * When the end of a sequence is reached, next should always equal NULL
402 *
403 * The 'bmiter__' prefix is used because these are used in
404 * bmesh_iterators_inine.c but should otherwise be seen as
405 * private.
406 */
407
408 /*
409 * VERT OF MESH CALLBACKS
410 */
411
412 /* see bug T36923 for why we need this,
413 * allow adding but not removing, this isnt _totally_ safe since
414 * you could add/remove within the same loop, but catches common cases
415 */
416 #ifdef DEBUG
417 # define USE_IMMUTABLE_ASSERT
418 #endif
419
bmiter__elem_of_mesh_begin(struct BMIter__elem_of_mesh * iter)420 void bmiter__elem_of_mesh_begin(struct BMIter__elem_of_mesh *iter)
421 {
422 #ifdef USE_IMMUTABLE_ASSERT
423 ((BMIter *)iter)->count = BLI_mempool_len(iter->pooliter.pool);
424 #endif
425 BLI_mempool_iternew(iter->pooliter.pool, &iter->pooliter);
426 }
427
bmiter__elem_of_mesh_step(struct BMIter__elem_of_mesh * iter)428 void *bmiter__elem_of_mesh_step(struct BMIter__elem_of_mesh *iter)
429 {
430 #ifdef USE_IMMUTABLE_ASSERT
431 BLI_assert(((BMIter *)iter)->count <= BLI_mempool_len(iter->pooliter.pool));
432 #endif
433 return BLI_mempool_iterstep(&iter->pooliter);
434 }
435
436 #ifdef USE_IMMUTABLE_ASSERT
437 # undef USE_IMMUTABLE_ASSERT
438 #endif
439
440 /*
441 * EDGE OF VERT CALLBACKS
442 */
443
bmiter__edge_of_vert_begin(struct BMIter__edge_of_vert * iter)444 void bmiter__edge_of_vert_begin(struct BMIter__edge_of_vert *iter)
445 {
446 if (iter->vdata->e) {
447 iter->e_first = iter->vdata->e;
448 iter->e_next = iter->vdata->e;
449 }
450 else {
451 iter->e_first = NULL;
452 iter->e_next = NULL;
453 }
454 }
455
bmiter__edge_of_vert_step(struct BMIter__edge_of_vert * iter)456 void *bmiter__edge_of_vert_step(struct BMIter__edge_of_vert *iter)
457 {
458 BMEdge *e_curr = iter->e_next;
459
460 if (iter->e_next) {
461 iter->e_next = bmesh_disk_edge_next(iter->e_next, iter->vdata);
462 if (iter->e_next == iter->e_first) {
463 iter->e_next = NULL;
464 }
465 }
466
467 return e_curr;
468 }
469
470 /*
471 * FACE OF VERT CALLBACKS
472 */
473
bmiter__face_of_vert_begin(struct BMIter__face_of_vert * iter)474 void bmiter__face_of_vert_begin(struct BMIter__face_of_vert *iter)
475 {
476 ((BMIter *)iter)->count = bmesh_disk_facevert_count(iter->vdata);
477 if (((BMIter *)iter)->count) {
478 iter->l_first = bmesh_disk_faceloop_find_first(iter->vdata->e, iter->vdata);
479 iter->e_first = iter->l_first->e;
480 iter->e_next = iter->e_first;
481 iter->l_next = iter->l_first;
482 }
483 else {
484 iter->l_first = iter->l_next = NULL;
485 iter->e_first = iter->e_next = NULL;
486 }
487 }
bmiter__face_of_vert_step(struct BMIter__face_of_vert * iter)488 void *bmiter__face_of_vert_step(struct BMIter__face_of_vert *iter)
489 {
490 BMLoop *l_curr = iter->l_next;
491
492 if (((BMIter *)iter)->count && iter->l_next) {
493 ((BMIter *)iter)->count--;
494 iter->l_next = bmesh_radial_faceloop_find_next(iter->l_next, iter->vdata);
495 if (iter->l_next == iter->l_first) {
496 iter->e_next = bmesh_disk_faceedge_find_next(iter->e_next, iter->vdata);
497 iter->l_first = bmesh_radial_faceloop_find_first(iter->e_next->l, iter->vdata);
498 iter->l_next = iter->l_first;
499 }
500 }
501
502 if (!((BMIter *)iter)->count) {
503 iter->l_next = NULL;
504 }
505
506 return l_curr ? l_curr->f : NULL;
507 }
508
509 /*
510 * LOOP OF VERT CALLBACKS
511 */
512
bmiter__loop_of_vert_begin(struct BMIter__loop_of_vert * iter)513 void bmiter__loop_of_vert_begin(struct BMIter__loop_of_vert *iter)
514 {
515 ((BMIter *)iter)->count = bmesh_disk_facevert_count(iter->vdata);
516 if (((BMIter *)iter)->count) {
517 iter->l_first = bmesh_disk_faceloop_find_first(iter->vdata->e, iter->vdata);
518 iter->e_first = iter->l_first->e;
519 iter->e_next = iter->e_first;
520 iter->l_next = iter->l_first;
521 }
522 else {
523 iter->l_first = iter->l_next = NULL;
524 iter->e_first = iter->e_next = NULL;
525 }
526 }
bmiter__loop_of_vert_step(struct BMIter__loop_of_vert * iter)527 void *bmiter__loop_of_vert_step(struct BMIter__loop_of_vert *iter)
528 {
529 BMLoop *l_curr = iter->l_next;
530
531 if (((BMIter *)iter)->count) {
532 ((BMIter *)iter)->count--;
533 iter->l_next = bmesh_radial_faceloop_find_next(iter->l_next, iter->vdata);
534 if (iter->l_next == iter->l_first) {
535 iter->e_next = bmesh_disk_faceedge_find_next(iter->e_next, iter->vdata);
536 iter->l_first = bmesh_radial_faceloop_find_first(iter->e_next->l, iter->vdata);
537 iter->l_next = iter->l_first;
538 }
539 }
540
541 if (!((BMIter *)iter)->count) {
542 iter->l_next = NULL;
543 }
544
545 /* NULL on finish */
546 return l_curr;
547 }
548
549 /*
550 * LOOP OF EDGE CALLBACKS
551 */
552
bmiter__loop_of_edge_begin(struct BMIter__loop_of_edge * iter)553 void bmiter__loop_of_edge_begin(struct BMIter__loop_of_edge *iter)
554 {
555 iter->l_first = iter->l_next = iter->edata->l;
556 }
557
bmiter__loop_of_edge_step(struct BMIter__loop_of_edge * iter)558 void *bmiter__loop_of_edge_step(struct BMIter__loop_of_edge *iter)
559 {
560 BMLoop *l_curr = iter->l_next;
561
562 if (iter->l_next) {
563 iter->l_next = iter->l_next->radial_next;
564 if (iter->l_next == iter->l_first) {
565 iter->l_next = NULL;
566 }
567 }
568
569 /* NULL on finish */
570 return l_curr;
571 }
572
573 /*
574 * LOOP OF LOOP CALLBACKS
575 */
576
bmiter__loop_of_loop_begin(struct BMIter__loop_of_loop * iter)577 void bmiter__loop_of_loop_begin(struct BMIter__loop_of_loop *iter)
578 {
579 iter->l_first = iter->ldata;
580 iter->l_next = iter->l_first->radial_next;
581
582 if (iter->l_next == iter->l_first) {
583 iter->l_next = NULL;
584 }
585 }
586
bmiter__loop_of_loop_step(struct BMIter__loop_of_loop * iter)587 void *bmiter__loop_of_loop_step(struct BMIter__loop_of_loop *iter)
588 {
589 BMLoop *l_curr = iter->l_next;
590
591 if (iter->l_next) {
592 iter->l_next = iter->l_next->radial_next;
593 if (iter->l_next == iter->l_first) {
594 iter->l_next = NULL;
595 }
596 }
597
598 /* NULL on finish */
599 return l_curr;
600 }
601
602 /*
603 * FACE OF EDGE CALLBACKS
604 */
605
bmiter__face_of_edge_begin(struct BMIter__face_of_edge * iter)606 void bmiter__face_of_edge_begin(struct BMIter__face_of_edge *iter)
607 {
608 iter->l_first = iter->l_next = iter->edata->l;
609 }
610
bmiter__face_of_edge_step(struct BMIter__face_of_edge * iter)611 void *bmiter__face_of_edge_step(struct BMIter__face_of_edge *iter)
612 {
613 BMLoop *current = iter->l_next;
614
615 if (iter->l_next) {
616 iter->l_next = iter->l_next->radial_next;
617 if (iter->l_next == iter->l_first) {
618 iter->l_next = NULL;
619 }
620 }
621
622 return current ? current->f : NULL;
623 }
624
625 /*
626 * VERTS OF EDGE CALLBACKS
627 */
628
bmiter__vert_of_edge_begin(struct BMIter__vert_of_edge * iter)629 void bmiter__vert_of_edge_begin(struct BMIter__vert_of_edge *iter)
630 {
631 ((BMIter *)iter)->count = 0;
632 }
633
bmiter__vert_of_edge_step(struct BMIter__vert_of_edge * iter)634 void *bmiter__vert_of_edge_step(struct BMIter__vert_of_edge *iter)
635 {
636 switch (((BMIter *)iter)->count++) {
637 case 0:
638 return iter->edata->v1;
639 case 1:
640 return iter->edata->v2;
641 default:
642 return NULL;
643 }
644 }
645
646 /*
647 * VERT OF FACE CALLBACKS
648 */
649
bmiter__vert_of_face_begin(struct BMIter__vert_of_face * iter)650 void bmiter__vert_of_face_begin(struct BMIter__vert_of_face *iter)
651 {
652 iter->l_first = iter->l_next = BM_FACE_FIRST_LOOP(iter->pdata);
653 }
654
bmiter__vert_of_face_step(struct BMIter__vert_of_face * iter)655 void *bmiter__vert_of_face_step(struct BMIter__vert_of_face *iter)
656 {
657 BMLoop *l_curr = iter->l_next;
658
659 if (iter->l_next) {
660 iter->l_next = iter->l_next->next;
661 if (iter->l_next == iter->l_first) {
662 iter->l_next = NULL;
663 }
664 }
665
666 return l_curr ? l_curr->v : NULL;
667 }
668
669 /*
670 * EDGE OF FACE CALLBACKS
671 */
672
bmiter__edge_of_face_begin(struct BMIter__edge_of_face * iter)673 void bmiter__edge_of_face_begin(struct BMIter__edge_of_face *iter)
674 {
675 iter->l_first = iter->l_next = BM_FACE_FIRST_LOOP(iter->pdata);
676 }
677
bmiter__edge_of_face_step(struct BMIter__edge_of_face * iter)678 void *bmiter__edge_of_face_step(struct BMIter__edge_of_face *iter)
679 {
680 BMLoop *l_curr = iter->l_next;
681
682 if (iter->l_next) {
683 iter->l_next = iter->l_next->next;
684 if (iter->l_next == iter->l_first) {
685 iter->l_next = NULL;
686 }
687 }
688
689 return l_curr ? l_curr->e : NULL;
690 }
691
692 /*
693 * LOOP OF FACE CALLBACKS
694 */
695
bmiter__loop_of_face_begin(struct BMIter__loop_of_face * iter)696 void bmiter__loop_of_face_begin(struct BMIter__loop_of_face *iter)
697 {
698 iter->l_first = iter->l_next = BM_FACE_FIRST_LOOP(iter->pdata);
699 }
700
bmiter__loop_of_face_step(struct BMIter__loop_of_face * iter)701 void *bmiter__loop_of_face_step(struct BMIter__loop_of_face *iter)
702 {
703 BMLoop *l_curr = iter->l_next;
704
705 if (iter->l_next) {
706 iter->l_next = iter->l_next->next;
707 if (iter->l_next == iter->l_first) {
708 iter->l_next = NULL;
709 }
710 }
711
712 return l_curr;
713 }
714