1 /*===========================================================================
2 *
3 *                            PUBLIC DOMAIN NOTICE
4 *               National Center for Biotechnology Information
5 *
6 *  This software/database is a "United States Government Work" under the
7 *  terms of the United States Copyright Act.  It was written as part of
8 *  the author's official duties as a United States Government employee and
9 *  thus cannot be copyrighted.  This software/database is freely available
10 *  to the public for use. The National Library of Medicine and the U.S.
11 *  Government have not placed any restriction on its use or reproduction.
12 *
13 *  Although all reasonable efforts have been taken to ensure the accuracy
14 *  and reliability of the software and data, the NLM and the U.S.
15 *  Government do not and cannot warrant the performance or results that
16 *  may be obtained by using this software or data. The NLM and the U.S.
17 *  Government disclaim all warranties, express or implied, including
18 *  warranties of performance, merchantability or fitness for any particular
19 *  purpose.
20 *
21 *  Please cite the author in any work or product based on this material.
22 *
23 * ===========================================================================
24 *
25 */
26 #include <align/extern.h>
27 
28 #include <klib/rc.h>
29 #include <klib/vector.h>
30 #include <klib/refcount.h>
31 #include <klib/sort.h>
32 #include <klib/text.h>
33 #include <klib/out.h>
34 #include <insdc/insdc.h>
35 #include <align/manager.h>
36 #include <align/iterator.h>
37 #include <sysalloc.h>
38 
39 #include "debug.h"
40 
41 #include <stdlib.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <assert.h>
45 
46 
47 typedef struct window
48 {
49     INSDC_coord_zero first;
50     INSDC_coord_len len;
51 } window;
52 
53 
54 typedef struct pi_entry
55 {
56     DLNode n;                       /* to have it in a DLList */
57     PlacementIterator *pi;          /* the placement-iterator we have added */
58     window nxt_avail;               /* the next available position of the placement-iterator */
59 } pi_entry;
60 
61 
62 typedef struct pi_window
63 {
64     DLNode n;                       /* to have it in a DLList */
65     window w;                       /* the window of the placement-iterator */
66     DLList pi_entries;              /* it has a DLList of pi_entry-struct's */
67     uint32_t count;                 /* how many entries do we have */
68 } pi_window;
69 
70 
71 typedef struct pi_ref
72 {
73     DLNode n;                       /* to have it in a DLList */
74     char * name;                    /* the name of the reference it referes to */
75     window outer;                   /* the sum of all windows it has... */
76     bool outer_initialized;         /* has the outer-window been initialized */
77     DLList pi_windows;              /* it has a DLList of pi_window-struct's */
78 } pi_ref;
79 
80 
81 struct PlacementSetIterator
82 {
83     KRefcount refcount;
84     struct AlignMgr const *amgr;    /* the alignment-manager... ( right now: we store it, but that's it )*/
85     DLList pi_refs;                 /* a list of references we have to iterate over... */
86     pi_ref * current_ref;           /* what is the current reference, we are handling ? */
87     pi_window * current_window;     /* what is the current window, we are handling ? */
88     pi_entry * current_entry;       /* what is the current pi-entry, we are handling ? */
89 };
90 
91 
92 /* =================================================================================================== */
93 
94 
AlignMgrMakePlacementSetIterator(struct AlignMgr const * self,PlacementSetIterator ** iter)95 LIB_EXPORT rc_t CC AlignMgrMakePlacementSetIterator ( struct AlignMgr const *self,
96     PlacementSetIterator **iter )
97 {
98     rc_t rc = 0;
99     if ( self == NULL )
100         rc = RC( rcAlign, rcIterator, rcConstructing, rcSelf, rcNull );
101     else
102     {
103         if ( iter == NULL  )
104             rc = RC( rcAlign, rcIterator, rcConstructing, rcParam, rcNull );
105         else
106         {
107             PlacementSetIterator * psi = calloc( sizeof * psi, 1 );
108             if ( psi == NULL )
109                 rc = RC( rcAlign, rcIterator, rcConstructing, rcMemory, rcExhausted );
110             else
111             {
112                 rc = AlignMgrAddRef ( self );
113                 if ( rc == 0 )
114                 {
115                     KRefcountInit( &psi->refcount, 1, "PlacementSetIterator", "Make", "align" );
116                     psi->amgr = self;
117                     psi->current_ref = NULL;          /* we don't know that yet */
118                     psi->current_window = NULL;
119                     psi->current_entry = NULL;
120                     DLListInit( &psi->pi_refs );
121                 }
122             }
123             if ( rc == 0 )
124                 *iter = psi;
125             else
126                 free( psi );
127         }
128     }
129 
130     return rc;
131 }
132 
133 
134 /* =================================================================================================== */
135 
136 
cmp_pchar(const char * a,const char * b)137 static int cmp_pchar( const char * a, const char * b )
138 {
139     int res = 0;
140     if ( ( a != NULL )&&( b != NULL ) )
141     {
142         size_t len_a = string_size( a );
143         size_t len_b = string_size( b );
144         res = string_cmp ( a, len_a, b, len_b, ( len_a < len_b ) ? len_b : len_a );
145     }
146     return res;
147 }
148 
149 
150 /* =================================================================================================== */
151 
152 
153 typedef struct pi_ref_cb_ctx
154 {
155     const char * name;
156     pi_ref *res;
157 } pi_ref_cb_ctx;
158 
159 
find_pi_ref_callback(DLNode * n,void * data)160 static bool CC find_pi_ref_callback( DLNode *n, void *data )
161 {
162     pi_ref_cb_ctx *ctx = ( pi_ref_cb_ctx * )data;
163     pi_ref * pr = ( pi_ref * ) n;
164     bool res = ( cmp_pchar( ctx->name, pr->name ) == 0 );
165     if ( res )
166     {
167         ctx->res = pr;
168     }
169     return res;
170 }
171 
172 
find_pi_ref(const DLList * list,const char * name)173 static pi_ref * find_pi_ref( const DLList * list, const char * name )
174 {
175     pi_ref_cb_ctx ctx;
176     ctx.res = NULL;
177     ctx.name = name;
178     DLListDoUntil ( list, false, find_pi_ref_callback, &ctx );
179     return ctx.res;
180 }
181 
182 
183 /* =================================================================================================== */
184 
185 typedef struct pi_window_cb_ctx
186 {
187     window *w;
188     pi_window *res;
189 } pi_window_cb_ctx;
190 
191 
find_pi_window_callback(DLNode * n,void * data)192 static bool CC find_pi_window_callback( DLNode *n, void *data )
193 {
194     pi_window_cb_ctx *ctx = ( pi_window_cb_ctx * )data;
195     pi_window * pw = ( pi_window * ) n;
196     bool res = ( pw->w.first == ctx->w->first && pw->w.len == ctx->w->len );
197     if ( res )
198         ctx->res = pw;
199     return res;
200 }
201 
202 
find_pi_window(const DLList * list,window * w)203 static pi_window * find_pi_window( const DLList * list, window * w )
204 {
205     pi_window_cb_ctx ctx;
206     ctx.res = NULL;
207     ctx.w = w;
208     DLListDoUntil ( list, false, find_pi_window_callback, &ctx );
209     return ctx.res;
210 }
211 
212 
213 /* =================================================================================================== */
214 
215 
make_pi_window(pi_window ** pw,DLList * list,window * w)216 static rc_t make_pi_window( pi_window ** pw, DLList * list, window * w )
217 {
218     rc_t rc = 0;
219     *pw = calloc( 1, sizeof ** pw );
220     if ( *pw == NULL )
221         rc = RC( rcAlign, rcIterator, rcConstructing, rcMemory, rcExhausted );
222     else
223     {
224         (*pw)->w.first = w->first;
225         (*pw)->w.len = w->len;
226         DLListInit( &( (*pw)->pi_entries ) );
227         DLListPushTail ( list, ( DLNode * )(*pw) );
228     }
229     return rc;
230 }
231 
232 
add_to_pi_window(pi_window * pw,PlacementIterator * pi)233 static rc_t add_to_pi_window( pi_window * pw, PlacementIterator *pi )
234 {
235     rc_t rc = 0;
236     pi_entry * pie = calloc( 1, sizeof *pie );
237     if ( pie == NULL )
238         rc = RC( rcAlign, rcIterator, rcConstructing, rcMemory, rcExhausted );
239     else
240     {
241         rc = PlacementIteratorNextAvailPos ( pi, &(pie->nxt_avail.first), &(pie->nxt_avail.len) );
242         if ( rc == 0 )
243         {
244             pie->pi = pi;  /* store the placement-iterator in it's entry-struct */
245             DLListPushTail ( &pw->pi_entries, ( DLNode * )pie );
246             pw->count += 1;
247         }
248         else
249         {
250             free( pie );
251             ALIGN_DBG( "PlacementIter has no placements...", 0 );
252         }
253     }
254     return rc;
255 }
256 
257 
258 /* =================================================================================================== */
259 
260 
make_pi_ref(pi_ref ** pr,DLList * list,const char * name)261 static rc_t make_pi_ref( pi_ref ** pr, DLList * list, const char * name )
262 {
263     rc_t rc = 0;
264     *pr = calloc( 1, sizeof ** pr );
265     if ( *pr == NULL )
266         rc = RC( rcAlign, rcIterator, rcConstructing, rcMemory, rcExhausted );
267     else
268     {
269         (*pr)->name = string_dup_measure ( name, NULL );
270         DLListInit( &( (*pr)->pi_windows ) );
271         DLListPushTail ( list, ( DLNode * )(*pr) );
272     }
273     return rc;
274 }
275 
276 
add_to_pi_ref(pi_ref * pr,window * w,PlacementIterator * pi)277 static rc_t add_to_pi_ref( pi_ref * pr, window * w, PlacementIterator *pi )
278 {
279     rc_t rc = 0;
280     pi_window * pw = find_pi_window( &pr->pi_windows, w );
281 
282     if ( pw == NULL )
283         rc = make_pi_window( &pw, &pr->pi_windows, w );
284     if ( rc == 0 )
285         rc = add_to_pi_window( pw, pi );
286 
287     if ( rc == 0 )
288     {
289         /* keep track of the outer window... */
290         if ( DLListHead( &pr->pi_windows ) == NULL )
291         {
292             /* first window ?*/
293             pr->outer.first = w->first;
294             pr->outer.len = w->len;
295         }
296         else
297         {
298             if ( w->first < pr->outer.first )
299                 pr->outer.first = w->first;
300             if ( w->first + w->len > pr->outer.first + pr->outer.len )
301                 pr->outer.len = ( ( w->first + w->len ) - pr->outer.first ) + 1;
302         }
303     }
304     else if ( ( pw != NULL )&&( GetRCState( rc ) == rcDone ) )
305     {
306         /* add_to_pi_window() was not successful because iterator has no
307            alignments int the requested window, that means we have to delete
308            the window if it is empty */
309         if ( pw->count == 0 )
310         {
311             /* first we have to take the pw out of the pr->pi_windows - list...
312                it was pushed at the tail of it, so we pop it from there */
313             DLListPopTail( &pr->pi_windows );
314             /* because it is empty ( count == 0 ) we can just free it now */
315             free( pw );
316         }
317     }
318     return rc;
319 }
320 
321 
322 /* =================================================================================================== */
323 
324 
PlacementSetIteratorAddPlacementIterator(PlacementSetIterator * self,PlacementIterator * pi)325 LIB_EXPORT rc_t CC PlacementSetIteratorAddPlacementIterator ( PlacementSetIterator *self,
326     PlacementIterator *pi )
327 {
328     rc_t rc = 0;
329     if ( self == NULL )
330         rc = RC( rcAlign, rcIterator, rcConstructing, rcSelf, rcNull );
331     else
332     {
333         if ( pi == NULL  )
334             rc = RC( rcAlign, rcIterator, rcConstructing, rcParam, rcNull );
335         else
336         {
337             const char * name;      /* what reference are we aligning against */
338             window w;               /* where does the pi start/end, against said reference */
339 
340             /* to find the name of the reference used, important for adding the iterator */
341             rc = PlacementIteratorRefWindow ( pi, &name, &(w.first), &(w.len) );
342             if ( rc == 0 )
343             {
344                 pi_ref * pr = find_pi_ref( &self->pi_refs, name );
345                 /* if we do not have a pi_ref yet with this name: make one! */
346                 if ( pr == NULL )
347                     rc = make_pi_ref( &pr, &self->pi_refs, name );
348                 /* add the placement-iterator to the newly-made or existing pi_ref! */
349                 if ( rc == 0 )
350                     rc = add_to_pi_ref( pr, &w, pi );
351             }
352         }
353     }
354     return rc;
355 }
356 
357 
PlacementSetIteratorAddRef(const PlacementSetIterator * cself)358 LIB_EXPORT rc_t CC PlacementSetIteratorAddRef ( const PlacementSetIterator *cself )
359 {
360     rc_t rc = 0;
361     if ( cself == NULL )
362         rc = RC( rcAlign, rcIterator, rcAttaching, rcSelf, rcNull );
363     else
364     {
365         if ( KRefcountAdd( &cself->refcount, "PlacementSetIterator" ) != krefOkay )
366         {
367             rc = RC( rcAlign, rcIterator, rcAttaching, rcError, rcUnexpected );
368         }
369     }
370     return rc;
371 }
372 
373 
374 /* =================================================================================================== */
375 
376 
pi_entry_whacker(DLNode * n,void * data)377 static void CC pi_entry_whacker( DLNode *n, void *data )
378 {
379     pi_entry * pie = ( pi_entry * )n;
380     if ( pie->pi != NULL )
381     {
382         PlacementIteratorRelease ( pie->pi );
383         pie->pi = NULL;
384     }
385     free( pie );
386 }
387 
pi_window_whacker(DLNode * n,void * data)388 static void CC pi_window_whacker( DLNode *n, void *data )
389 {
390     pi_window * pw = ( pi_window * )n;
391     DLListWhack ( &pw->pi_entries, pi_entry_whacker, NULL );
392     free( pw );
393 }
394 
pi_ref_whacker(DLNode * n,void * data)395 static void CC pi_ref_whacker( DLNode *n, void *data )
396 {
397     pi_ref * pr = ( pi_ref * )n;
398     DLListWhack ( &pr->pi_windows, pi_window_whacker, NULL );
399     free( pr->name );
400     free( pr );
401 }
402 
403 
pl_set_iter_clear_curr_ref_window(PlacementSetIterator * self)404 static void pl_set_iter_clear_curr_ref_window( PlacementSetIterator *self )
405 {
406     if ( self->current_window != NULL )
407     {
408         pi_window_whacker( (DLNode *)self->current_window, NULL );
409         self->current_window = NULL;
410     }
411 }
412 
413 
pl_set_iter_clear_curr_ref(PlacementSetIterator * self)414 static void pl_set_iter_clear_curr_ref( PlacementSetIterator *self )
415 {
416     if ( self->current_ref != NULL )
417     {
418         pi_ref_whacker( (DLNode *)self->current_ref, NULL );
419         self->current_ref = NULL;
420     }
421 }
422 
423 /* =================================================================================================== */
424 
425 
PlacementSetIteratorRelease(const PlacementSetIterator * cself)426 LIB_EXPORT rc_t CC PlacementSetIteratorRelease ( const PlacementSetIterator *cself )
427 {
428     rc_t rc = 0;
429     if ( cself == NULL )
430         rc = RC( rcAlign, rcIterator, rcReleasing, rcSelf, rcNull );
431     else
432     {
433         if ( KRefcountDrop( &cself->refcount, "PlacementSetIterator" ) == krefWhack )
434         {
435             PlacementSetIterator * self = ( PlacementSetIterator * ) cself;
436 
437             pl_set_iter_clear_curr_ref_window( self );
438             pl_set_iter_clear_curr_ref( self );
439 
440             /* release the DLList of pi-ref's and the pi's in it... */
441             DLListWhack ( &self->pi_refs, pi_ref_whacker, NULL );
442 
443             AlignMgrRelease ( self->amgr );
444 
445             free( self );
446         }
447     }
448     return rc;
449 }
450 
451 
PlacementSetIteratorNextReference(PlacementSetIterator * self,INSDC_coord_zero * first_pos,INSDC_coord_len * len,struct ReferenceObj const ** refobj)452 LIB_EXPORT rc_t CC PlacementSetIteratorNextReference ( PlacementSetIterator *self,
453     INSDC_coord_zero *first_pos, INSDC_coord_len *len, struct ReferenceObj const ** refobj )
454 {
455     rc_t rc = 0;
456     if ( refobj != NULL ) { *refobj = NULL; }
457 
458     if ( self == NULL )
459         return RC( rcAlign, rcIterator, rcReleasing, rcSelf, rcNull );
460 
461     pl_set_iter_clear_curr_ref_window( self );
462     pl_set_iter_clear_curr_ref( self );
463     self->current_entry = NULL;     /* what is the current pi-entry, we are handling ? */
464 
465     /* !!! here we are taking the next reference from the top of the list */
466     self->current_ref = ( pi_ref * )DLListPopHead ( &self->pi_refs );
467 
468     if ( self->current_ref == NULL )
469     {
470         return SILENT_RC( rcAlign, rcIterator, rcAccessing, rcOffset, rcDone );
471     }
472 
473     if ( first_pos != NULL ) *first_pos = self->current_ref->outer.first;
474     if ( len != NULL) *len = self->current_ref->outer.len;
475 
476     /* if the caller wants to know the ref-obj... */
477     if ( refobj != NULL )
478     {
479         pi_window *pw = ( pi_window * )DLListHead( &(self->current_ref->pi_windows) );
480         if ( pw != NULL )
481         {
482             pi_entry * pie = ( pi_entry * )DLListHead( &(pw->pi_entries) );
483             if ( pie != NULL )
484             {
485                 rc = PlacementIteratorRefObj( pie->pi, refobj );
486             }
487         }
488     }
489     return rc;
490 }
491 
492 
PlacementSetIteratorNextWindow(PlacementSetIterator * self,INSDC_coord_zero * first_pos,INSDC_coord_len * len)493 LIB_EXPORT rc_t CC PlacementSetIteratorNextWindow ( PlacementSetIterator *self,
494     INSDC_coord_zero *first_pos, INSDC_coord_len *len )
495 {
496     rc_t rc = 0;
497     if ( first_pos != NULL ) { *first_pos = 0; }
498     if ( len != NULL ) { *len = 0; }
499 
500     if ( self == NULL )
501         return RC( rcAlign, rcIterator, rcReleasing, rcSelf, rcNull );
502 
503     self->current_entry = NULL;     /* what is the current pi-entry, we are handling ? */
504 
505     if ( self->current_ref == NULL )
506     {
507         return SILENT_RC( rcAlign, rcIterator, rcAccessing, rcOffset, rcDone );
508     }
509 
510     pl_set_iter_clear_curr_ref_window( self );
511 
512     /* !!! here we are taking the next window from the top of the list */
513     self->current_window = ( pi_window * )DLListPopHead ( &(self->current_ref->pi_windows) );
514 
515     /* check if we have reached the last window on this reference... */
516     if ( self->current_window == NULL )
517     {
518         return SILENT_RC( rcAlign, rcIterator, rcAccessing, rcOffset, rcDone );
519     }
520 
521     /* point to the first entry in this window... */
522     self->current_entry = ( pi_entry * )DLListHead( &(self->current_window->pi_entries) );
523 
524     /* if the caller wants to know first_pos / len */
525     if ( first_pos != NULL )
526     {
527         *first_pos = self->current_window->w.first;
528     }
529     if ( len != NULL )
530     {
531         *len = self->current_window->w.len;
532     }
533 
534     return rc;
535 }
536 
537 typedef struct pi_ref_nxt_avail_pos_ctx
538 {
539     uint32_t count;
540     INSDC_coord_zero min_pos;
541     INSDC_coord_len min_len;
542     bool min_pos_initialized;
543     rc_t rc;
544 } pi_ref_nxt_avail_pos_ctx;
545 
nxt_avail_pos_cb(DLNode * n,void * data)546 static void CC nxt_avail_pos_cb( DLNode * n, void * data )
547 {
548     pi_ref_nxt_avail_pos_ctx * ctx = ( pi_ref_nxt_avail_pos_ctx * ) data;
549     if ( ctx->rc == 0 )
550     {
551         pi_entry * pie = ( pi_entry * )n;
552         rc_t rc = PlacementIteratorNextAvailPos ( pie->pi, &(pie->nxt_avail.first), &(pie->nxt_avail.len) );
553         if ( rc == 0 )
554         {
555 /*            OUTMSG(( "nxt_avail.first=%u w.last=%u\n", pie->nxt_avail.first, pie->w.last )); */
556             ( ctx->count )++;
557             if ( ctx->min_pos_initialized )
558             {
559                 if ( pie->nxt_avail.first < ctx->min_pos )
560                 {
561                     ctx->min_pos = pie->nxt_avail.first;
562                     ctx->min_len = pie->nxt_avail.len;
563                 }
564             }
565             else
566             {
567                 ctx->min_pos = pie->nxt_avail.first;
568                 ctx->min_len = pie->nxt_avail.len;
569                 ctx->min_pos_initialized = true;
570             }
571         }
572         else
573         {
574             if ( GetRCState( rc ) != rcDone )
575                 ctx->rc = rc;
576         }
577     }
578 }
579 
580 
PlacementSetIteratorNextAvailPos(const PlacementSetIterator * cself,INSDC_coord_zero * pos,INSDC_coord_len * len)581 LIB_EXPORT rc_t CC PlacementSetIteratorNextAvailPos ( const PlacementSetIterator *cself,
582     INSDC_coord_zero *pos, INSDC_coord_len *len )
583 {
584     rc_t rc = 0;
585     if ( cself == NULL )
586         rc = RC( rcAlign, rcIterator, rcAccessing, rcSelf, rcNull );
587     else
588     {
589         if ( pos == NULL )
590             rc = RC( rcAlign, rcIterator, rcAccessing, rcParam, rcNull );
591         else
592         {
593             PlacementSetIterator *self = ( PlacementSetIterator * )cself;
594             if ( self->current_ref == NULL || self->current_window == NULL )
595             {
596                 rc = SILENT_RC( rcAlign, rcIterator, rcAccessing, rcOffset, rcDone );
597             }
598             else
599             {
600                 /* loop through all the pi_entry int the current_pi_ref */
601                 pi_ref_nxt_avail_pos_ctx ctx;
602                 ctx.count = 0;
603                 ctx.rc = 0;
604                 ctx.min_pos = 0;
605                 ctx.min_len = 0;
606                 ctx.min_pos_initialized = false;
607                 DLListForEach ( &(self->current_window->pi_entries),
608                                 false, nxt_avail_pos_cb, &ctx );
609                 rc = ctx.rc;
610                 if ( ctx.count == 0 )
611                 {
612                     rc = SILENT_RC( rcAlign, rcIterator, rcAccessing, rcOffset, rcDone );
613                 }
614                 else
615                 {
616                     *pos = ctx.min_pos;
617                     if ( len != NULL )
618                     {
619                         *len = ctx.min_len;
620                     }
621                 }
622             }
623         }
624     }
625     return rc;
626 }
627 
628 
PlacementSetIteratorNextRecordAt(PlacementSetIterator * self,INSDC_coord_zero pos,const PlacementRecord ** rec)629 LIB_EXPORT rc_t CC PlacementSetIteratorNextRecordAt ( PlacementSetIterator *self,
630     INSDC_coord_zero pos, const PlacementRecord **rec )
631 {
632     rc_t rc = 0;
633     pi_window * pw;
634     bool done;
635 
636     if ( rec == NULL )
637         return RC( rcAlign, rcIterator, rcAccessing, rcParam, rcNull );
638     *rec = NULL;
639     if ( self == NULL )
640         return RC( rcAlign, rcIterator, rcAccessing, rcSelf, rcNull );
641     if ( self->current_ref == NULL )
642     {
643         /* no more reference to iterator over! the iterator is done! */
644         return SILENT_RC( rcAlign, rcIterator, rcAccessing, rcOffset, rcDone );
645     }
646     if ( self->current_window == NULL )
647     {
648         /* no more windows to iterator over! the iterator is done! */
649         return SILENT_RC( rcAlign, rcIterator, rcAccessing, rcOffset, rcDone );
650     }
651 
652     pw = self->current_window;
653     done = false;
654     do
655     {
656         if ( self->current_entry == NULL )
657         {
658             self->current_entry = ( pi_entry * )DLListHead( &(pw->pi_entries) );
659         }
660         done = ( self->current_entry == NULL );
661         rc = ( done ? SILENT_RC( rcAlign, rcIterator, rcAccessing, rcOffset, rcDone ) : 0 );
662         if ( rc == 0 )
663         {
664             rc = PlacementIteratorNextRecordAt ( self->current_entry->pi, pos, rec );
665             done = ( GetRCState( rc ) != rcDone );
666             if ( !done )
667             {
668                 self->current_entry = ( pi_entry * )DLNodeNext( ( DLNode * )self->current_entry );
669                 done = ( self->current_entry == NULL );
670                 rc = ( done ? SILENT_RC( rcAlign, rcIterator, rcAccessing, rcOffset, rcDone ) : 0 );
671             }
672         }
673     } while ( !done );
674     return rc;
675 }
676 
677 
PlacementSetIteratorNextIdAt(PlacementSetIterator * self,INSDC_coord_zero pos,int64_t * row_id,INSDC_coord_len * len)678 LIB_EXPORT rc_t CC PlacementSetIteratorNextIdAt ( PlacementSetIterator *self,
679     INSDC_coord_zero pos, int64_t *row_id, INSDC_coord_len *len )
680 {
681     const PlacementRecord *rec;
682     rc_t rc = PlacementSetIteratorNextRecordAt ( self, pos, &rec );
683     if ( rc == 0 )
684     {
685         if ( row_id != NULL ) *row_id = rec->id;
686         if ( len != NULL ) *len = rec->len;
687     }
688     return rc;
689 }
690