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