00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <plang/term.h>
00021 #include <plang/errors.h>
00022 #include "term-priv.h"
00023 #include "context-priv.h"
00024 #include "database-priv.h"
00025
00060 P_INLINE int p_term_sort_compare
00061 (p_context *context, p_term *term1, p_term *term2, int flags)
00062 {
00063 int cmp;
00064 if (flags & P_SORT_KEYED) {
00065 if (term1->header.type == P_TERM_FUNCTOR &&
00066 term1->header.size == 2)
00067 term1 = term1->functor.arg[0];
00068 if (term2->header.type == P_TERM_FUNCTOR &&
00069 term2->header.size == 2)
00070 term2 = term2->functor.arg[0];
00071 } else if (flags & P_SORT_REVERSE_KEYED) {
00072 if (term1->header.type == P_TERM_FUNCTOR &&
00073 term1->header.size == 2)
00074 term1 = term1->functor.arg[1];
00075 if (term2->header.type == P_TERM_FUNCTOR &&
00076 term2->header.size == 2)
00077 term2 = term2->functor.arg[1];
00078 }
00079 cmp = p_term_precedes(context, term1, term2);
00080 if (flags & P_SORT_DESCENDING)
00081 return -cmp;
00082 else
00083 return cmp;
00084 }
00085
00086
00087
00088 static void p_term_sort_section
00089 (p_context *context, p_term **array, p_term **temp,
00090 int left, int right, int flags)
00091 {
00092 int middle, i, j, k;
00093 if (left >= right)
00094 return;
00095 middle = (left + right) / 2;
00096 p_term_sort_section(context, array, temp, left, middle, flags);
00097 p_term_sort_section(context, array, temp, middle + 1, right, flags);
00098 for (i = middle + 1; i > left; --i)
00099 temp[i - 1] = array[i - 1];
00100 for (j = middle; j < right; ++j)
00101 temp[right + middle - j] = array[j + 1];
00102 for (k = left; k <= right; ++k) {
00103 if (p_term_sort_compare(context, temp[i], temp[j], flags) <= 0)
00104 array[k] = temp[i++];
00105 else
00106 array[k] = temp[j--];
00107 }
00108 }
00109
00110
00111 static p_term *p_term_section_to_list
00112 (p_context *context, p_term **array, int size, int flags)
00113 {
00114 p_term *list = p_term_create_list(context, array[0], 0);
00115 p_term *tail = list;
00116 p_term *new_tail;
00117 int index;
00118 if (!list)
00119 return 0;
00120 if ((flags & P_SORT_UNIQUE) == 0) {
00121 for (index = 1; index < size; ++index) {
00122 new_tail = p_term_create_list(context, array[index], 0);
00123 if (!new_tail)
00124 return 0;
00125 p_term_set_tail(tail, new_tail);
00126 tail = new_tail;
00127 }
00128 } else {
00129 for (index = 1; index < size; ++index) {
00130 if (!p_term_sort_compare
00131 (context, array[index - 1], array[index], flags))
00132 continue;
00133 new_tail = p_term_create_list(context, array[index], 0);
00134 if (!new_tail)
00135 return 0;
00136 p_term_set_tail(tail, new_tail);
00137 tail = new_tail;
00138 }
00139 }
00140 p_term_set_tail(tail, context->nil_atom);
00141 return list;
00142 }
00143
00144
00145 static p_term *p_term_sort_merge
00146 (p_context *context, p_term *list1, p_term *list2, int flags)
00147 {
00148 p_term *head = 0;
00149 p_term *tail = 0;
00150 int cmp;
00151 for (;;) {
00152 if (list1 == context->nil_atom) {
00153 if (head)
00154 p_term_set_tail(tail, list2);
00155 else
00156 head = list2;
00157 break;
00158 }
00159 if (list2 == context->nil_atom) {
00160 if (head)
00161 p_term_set_tail(tail, list1);
00162 else
00163 head = list1;
00164 break;
00165 }
00166 cmp = p_term_sort_compare(context, list1->list.head,
00167 list2->list.head, flags);
00168 if (cmp <= 0) {
00169 if (head)
00170 p_term_set_tail(tail, list1);
00171 else
00172 head = list1;
00173 tail = list1;
00174 list1 = list1->list.tail;
00175 if (!cmp && (flags & P_SORT_UNIQUE) != 0)
00176 list2 = list2->list.tail;
00177 } else {
00178 if (head)
00179 p_term_set_tail(tail, list2);
00180 else
00181 head = list2;
00182 tail = list2;
00183 list2 = list2->list.tail;
00184 }
00185 }
00186 return head;
00187 }
00188
00208 p_term *p_term_sort(p_context *context, p_term *list, int flags)
00209 {
00210 #define P_SORT_SECTION_SIZE 256
00211 p_term *array[P_SORT_SECTION_SIZE];
00212 p_term *temp[P_SORT_SECTION_SIZE];
00213 int size;
00214 p_term *section;
00215 p_term *sections;
00216
00217
00218 list = p_term_deref(list);
00219 if (!list)
00220 return 0;
00221 if (list == context->nil_atom)
00222 return list;
00223 if (list->header.type != P_TERM_LIST)
00224 return 0;
00225
00226
00227
00228 size = 0;
00229 sections = 0;
00230 do {
00231 if ((array[size++] = p_term_deref(list->list.head)) == 0)
00232 return 0;
00233 if (size >= P_SORT_SECTION_SIZE) {
00234 p_term_sort_section
00235 (context, array, temp, 0, size - 1, flags);
00236 section = p_term_section_to_list
00237 (context, array, size, flags);
00238 if (!section)
00239 return 0;
00240 if (sections) {
00241 sections = p_term_sort_merge
00242 (context, sections, section, flags);
00243 } else {
00244 sections = section;
00245 }
00246 size = 0;
00247 }
00248 list = p_term_deref(list->list.tail);
00249 } while (list && list->header.type == P_TERM_LIST);
00250 if (list && (list->header.type & P_TERM_VARIABLE) == 0 &&
00251 list != context->nil_atom)
00252 return 0;
00253 if (size > 0) {
00254 p_term_sort_section(context, array, temp, 0, size - 1, flags);
00255 section = p_term_section_to_list(context, array, size, flags);
00256 if (!section)
00257 return 0;
00258 if (sections) {
00259 sections = p_term_sort_merge
00260 (context, sections, section, flags);
00261 } else {
00262 sections = section;
00263 }
00264 }
00265 return sections;
00266 }
00267
00287 static p_goal_result p_builtin_common_sort
00288 (p_context *context, p_term **args, p_term **error, int flags)
00289 {
00290 p_term *list = p_term_deref_member(context, args[0]);
00291 p_term *sorted;
00292 if (!list || (list->header.type & P_TERM_VARIABLE) != 0) {
00293 *error = p_create_instantiation_error(context);
00294 return P_RESULT_ERROR;
00295 }
00296 sorted = p_term_sort(context, list, flags);
00297 if (!sorted) {
00298 *error = p_create_type_error(context, "list", list);
00299 return P_RESULT_ERROR;
00300 }
00301 if (p_term_unify(context, args[1], sorted, P_BIND_DEFAULT))
00302 return P_RESULT_TRUE;
00303 else
00304 return P_RESULT_FAIL;
00305 }
00306
00351 static p_goal_result p_builtin_keysort
00352 (p_context *context, p_term **args, p_term **error)
00353 {
00354 return p_builtin_common_sort
00355 (context, args, error, P_SORT_ASCENDING | P_SORT_KEYED);
00356 }
00357
00394 static p_goal_result p_builtin_keysortd
00395 (p_context *context, p_term **args, p_term **error)
00396 {
00397 return p_builtin_common_sort
00398 (context, args, error, P_SORT_DESCENDING | P_SORT_KEYED);
00399 }
00400
00438 static p_goal_result p_builtin_msort
00439 (p_context *context, p_term **args, p_term **error)
00440 {
00441 return p_builtin_common_sort
00442 (context, args, error, P_SORT_ASCENDING);
00443 }
00444
00479 static p_goal_result p_builtin_msortd
00480 (p_context *context, p_term **args, p_term **error)
00481 {
00482 return p_builtin_common_sort
00483 (context, args, error, P_SORT_DESCENDING);
00484 }
00485
00523 static p_goal_result p_builtin_rkeysort
00524 (p_context *context, p_term **args, p_term **error)
00525 {
00526 return p_builtin_common_sort
00527 (context, args, error, P_SORT_ASCENDING | P_SORT_REVERSE_KEYED);
00528 }
00529
00567 static p_goal_result p_builtin_rkeysortd
00568 (p_context *context, p_term **args, p_term **error)
00569 {
00570 return p_builtin_common_sort
00571 (context, args, error, P_SORT_DESCENDING | P_SORT_REVERSE_KEYED);
00572 }
00573
00612 static p_goal_result p_builtin_sort
00613 (p_context *context, p_term **args, p_term **error)
00614 {
00615 return p_builtin_common_sort
00616 (context, args, error, P_SORT_ASCENDING | P_SORT_UNIQUE);
00617 }
00618
00654 static p_goal_result p_builtin_sortd
00655 (p_context *context, p_term **args, p_term **error)
00656 {
00657 return p_builtin_common_sort
00658 (context, args, error, P_SORT_DESCENDING | P_SORT_UNIQUE);
00659 }
00660
00661 void _p_db_init_sort(p_context *context)
00662 {
00663 static struct p_builtin const builtins[] = {
00664 {"keysort", 2, p_builtin_keysort},
00665 {"keysortd", 2, p_builtin_keysortd},
00666 {"msort", 2, p_builtin_msort},
00667 {"msortd", 2, p_builtin_msortd},
00668 {"rkeysort", 2, p_builtin_rkeysort},
00669 {"rkeysortd", 2, p_builtin_rkeysortd},
00670 {"sort", 2, p_builtin_sort},
00671 {"sortd", 2, p_builtin_sortd},
00672 {0, 0, 0}
00673 };
00674 _p_db_register_builtins(context, builtins);
00675 }