Update TODO a bit.
22 struct razor_set_section {
28 struct razor_set_header {
31 struct razor_set_section sections[0];
34 #define RAZOR_MAGIC 0x7a7a7a7a
35 #define RAZOR_VERSION 1
37 #define RAZOR_PACKAGES 0
38 #define RAZOR_REQUIRES 1
39 #define RAZOR_PROVIDES 2
40 #define RAZOR_STRING_POOL 3
41 #define RAZOR_PACKAGE_POOL 4
42 #define RAZOR_REQUIRES_POOL 5
43 #define RAZOR_PROVIDES_POOL 6
45 struct razor_package {
47 unsigned long version;
48 unsigned long requires;
49 unsigned long provides;
52 struct razor_property {
54 unsigned long version;
55 unsigned long packages;
59 struct array string_pool;
60 struct array packages;
61 struct array package_pool;
62 struct array requires;
63 struct array provides;
64 struct array requires_pool;
65 struct array provides_pool;
66 struct razor_set_header *header;
69 struct import_property_context {
74 struct razor_importer {
75 struct razor_set *set;
77 struct import_property_context requires;
78 struct import_property_context provides;
79 struct razor_package *package;
83 array_init(struct array *array)
85 memset(array, 0, sizeof *array);
89 array_release(struct array *array)
95 array_add(struct array *array, int size)
100 if (array->alloc > 0)
101 alloc = array->alloc;
105 while (alloc < array->size + size)
108 if (array->alloc < alloc) {
109 data = realloc(array->data, alloc);
113 array->alloc = alloc;
116 p = array->data + array->size;
123 write_to_fd(int fd, void *p, size_t size)
129 len = write(fd, p, rest);
149 struct razor_set_section razor_sections[] = {
150 { RAZOR_PACKAGES, offsetof(struct razor_set, packages) },
151 { RAZOR_REQUIRES, offsetof(struct razor_set, requires) },
152 { RAZOR_PROVIDES, offsetof(struct razor_set, provides) },
153 { RAZOR_STRING_POOL, offsetof(struct razor_set, string_pool) },
154 { RAZOR_PACKAGE_POOL, offsetof(struct razor_set, package_pool) },
155 { RAZOR_REQUIRES_POOL, offsetof(struct razor_set, requires_pool) },
156 { RAZOR_PROVIDES_POOL, offsetof(struct razor_set, provides_pool) },
160 razor_set_create(void)
162 return zalloc(sizeof(struct razor_set));
166 razor_set_open(const char *filename)
168 struct razor_set *set;
169 struct razor_set_section *s;
174 set = zalloc(sizeof *set);
175 fd = open(filename, O_RDONLY);
176 if (fstat(fd, &stat) < 0)
178 set->header = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
179 if (set->header == MAP_FAILED) {
184 for (s = set->header->sections; ~s->type; s++) {
185 if (s->type >= ARRAY_SIZE(razor_sections))
187 if (s->type != razor_sections[s->type].type)
189 array = (void *) set + razor_sections[s->type].offset;
190 array->data = (void *) set->header + s->offset;
191 array->size = s->size;
192 array->alloc = s->size;
200 razor_set_destroy(struct razor_set *set)
207 for (i = 0; set->header->sections[i].type; i++)
209 size = set->header->sections[i].type;
210 munmap(set->header, size);
212 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
213 a = (void *) set + razor_sections[i].offset;
222 razor_set_write(struct razor_set *set, const char *filename)
225 struct razor_set_header *header = (struct razor_set_header *) data;
227 unsigned long offset;
230 memset(data, 0, sizeof data);
231 header->magic = RAZOR_MAGIC;
232 header->version = RAZOR_VERSION;
233 offset = sizeof data;
235 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
236 if (razor_sections[i].type != i)
238 a = (void *) set + razor_sections[i].offset;
239 header->sections[i].type = i;
240 header->sections[i].offset = offset;
241 header->sections[i].size = a->size;
242 offset += (a->size + 4095) & ~4095;
245 header->sections[i].type = ~0;
246 header->sections[i].offset = 0;
247 header->sections[i].size = 0;
249 fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
253 write_to_fd(fd, data, sizeof data);
254 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
255 if (razor_sections[i].type != i)
257 a = (void *) set + razor_sections[i].offset;
258 write_to_fd(fd, a->data, (a->size + 4095) & ~4095);
267 hash_string(const char *key)
270 unsigned int hash = 0;
272 for (p = key; *p; p++)
273 hash = (hash * 617) ^ *p;
279 razor_importer_lookup(struct razor_importer *importer, const char *key)
281 unsigned int mask, start, i;
285 pool = importer->set->string_pool.data;
286 mask = importer->buckets.alloc - 1;
287 start = hash_string(key) * sizeof(unsigned long);
289 for (i = 0; i < importer->buckets.alloc; i += sizeof *b) {
290 b = importer->buckets.data + ((start + i) & mask);
295 if (strcmp(key, &pool[*b]) == 0)
303 add_to_string_pool(struct razor_set *set, const char *key)
308 len = strlen(key) + 1;
309 p = array_add(&set->string_pool, len);
312 return p - (char *) set->string_pool.data;
316 add_to_property_pool(struct array *pool, struct array *properties)
320 p = array_add(properties, sizeof *p);
322 p = array_add(pool, properties->size);
323 memcpy(p, properties->data, properties->size);
325 return p - (unsigned long *) pool->data;
329 do_insert(struct razor_importer *importer, unsigned long value)
331 unsigned int mask, start, i;
335 key = (char *) importer->set->string_pool.data + value;
336 mask = importer->buckets.alloc - 1;
337 start = hash_string(key) * sizeof(unsigned long);
339 for (i = 0; i < importer->buckets.alloc; i += sizeof *b) {
340 b = importer->buckets.data + ((start + i) & mask);
349 razor_importer_insert(struct razor_importer *importer, const char *key)
351 unsigned long value, *buckets, *b, *end;
354 alloc = importer->buckets.alloc;
355 array_add(&importer->buckets, 4 * sizeof *buckets);
356 if (alloc != importer->buckets.alloc) {
357 end = importer->buckets.data + alloc;
358 memset(end, 0, importer->buckets.alloc - alloc);
359 for (b = importer->buckets.data; b < end; b++) {
363 do_insert(importer, value);
368 value = add_to_string_pool(importer->set, key);
369 do_insert (importer, value);
375 razor_importer_tokenize(struct razor_importer *importer, const char *string)
380 return razor_importer_tokenize(importer, "");
382 token = razor_importer_lookup(importer, string);
386 return razor_importer_insert(importer, string);
390 razor_importer_begin_package(struct razor_importer *importer,
391 const char *name, const char *version)
393 struct razor_package *p;
395 p = array_add(&importer->set->packages, sizeof *p);
396 p->name = razor_importer_tokenize(importer, name);
397 p->version = razor_importer_tokenize(importer, version);
399 importer->package = p;
400 array_init(&importer->requires.package);
401 array_init(&importer->provides.package);
405 razor_importer_finish_package(struct razor_importer *importer)
407 struct razor_package *p;
409 p = importer->package;
410 p->requires = add_to_property_pool(&importer->set->requires_pool,
411 &importer->requires.package);
412 p->provides = add_to_property_pool(&importer->set->provides_pool,
413 &importer->provides.package);
415 array_release(&importer->requires.package);
416 array_release(&importer->provides.package);
420 razor_importer_add_property(struct razor_importer *importer,
421 struct import_property_context *pctx,
422 const char *name, const char *version)
424 struct razor_property *p;
427 p = array_add(pctx->all, sizeof *p);
428 p->name = razor_importer_tokenize(importer, name);
429 p->version = razor_importer_tokenize(importer, version);
430 p->packages = importer->package -
431 (struct razor_package *) importer->set->packages.data;
433 r = array_add(&pctx->package, sizeof *r);
434 *r = p - (struct razor_property *) pctx->all->data;
438 razor_importer_add_requires(struct razor_importer *importer,
439 const char *name, const char *version)
441 razor_importer_add_property(importer,
442 &importer->requires, name, version);
446 razor_importer_add_provides(struct razor_importer *importer,
447 const char *name, const char *version)
449 razor_importer_add_property(importer,
450 &importer->provides, name, version);
454 razor_importer_add_file(struct razor_importer *importer, const char *name)
458 struct razor_importer *
459 razor_importer_new(void)
461 struct razor_importer *importer;
463 importer = zalloc(sizeof *importer);
464 importer->set = razor_set_create();
465 importer->requires.all = &importer->set->requires;
466 importer->provides.all = &importer->set->provides;
471 typedef int (*compare_with_data_func_t)(const void *p1,
475 struct qsort_context {
477 compare_with_data_func_t compare;
482 qsort_swap(void *p1, void *p2, size_t size)
486 memcpy(buffer, p1, size);
487 memcpy(p1, p2, size);
488 memcpy(p2, buffer, size);
492 __qsort_with_data(void *base, size_t nelem, unsigned long *map,
493 struct qsort_context *ctx)
495 void *p, *start, *end, *pivot;
496 unsigned long *mp, *mstart, *mend, tmp;
497 int left, right, result;
498 size_t size = ctx->size;
502 end = base + nelem * size;
506 pivot = base + (random() % nelem) * size;
509 result = ctx->compare(p, pivot, ctx->data);
511 qsort_swap(p, start, size);
521 } else if (result == 0) {
527 qsort_swap(p, end, size);
536 left = (start - base) / size;
537 right = (base + nelem * size - end) / size;
539 __qsort_with_data(base, left, map, ctx);
541 __qsort_with_data(end, right, mend, ctx);
545 qsort_with_data(void *base, size_t nelem, size_t size,
546 compare_with_data_func_t compare, void *data)
548 struct qsort_context ctx;
553 ctx.compare = compare;
556 map = malloc(nelem * sizeof (unsigned long));
557 for (i = 0; i < nelem; i++)
560 __qsort_with_data(base, nelem, map, &ctx);
566 versioncmp(const char *s1, const char *s2)
572 n1 = strtol(s1, (char **) &p1, 0);
573 n2 = strtol(s2, (char **) &p2, 0);
575 /* Epoch; if one but not the other has an epoch set, default
576 * the epoch-less version to 0. */
577 res = (*p1 == ':') - (*p2 == ':');
582 } else if (res > 0) {
595 if (isdigit(*p1) && isdigit(*p2))
596 return versioncmp(p1, p2);
604 compare_packages(const void *p1, const void *p2, void *data)
606 const struct razor_package *pkg1 = p1, *pkg2 = p2;
607 struct razor_set *set = data;
608 char *pool = set->string_pool.data;
610 if (pkg1->name == pkg2->name)
611 return versioncmp(&pool[pkg1->version], &pool[pkg2->version]);
613 return strcmp(&pool[pkg1->name], &pool[pkg2->name]);
617 compare_properties(const void *p1, const void *p2, void *data)
619 const struct razor_property *prop1 = p1, *prop2 = p2;
620 struct razor_set *set = data;
621 char *pool = set->string_pool.data;
623 if (prop1->name == prop2->name)
624 return versioncmp(&pool[prop1->version], &pool[prop2->version]);
626 return strcmp(&pool[prop1->name], &pool[prop2->name]);
629 static unsigned long *
630 uniqueify_properties(struct razor_set *set, struct array *properties)
632 struct razor_property *rp, *up, *rp_end;
633 struct array *pkgs, *p;
634 unsigned long *map, *rmap, *r;
635 int i, count, unique;
637 count = properties->size / sizeof(struct razor_property);
638 map = qsort_with_data(properties->data,
640 sizeof(struct razor_property),
644 rp_end = properties->data + properties->size;
645 rmap = malloc(count * sizeof *map);
646 pkgs = zalloc(count * sizeof *pkgs);
647 for (rp = properties->data, up = rp, i = 0; rp < rp_end; rp++, i++) {
648 if (rp->name != up->name || rp->version != up->version) {
651 up->version = rp->version;
654 unique = up - (struct razor_property *) properties->data;
655 rmap[map[i]] = unique;
656 r = array_add(&pkgs[unique], sizeof *r);
662 properties->size = (void *) up - properties->data;
664 for (rp = properties->data, p = pkgs; rp < rp_end; rp++, p++) {
665 rp->packages = add_to_property_pool(&set->package_pool, p);
675 remap_links(struct array *links, unsigned long *map)
677 unsigned long *p, *end;
679 end = links->data + links->size;
680 for (p = links->data; p < end; p++)
686 razor_importer_finish(struct razor_importer *importer)
688 struct razor_set *set;
689 unsigned long *map, *rmap;
692 map = uniqueify_properties(importer->set, &importer->set->requires);
693 remap_links(&importer->set->requires_pool, map);
696 map = uniqueify_properties(importer->set, &importer->set->provides);
697 remap_links(&importer->set->provides_pool, map);
700 count = importer->set->packages.size / sizeof(struct razor_package);
701 map = qsort_with_data(importer->set->packages.data,
703 sizeof(struct razor_package),
707 rmap = malloc(count * sizeof *rmap);
708 for (i = 0; i < count; i++)
711 remap_links(&importer->set->package_pool, rmap);
716 array_release(&importer->buckets);
723 razor_set_list(struct razor_set *set)
725 struct razor_package *p, *end;
728 pool = set->string_pool.data;
729 end = set->packages.data + set->packages.size;
730 for (p = set->packages.data; p < end; p++)
731 printf("%s %s\n", &pool[p->name], &pool[p->version]);
734 struct razor_set *bsearch_set;
737 compare_package_name(const void *key, const void *data)
739 const struct razor_package *p = data;
742 pool = bsearch_set->string_pool.data;
744 return strcmp(key, &pool[p->name]);
747 struct razor_package *
748 razor_set_get_package(struct razor_set *set, const char *package)
751 return bsearch(package, set->packages.data,
752 set->packages.size / sizeof(struct razor_package),
753 sizeof(struct razor_package), compare_package_name);
757 compare_property_name(const void *key, const void *data)
759 const struct razor_property *p = data;
762 pool = bsearch_set->string_pool.data;
764 return strcmp(key, &pool[p->name]);
767 struct razor_property *
768 razor_set_get_property(struct razor_set *set,
769 struct array *properties,
770 const char *property)
772 struct razor_property *p, *start;
775 p = bsearch(property, properties->data,
776 properties->size / sizeof(struct razor_property),
777 sizeof(struct razor_property), compare_property_name);
779 start = properties->data;
780 while (p > start && (p - 1)->name == p->name)
787 razor_set_list_all_properties(struct razor_set *set, struct array *properties)
789 struct razor_property *p, *end;
792 pool = set->string_pool.data;
793 end = properties->data + properties->size;
794 for (p = properties->data; p < end; p++)
795 printf("%s %s\n", &pool[p->name], &pool[p->version]);
799 razor_set_list_requires(struct razor_set *set, const char *name)
801 struct razor_property *p, *requires;
802 struct razor_package *package;
807 package = razor_set_get_package(set, name);
808 r = (unsigned long *) set->requires_pool.data +
810 requires = set->requires.data;
811 pool = set->string_pool.data;
814 printf("%s %s\n", &pool[p->name], &pool[p->version]);
817 razor_set_list_all_properties(set, &set->requires);
821 razor_set_list_provides(struct razor_set *set, const char *name)
823 struct razor_property *p, *provides;
824 struct razor_package *package;
829 package = razor_set_get_package(set, name);
830 r = (unsigned long *) set->provides_pool.data +
832 provides = set->provides.data;
833 pool = set->string_pool.data;
836 printf("%s %s\n", &pool[p->name], &pool[p->version]);
839 razor_set_list_all_properties(set, &set->provides);
843 razor_set_list_property_packages(struct razor_set *set,
844 struct array *properties,
848 struct razor_property *property, *end;
849 struct razor_package *p, *packages;
856 property = razor_set_get_property(set, properties, name);
857 packages = set->packages.data;
858 pool = set->string_pool.data;
859 end = properties->data + properties->size;
860 while (property < end && strcmp(name, &pool[property->name]) == 0) {
861 if (version && versioncmp(version, &pool[property->version]) != 0)
863 r = (unsigned long *)
864 set->package_pool.data + property->packages;
868 &pool[p->name], &pool[p->version]);
876 razor_set_list_requires_packages(struct razor_set *set,
880 razor_set_list_property_packages(set, &set->requires, name, version);
884 razor_set_list_provides_packages(struct razor_set *set,
888 razor_set_list_property_packages(set, &set->provides, name, version);
892 razor_set_validate(struct razor_set *set, struct array *unsatisfied)
894 struct razor_property *r, *p, *rend, *pend;
898 p = set->provides.data;
899 rend = set->requires.data + set->requires.size;
900 pend = set->provides.data + set->provides.size;
901 pool = set->string_pool.data;
903 for (r = set->requires.data; r < rend; r++) {
904 while (p < pend && strcmp(&pool[r->name], &pool[p->name]) > 0)
907 /* If there is more than one version of a provides,
908 * seek to the end for the highest version. */
909 while (p + 1 < pend && p->name == (p + 1)->name)
912 /* FIXME: We need to track property flags (<, <=, =
913 * etc) to properly determine if a requires is
914 * satisfied. The current code doesn't track that the
915 * requires a = 1 isn't satisfied by a = 2 provides. */
917 if (p == pend || strcmp(&pool[r->name], &pool[p->name]) != 0 ||
918 versioncmp(&pool[r->version], &pool[p->version]) > 0) {
919 /* FIXME: We ignore file requires for now. */
920 if (pool[r->name] == '/')
922 u = array_add(unsatisfied, sizeof *u);
923 *u = r - (struct razor_property *) set->requires.data;
929 razor_set_list_unsatisfied(struct razor_set *set)
931 struct array unsatisfied;
932 struct razor_property *requires, *r;
933 unsigned long *u, *end;
936 array_init(&unsatisfied);
937 razor_set_validate(set, &unsatisfied);
939 end = unsatisfied.data + unsatisfied.size;
940 requires = set->requires.data;
941 pool = set->string_pool.data;
943 for (u = unsatisfied.data; u < end; u++) {
945 printf("%s %s not satisfied\n",
946 &pool[r->name], &pool[r->version]);
949 array_release(&unsatisfied);
952 #define UPSTREAM_SOURCE 0x80000000ul
953 #define INDEX_MASK 0x00fffffful
956 struct razor_set *set;
957 unsigned long *requires_map;
958 unsigned long *provides_map;
962 prepare_source(struct source *source, struct razor_set *set)
969 count = set->requires.size / sizeof (struct razor_property);
970 size = count * sizeof *source->requires_map;
971 source->requires_map = zalloc(size);
973 count = set->provides.size / sizeof (struct razor_property);
974 size = count * sizeof *source->provides_map;
975 source->provides_map = zalloc(size);
979 add_package(struct razor_importer *importer,
980 struct razor_package *package, struct source *source,
985 struct razor_package *p;
987 pool = source->set->string_pool.data;
988 p = array_add(&importer->set->packages, sizeof *p);
989 p->name = razor_importer_tokenize(importer, &pool[package->name]);
991 p->version = razor_importer_tokenize(importer,
992 &pool[package->version]);
993 p->requires = package->requires;
994 p->provides = package->provides;
996 r = (unsigned long *)
997 source->set->requires_pool.data + package->requires;
999 source->requires_map[*r++] = 1;
1001 r = (unsigned long *)
1002 source->set->provides_pool.data + package->provides;
1004 source->provides_map[*r++] = 1;
1008 /* Build the new package list sorted by merging the two package lists.
1009 * Build new string pool as we go. (for now we just re-use that part of
1012 merge_packages(struct razor_importer *importer,
1013 struct source *source1, struct source *source2,
1014 struct array *packages)
1016 struct razor_package *upstream_packages, *p, *s, *send;
1017 char *spool, *upool;
1018 unsigned long *u, *uend;
1021 upstream_packages = source2->set->packages.data;
1024 uend = packages->data + packages->size;
1025 upool = source2->set->string_pool.data;
1027 s = source1->set->packages.data;
1028 send = source1->set->packages.data + source1->set->packages.size;
1029 spool = source1->set->string_pool.data;
1032 p = upstream_packages + *u;
1035 cmp = strcmp(&spool[s->name], &upool[p->name]);
1036 if (u >= uend || cmp < 0) {
1037 add_package(importer, s, source1, 0);
1039 } else if (cmp == 0) {
1040 add_package(importer, p, source2, UPSTREAM_SOURCE);
1044 add_package(importer, p, source2, UPSTREAM_SOURCE);
1050 static unsigned long
1051 add_property(struct razor_importer *importer, struct array *properties,
1052 const char *name, const char *version)
1054 struct razor_property *p;
1056 p = array_add(properties, sizeof *p);
1057 p->name = razor_importer_tokenize(importer, name);
1058 p->version = razor_importer_tokenize(importer, version);
1060 return p - (struct razor_property *) properties->data;
1064 merge_properties(struct array *properties,
1065 struct razor_importer *importer,
1066 struct razor_set *set1,
1067 struct array *properties1,
1068 unsigned long *map1,
1069 struct razor_set *set2,
1070 struct array *properties2,
1071 unsigned long *map2)
1073 struct razor_property *p1, *p2;
1074 int i, j, cmp, count1, count2;
1075 char *pool1, *pool2;
1079 pool1 = set1->string_pool.data;
1080 pool2 = set2->string_pool.data;
1082 count1 = properties1->size / sizeof *p1;
1083 count2 = properties2->size / sizeof *p2;
1084 while (i < count1 || j < count2) {
1085 if (i < count1 && map1[i] == 0) {
1089 if (j < count2 && map2[j] == 0) {
1093 p1 = (struct razor_property *) properties1->data + i;
1094 p2 = (struct razor_property *) properties2->data + j;
1095 if (i < count1 && j < count2)
1096 cmp = strcmp(&pool1[p1->name], &pool2[p2->name]);
1097 else if (i < count1)
1102 cmp = versioncmp(&pool1[p1->version],
1103 &pool2[p2->version]);
1105 map1[i++] = add_property(importer,
1108 &pool1[p1->version]);
1109 } else if (cmp > 0) {
1110 map2[j++] = add_property(importer,
1113 &pool2[p2->version]);
1115 map1[i++] = map2[j++] = add_property(importer,
1118 &pool1[p1->version]);
1123 static unsigned long
1124 emit_properties(struct array *source_pool, unsigned long index,
1125 unsigned long *map, struct array *pool)
1127 unsigned long r, *p, *q;
1129 r = pool->size / sizeof *q;
1130 p = (unsigned long *) source_pool->data + index;
1132 q = array_add(pool, sizeof *q);
1136 q = array_add(pool, sizeof *q);
1142 /* Rebuild property->packages maps. We can't just remap these, as a
1143 * property may have lost or gained a number of packages. Allocate an
1144 * array per property and loop through the packages and add them to
1145 * the arrays for their properties. */
1147 rebuild_package_lists(struct razor_set *set)
1149 int requires_count, provides_count;
1150 struct array *requires_pkgs, *provides_pkgs, *a;
1151 struct razor_package *pkg, *pkg_end;
1152 struct razor_property *prop, *prop_end;
1153 unsigned long *r, *q, *rpool, *ppool;
1155 requires_count = set->requires.size / sizeof (struct razor_property);
1156 provides_count = set->provides.size / sizeof (struct razor_property);
1157 requires_pkgs = zalloc(requires_count * sizeof *requires_pkgs);
1158 provides_pkgs = zalloc(provides_count * sizeof *provides_pkgs);
1159 pkg_end = set->packages.data + set->packages.size;
1160 rpool = set->requires_pool.data;
1161 ppool = set->provides_pool.data;
1163 for (pkg = set->packages.data; pkg < pkg_end; pkg++) {
1164 for (r = &rpool[pkg->requires]; *r != ~0; r++) {
1165 q = array_add(&requires_pkgs[*r], sizeof *q);
1166 *q = pkg - (struct razor_package *) set->packages.data;
1168 for (r = &ppool[pkg->provides]; *r != ~0; r++) {
1169 q = array_add(&provides_pkgs[*r], sizeof *q);
1170 *q = pkg - (struct razor_package *) set->packages.data;
1174 prop_end = set->requires.data + set->requires.size;
1176 for (prop = set->requires.data; prop < prop_end; prop++, a++) {
1177 prop->packages = add_to_property_pool(&set->requires_pool, a);
1180 free(requires_pkgs);
1182 prop_end = set->provides.data + set->provides.size;
1184 for (prop = set->provides.data; prop < prop_end; prop++, a++) {
1185 prop->packages = add_to_property_pool(&set->provides_pool, a);
1188 free(provides_pkgs);
1191 /* Add packages from 'upstream' to 'set'. The packages to add are
1192 * specified by the 'packages' array, which is a sorted list of
1193 * package indexes. Returns a newly allocated package set. Does not
1194 * enforce validity of the resulting package set.
1196 * This looks more complicated than it is. An easy way to merge two
1197 * package sets would be to just use a razor_importer, but that
1198 * requires resorting, and is thus O(n log n). We can do this in a
1199 * linear sweep, but it gets a little more complicated.
1202 razor_set_add(struct razor_set *set, struct razor_set *upstream,
1203 struct array *packages)
1205 struct razor_set *result;
1206 struct razor_importer *importer;
1207 struct razor_package *p, *pend;
1208 struct source source, upstream_source;
1210 importer = razor_importer_new();
1212 prepare_source(&upstream_source, upstream);
1213 prepare_source(&source, set);
1215 merge_packages(importer, &source, &upstream_source, packages);
1217 /* As we built the package list, we filled out a bitvector of
1218 * the properties that are referenced by the packages in the
1219 * new set. Now we do a parallel loop through the properties
1220 * and emit those marked in the bit vector to the new set. In
1221 * the process, we update the bit vector to actually map from
1222 * indices in the old property list to indices in the new
1223 * property list for both sets. */
1225 merge_properties(&importer->set->requires, importer,
1226 set, &set->requires, source.requires_map,
1227 upstream, &upstream->requires,
1228 upstream_source.requires_map);
1229 merge_properties(&importer->set->provides, importer,
1230 set, &set->provides, source.provides_map,
1231 upstream, &upstream->provides,
1232 upstream_source.provides_map);
1234 /* Now we loop through the packages again and emit the
1235 * property lists, remapped to point to the new properties. */
1237 pend = importer->set->packages.data + importer->set->packages.size;
1238 for (p = importer->set->packages.data; p < pend; p++) {
1241 if (p->name & UPSTREAM_SOURCE)
1242 src = &upstream_source;
1246 p->requires = emit_properties(&src->set->requires_pool,
1249 &importer->set->requires_pool);
1250 p->provides = emit_properties(&src->set->provides_pool,
1253 &importer->set->provides_pool);
1254 p->name &= INDEX_MASK;
1257 rebuild_package_lists(importer->set);
1259 result = importer->set;
1260 array_release(&importer->buckets);
1267 razor_set_satisfy(struct razor_set *set, struct array *unsatisfied,
1268 struct razor_set *upstream, struct array *list)
1270 struct razor_property *requires, *r;
1271 struct razor_property *p, *pend;
1272 unsigned long *u, *end, *pkg, *package_pool;
1275 end = unsatisfied->data + unsatisfied->size;
1276 requires = set->requires.data;
1277 pool = set->string_pool.data;
1279 p = upstream->provides.data;
1280 pend = upstream->provides.data + upstream->provides.size;
1281 upool = upstream->string_pool.data;
1282 package_pool = upstream->package_pool.data;
1284 for (u = unsatisfied->data; u < end; u++) {
1287 while (p < pend && strcmp(&pool[r->name], &upool[p->name]) > 0)
1289 /* If there is more than one version of a provides,
1290 * seek to the end for the highest version. */
1291 while (p + 1 < pend && p->name == (p + 1)->name)
1295 strcmp(&pool[r->name], &upool[p->name]) != 0 ||
1296 versioncmp(&pool[r->version], &upool[p->version]) > 0) {
1297 /* Do we need to track unsatisfiable requires
1298 * as we go, or should we just do a
1299 * razor_set_validate() at the end? */
1301 pkg = array_add(list, sizeof *pkg);
1302 /* We just pull in the first package that provides */
1303 *pkg = package_pool[p->packages];
1309 find_packages(struct razor_set *set,
1310 int count, const char **packages, struct array *list)
1312 struct razor_package *p;
1316 /* FIXME: Sort the packages. */
1317 for (i = 0; i < count; i++) {
1318 p = razor_set_get_package(set, packages[i]);
1319 r = array_add(list, sizeof *r);
1320 *r = p - (struct razor_package *) set->packages.data;
1325 find_all_packages(struct razor_set *set,
1326 struct razor_set *upstream, struct array *list)
1328 struct razor_package *p, *u, *pend, *uend;
1332 pend = set->packages.data + set->packages.size;
1333 pool = set->string_pool.data;
1334 u = upstream->packages.data;
1335 uend = upstream->packages.data + upstream->packages.size;
1336 upool = upstream->string_pool.data;
1338 for (p = set->packages.data; p < pend; p++) {
1339 while (u < uend && strcmp(&pool[p->name], &upool[u->name]) > 0)
1341 if (strcmp(&pool[p->name], &upool[u->name]) == 0) {
1342 r = array_add(list, sizeof *r);
1343 *r = u - (struct razor_package *) upstream->packages.data;
1349 razor_set_update(struct razor_set *set, struct razor_set *upstream,
1350 int count, const char **packages)
1352 struct razor_set *new;
1353 struct razor_package *upackages;
1354 struct array list, unsatisfied;
1356 unsigned long *u, *end;
1361 find_packages(upstream, count, packages, &list);
1363 find_all_packages(set, upstream, &list);
1365 end = list.data + list.size;
1366 upackages = upstream->packages.data;
1367 pool = upstream->string_pool.data;
1368 total += list.size / sizeof *u;
1370 while (list.size > 0) {
1371 new = razor_set_add(set, upstream, &list);
1372 array_release(&list);
1373 razor_set_destroy(set);
1376 array_init(&unsatisfied);
1377 razor_set_validate(new, &unsatisfied);
1379 razor_set_satisfy(new, &unsatisfied, upstream, &list);
1380 array_release(&unsatisfied);
1382 end = list.data + list.size;
1383 upackages = upstream->packages.data;
1384 pool = upstream->string_pool.data;
1385 total += list.size / sizeof *u;
1388 array_release(&list);
1393 /* The diff order matters. We should sort the packages so that a
1394 * REMOVE of a package comes before the INSTALL, and so that all
1395 * requires for a package have been installed before the package.
1399 razor_set_diff(struct razor_set *set, struct razor_set *upstream,
1400 razor_package_callback_t callback, void *data)
1402 struct razor_package *p, *pend, *u, *uend;
1403 char *ppool, *upool;
1406 p = set->packages.data;
1407 pend = set->packages.data + set->packages.size;
1408 ppool = set->string_pool.data;
1410 u = upstream->packages.data;
1411 uend = upstream->packages.data + upstream->packages.size;
1412 upool = upstream->string_pool.data;
1414 while (p < pend || u < uend) {
1415 if (p < pend && u < uend) {
1416 res = strcmp(&ppool[p->name], &upool[u->name]);
1418 res = versioncmp(&ppool[p->version],
1419 &upool[u->version]);
1422 if (u == uend || res < 0) {
1423 callback(&ppool[p->name], &ppool[p->version],
1427 } else if (p == pend || res > 0) {
1428 callback(&upool[u->name], NULL, &upool[u->version],