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 }