//
// aegis - project change supervisor
// Copyright (C) 1994-1996, 1999, 2003-2008 Peter Miller
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see
// .
//
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define PAIR(a, b) ((a) * rpt_value_type_MAX + (b))
rpt_func_sort::~rpt_func_sort()
{
}
rpt_func_sort::rpt_func_sort()
{
}
rpt_func::pointer
rpt_func_sort::create()
{
return pointer(new rpt_func_sort());
}
const char *
rpt_func_sort::name()
const
{
return "sort";
}
bool
rpt_func_sort::optimizable()
const
{
return true;
}
bool
rpt_func_sort::verify(const rpt_expr::pointer &ep)
const
{
return (ep->get_nchildren() == 1);
}
static int
cmp(const void *va, const void *vb)
{
rpt_value::pointer a = *(rpt_value::pointer *)va;
rpt_value::pointer b = *(rpt_value::pointer *)vb;
rpt_value_integer *aip = dynamic_cast(a.get());
if (aip)
{
long na = aip->query();
rpt_value_integer *bip = dynamic_cast(b.get());
if (bip)
{
long nb = bip->query();
if (na < nb)
return -1;
if (na > nb)
return 1;
return 0;
}
rpt_value_real *brp = dynamic_cast(b.get());
if (brp)
{
double nb = brp->query();
if (na < nb)
return -1;
if (na > nb)
return 1;
return 0;
}
}
rpt_value_real *arp = dynamic_cast(a.get());
if (arp)
{
double na = arp->query();
rpt_value_integer *bip = dynamic_cast(b.get());
if (bip)
{
long nb = bip->query();
if (na < nb)
return -1;
if (na > nb)
return 1;
return 0;
}
rpt_value_real *brp = dynamic_cast(b.get());
if (brp)
{
double nb = brp->query();
if (na < nb)
return -1;
if (na > nb)
return 1;
return 0;
}
}
//
// compare strings, if possible
//
rpt_value_string *asp = dynamic_cast(a.get());
rpt_value_string *bsp = dynamic_cast(b.get());
if (asp && bsp)
return strcmp(asp->query().c_str(), bsp->query().c_str());
//
// absolutely no idea
//
return 0;
}
rpt_value::pointer
rpt_func_sort::run(const rpt_expr::pointer &ep, size_t argc,
rpt_value::pointer *argv) const
{
if (argc != 1)
{
sub_context_ty sc;
sc.var_set_long("Number", (long)argc);
nstring s
(
sc.subst_intl
(
i18n("sort requires exactly 1 argument (was given $number)")
)
);
return rpt_value_error::create(ep->get_pos(), s);
}
rpt_value::pointer vp = argv[0];
rpt_value_list *rvlp = dynamic_cast(vp.get());
if (!rvlp)
{
sub_context_ty sc;
sc.var_set_charstar("Name", vp->name());
nstring s
(
sc.subst_intl
(
i18n("sort requires a list argument (was given $name)")
)
);
return rpt_value_error::create(ep->get_pos(), s);
}
//
// sort the list items
//
size_t length = rvlp->size();
rpt_value::pointer *item = new rpt_value::pointer [length];
for (size_t j = 0; j < length; ++j)
item[j] = rpt_value::arithmetic(rvlp->nth(j));
qsort(item, length, sizeof(item[0]), cmp);
//
// build the result
//
rpt_value_list *rlp = new rpt_value_list();
rpt_value::pointer result(rlp);
for (size_t k = 0; k < length; ++k)
rlp->append(item[k]);
delete [] item;
return result;
}