amp

pcm player/editor for plan9
git clone git://nsmpr.xyz/amp.git
Log | Files | Refs | README

pages.c (3327B)


      1 #include <u.h>
      2 #include <libc.h>
      3 
      4 #include "pages.h"
      5 
      6 Array *
      7 allocarray(long len)
      8 {
      9 	Array *new = malloc(sizeof(ArHeader) + len);
     10 	assert(new != nil);
     11 	new->len = len;
     12 	new->ref = 0;
     13 	return new;
     14 }
     15 
     16 ArSlice *
     17 allocarslice(Array *ar, long start, long len)
     18 {
     19 	ArSlice *new = malloc(sizeof(ArSlice));
     20 	new->ar = ar;
     21 	new->p = ar->p + start;
     22 	new->len = len;
     23 	new->cap = ar->len - start;
     24 	assert(start + len <= ar->len);
     25 	return new;
     26 }
     27 
     28 Page *
     29 allocpage(void)
     30 {
     31 	Array *ar = allocarray(PageSize);
     32 	memset(ar->p, '?', PageSize);
     33 	ArSlice *as = allocarslice(ar, 0, PageSize);
     34 	ar->ref++;
     35 	Page *new = malloc(sizeof(Page));
     36 	new->as = as;
     37 	new->prev = nil;
     38 	new->next = nil;
     39 	return new;
     40 }
     41 
     42 Page *
     43 duppage(Page *old)
     44 {
     45 	Page *new = malloc(sizeof(Page));
     46 	ArSlice *as = malloc(sizeof(ArSlice));
     47 	new->as = as;
     48 	new->prev = old->prev;
     49 	new->next = old->next;
     50 	as->ar = old->as->ar;
     51 	as->p = old->as->p;
     52 	as->len = old->as->len;
     53 	as->cap = old->as->cap;
     54 	as->ar->ref++;
     55 	return new;
     56 }
     57 
     58 void
     59 freepage(Page *pg)
     60 {
     61 	pg->as->ar->ref--;
     62 	if (pg->as->ar->ref <= 0) {
     63 		free(pg->as->ar);
     64 	}
     65 	free(pg->as);
     66 	free(pg);
     67 }
     68 
     69 long
     70 pbwrite(PBuf *pb, void *buf, long nbytes, vlong offset)
     71 {
     72 	Page *pgpt;
     73 	long n, nwritten = 0;
     74 
     75 	// TODO: move this section to fs.c/fwrite/fdata
     76 	// or create separate pbgrow() function
     77 	// also, last page's len should be shortened accordingly
     78 	// [[[
     79 	while (offset + nbytes > pb->size) {
     80 		addpage(pb);
     81 	}
     82 	if (pb->length < offset + nbytes) pb->length = offset + nbytes;
     83 	// ]]]
     84 
     85 	pgpt = pb->start;
     86 	if (offset >= pb->length) nbytes = 0;
     87 	if (offset + nbytes >= pb->length) {
     88 		nbytes = (pb->length - offset);
     89 	}
     90 	while (nbytes > 0) {
     91 		if (pgpt == nil) {
     92 			break;
     93 		}
     94 		if (offset >= pgpt->as->len) {
     95 			offset -= pgpt->as->len;
     96 			pgpt = pgpt->next;
     97 			continue;
     98 		}
     99 		n = nbytes;
    100 		if (pgpt->as->len - offset < n) n = pgpt->as->len - offset;
    101 		memcpy(pgpt->as->p + offset, buf, n);
    102 		nwritten += n;
    103 		buf = (char *)buf + n;
    104 		offset += n;
    105 		nbytes -= n;
    106 	}
    107 	return nwritten;
    108 }
    109 
    110 long
    111 pbread(PBuf *pb, void *buf, long nbytes, vlong offset)
    112 {
    113 	Page *pgpt = pb->start;
    114 	long n, nread = 0;
    115 	if (offset >= pb->length) nbytes = 0;
    116 	if (offset + nbytes >= pb->length) {
    117 		nbytes = (pb->length - offset);
    118 	}
    119 	while (nbytes > 0) {
    120 		if (pgpt == nil) {
    121 			break;
    122 		}
    123 		if (offset >= pgpt->as->len) {
    124 			offset -= pgpt->as->len;
    125 			pgpt = pgpt->next;
    126 			continue;
    127 		}
    128 		n = nbytes;
    129 		if (pgpt->as->len - offset < n) n = pgpt->as->len - offset;
    130 		memcpy(buf, pgpt->as->p + offset, n);
    131 		nread += n;
    132 		buf = (char *)buf + n;
    133 		offset += n;
    134 		nbytes -= n;
    135 	}
    136 	return nread;
    137 }
    138 
    139 Page *
    140 addpage(PBuf *pb)
    141 {
    142 	Page *new = allocpage();
    143 	if ((pb->start == nil) || (pb->end == nil)) {
    144 		pb->start = new;
    145 		pb->end = new;
    146 	} else {
    147 		new->prev = pb->end;
    148 		pb->end->next = new;
    149 		pb->end = new;
    150 	}
    151 	pb->size += new->as->len;
    152 	return new;
    153 }
    154 
    155 Page *
    156 splitpage(PBuf *pb, vlong offset)
    157 {
    158 	vlong d, count = 0;
    159 	Page *sp = pb->start;
    160 	// find page at offset
    161 	while ((sp != nil) && (count + sp->as->len < offset)) {
    162 		count += sp->as->len;
    163 		sp = sp->next;
    164 	}
    165 	if (sp == nil) return nil;
    166 	d = offset - count;
    167 	if (d > 0) {
    168 		Page *np = duppage(sp);
    169 		np->as->len = d;
    170 		np->next = sp;
    171 		if (np->prev != nil) np->prev->next = np;
    172 		else pb->start = np;
    173 		sp->as->len -= d;
    174 		sp->as->cap -= d;
    175 		sp->as->p += d;
    176 		sp->prev = np;
    177 	}
    178 	return sp;
    179 }