/* -*- mode: c++; indent-tabs-mode: nil -*- */
/*
    ql_list.qpp

    Qore Programming Language

    Copyright (C) 2003 - 2023 Qore Technologies, s.r.o.

    Permission is hereby granted, free of charge, to any person obtaining a
    copy of this software and associated documentation files (the "Software"),
    to deal in the Software without restriction, including without limitation
    the rights to use, copy, modify, merge, publish, distribute, sublicense,
    and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in
    all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    DEALINGS IN THE SOFTWARE.

    Note that the Qore library is released under a choice of three open-source
    licenses: MIT (as above), LGPL 2+, or GPL 2+; see README-LICENSE for more
    information.
*/

#include <qore/Qore.h>
#include "qore/intern/ql_list.h"
#include "qore/intern/qore_program_private.h"

ResolvedCallReferenceNode* getCallReference(const QoreString* str, ExceptionSink* xsink) {
   // ensure string is in default encoding
   TempEncodingHelper tmp(str, QCS_DEFAULT, xsink);
   if (!tmp)
      return 0;
   return qore_program_private::runtimeGetCallReference(getProgram(), tmp->getBuffer(), xsink);
}

bool inlist_intern(const QoreValue arg, const QoreListNode* l, ExceptionSink* xsink) {
    assert(xsink);
    ConstListIterator li(l);
    while (li.next()) {
        bool b = QoreLogicalEqualsOperatorNode::softEqual(arg, li.getValue(), xsink);
        if (*xsink) {
            return false;
        }
        if (b) {
            return true;
        }
    }
    return false;
}

QoreListNode* range_intern(int64 start, int64 stop, int64 step, ExceptionSink* xsink) {
    if (step < 1) {
        xsink->raiseException("RANGE-ERROR", "Value of the 'step' argument has to be greater than 0");
        return 0;
    }

    bool broken_range = runtime_get_parse_options() & PO_BROKEN_RANGE;
    QoreListNode* l = new QoreListNode(bigIntTypeInfo);
    if (start < stop) {
        if (broken_range) {
            ++stop;
        }

        for (int64 i = start; i < stop; i += step) {
            l->push(i, xsink);
        }
    } else {
        if (broken_range) {
            --stop;
        }

        for (int64 i = start; i > stop; i -= step) {
            l->push(i, xsink);
        }
    }
    return l;
}

/** @defgroup list_functions List Functions
    List functions
 */
///@{
//! This function variant does nothing at all
/** it is only included for backwards-compatibility with qore prior to version 0.8.0 for functions that would ignore
    type errors in arguments
*/
auto sort(auto arg) [flags=NOOP] {
   return arg.refSelf();
}

//! Performs an unstable sort in ascending order and returns the new list
/** This variant will only sort basic data types

    @par Example:
    @code{.py}
list<auto> nl = sort(l);
    @endcode

    @param l the list to sort

    @return the sorted list

    @note This function uses an internal recursive quicksort algorithm that uses excessive stack space with large
    lists, therefore when the list size is > 1000 element, mergesort is used instead, which is equivalent to
    @ref sort_stable()

    @see
    - sortStable(list)
    - sortDescendingStable(list)
    - sortDescending(list)
*/
list<auto> sort(list<auto> l) [flags=CONSTANT] {
   return l->sort(xsink);
}

//! Performs an unstable sort in ascending order and returns the new list
/** Accepts the name of a function to use to sort complex data types or to give a special sort order

    @par Example:
    @code{.py}
list<auto> nl = sort(l, "my_sort_function");
    @endcode

    @param l the list to sort
    @param func the name of a function accessible in the current scope that accepts 2 arguments of the data type in
    the list; the function must return -1, 0, or 1 if the first is less than the second, if the first and second are
    equal, or if the first is greater than the second, respectively

    @return the sorted list

    @note This function uses an internal recursive quicksort algorithm that uses excessive stack space with large
    lists, therefore when the list size is > 1000 element, mergesort is used instead, which is equivalent to
    @ref sort_stable()

    @see
    - sortStable(list, string)
    - sortDescendingStable(list, string)
    - sortDescending(list, string)
*/
list<auto> sort(list<auto> l, string func) [flags=RET_VALUE_ONLY] {
   ReferenceHolder<ResolvedCallReferenceNode> fr(getCallReference(func, xsink), xsink);
   return !fr ? QoreValue() : l->sort(*fr, xsink);
}

//! Performs an unstable sort in ascending order and returns the new list
/** Accepts a @ref call_reference "call reference" or a @ref closure "closure" to use to sort complex data types or to
    give a special sort order

    @par Example:
    @code{.py}
code sort_func = int sub (hash l, hash r) { return l.id <=> r.id; };
list<auto> nl = sort(l, sort_func);
    @endcode

    @param l the list to sort
    @param f a @ref call_reference "call reference" or a @ref closure "closure" that accepts 2 arguments of the data
    type in the list; the code must return -1, 0, or 1 if the first is less than the second, if the first and second
    are equal, or if the first is greater than the second, respectively

    @return the sorted list

    @note This function uses an internal recursive quicksort algorithm that uses excessive stack space with large
    lists, therefore when the list size is > 1000 element, mergesort is used instead, which is equivalent to
    @ref sort_stable()

    @see
    - sortStable(list, code)
    - sortDescendingStable(list, code)
    - sortDescending(list, code)
*/
list<auto> sort(list<auto> l, code f) [flags=RET_VALUE_ONLY] {
   return l->sort(f, xsink);
}

//! This function variant does nothing at all
/** It is only included for backwards-compatibility with qore prior to version 0.8.0 for functions that would ignore
    type errors in arguments
*/
auto sortDescending(auto arg) [flags=NOOP,DEPRECATED] {
   return arg.refSelf();
}

//! Performs an unstable sort in descending order and returns the new list
/** This variant will only sort basic data types

    @param l the list to sort

    @return the sorted list

    @note This function uses an internal recursive quicksort algorithm that uses excessive stack space with large
    lists, therefore when the list size is > 1000 element, mergesort is used instead, which is equivalent to
    @ref sort_stable()

    @see
    - sort(list)
    - sortDescendingStable(list)
    - sortStable(list)

    @deprecated use sort_descending(); camel-case function names were deprecated in %Qore 0.8.12
*/
list<auto> sortDescending(list<auto> l) [flags=CONSTANT,DEPRECATED] {
   return l->sortDescending(xsink);
}

//! Performs an unstable sort in descending order and returns the new list
/** Accepts the name of a function to use to sort complex data types or to give a special sort order

    @param l the list to sort
    @param func the name of a function accessible in the current scope that accepts 2 arguments of the data type in
    the list; the function must return -1, 0, or 1 if the first is less than the second, if the first and second are
    equal, or if the first is greater than the second, respectively

    @return the sorted list

    @note This function uses an internal recursive quicksort algorithm that uses excessive stack space with large
    lists, therefore when the list size is > 1000 element, mergesort is used instead, which is equivalent to
    @ref sort_stable()

    @see
    - sortStable(list, string)
    - sortDescendingStable(list, string)
    - sort(list, string)

    @deprecated use sort_descending(); camel-case function names were deprecated in %Qore 0.8.12
*/
list<auto> sortDescending(list<auto> l, string func) [flags=CONSTANT,DEPRECATED] {
   ReferenceHolder<ResolvedCallReferenceNode> fr(getCallReference(func, xsink), xsink);
   return !fr ? QoreValue() : l->sortDescending(*fr, xsink);
}

//! Performs an unstable sort in descending order and returns the new list
/** Accepts a @ref call_reference "call reference" or a @ref closure "closure" to use to sort complex data types or to
    give a special sort order

    @param l the list to sort
    @param f a @ref call_reference "call reference" or a @ref closure "closure" that accepts 2 arguments of the data
    type in the list; the code must return -1, 0, or 1 if the first is less than the second, if the first and second
    are equal, or if the first is greater than the second, respectively

    @return the sorted list

    @note This function uses an internal recursive quicksort algorithm that uses excessive stack space with large
    lists, therefore when the list size is > 1000 element, mergesort is used instead, which is equivalent to
    @ref sort_stable()

    @see
    - sortStable(list, code)
    - sortDescendingStable(list, code)
    - sort(list, code)

    @deprecated use sort_descending(); camel-case function names were deprecated in %Qore 0.8.12
*/
list<auto> sortDescending(list<auto> l, code f) [flags=RET_VALUE_ONLY,DEPRECATED] {
   return l->sortDescending(f, xsink);
}

//! This function variant does nothing at all
/** It is only included for backwards-compatibility with qore prior to version 0.8.0 for functions that would ignore
    type errors in arguments
*/
auto sort_descending(auto arg) [flags=NOOP] {
   return arg.refSelf();
}

//! Performs an unstable sort in descending order and returns the new list
/** This variant will only sort basic data types

    @par Example:
    @code{.py}
list<auto> nl = sort_descending(l);
    @endcode

    @param l the list to sort

    @return the sorted list

    @note This function uses an internal recursive quicksort algorithm that uses excessive stack space with large
    lists, therefore when the list size is > 1000 element, mergesort is used instead, which is equivalent to
    @ref sort_stable()

    @see
    - sort(list)
    - sortDescendingStable(list)
    - sortStable(list)

    @since %Qore 0.8.12 as a replacement for deprecated camel-case sortDescending()
*/
list<auto> sort_descending(list<auto> l) [flags=CONSTANT] {
   return l->sortDescending(xsink);
}

//! Performs an unstable sort in descending order and returns the new list
/** Accepts the name of a function to use to sort complex data types or to give a special sort order

    @par Example:
    @code{.py}
list<auto> nl = sort_descending(l, "my_sort_function");
    @endcode

    @param l the list to sort
    @param func the name of a function accessible in the current scope that accepts 2 arguments of the data type in
    the list; the function must return -1, 0, or 1 if the first is less than the second, if the first and second are
    equal, or if the first is greater than the second, respectively

    @return the sorted list

    @note This function uses an internal recursive quicksort algorithm that uses excessive stack space with large
    lists, therefore when the list size is > 1000 element, mergesort is used instead, which is equivalent to
    @ref sort_stable()

    @see
    - sort_stable(list, string)
    - sort_descendingStable(list, string)
    - sort(list, string)

    @since %Qore 0.8.12 as a replacement for deprecated camel-case sortDescending()
*/
list<auto> sort_descending(list<auto> l, string func) [flags=CONSTANT] {
   ReferenceHolder<ResolvedCallReferenceNode> fr(getCallReference(func, xsink), xsink);
   return !fr ? QoreValue() : l->sortDescending(*fr, xsink);
}

//! Performs an unstable sort in descending order and returns the new list
/** Accepts a @ref call_reference "call reference" or a @ref closure "closure" to use to sort complex data types or to
    give a special sort order

    @par Example:
    @code{.py}
code sort_func = int sub (hash l, hash r) { return l.id <=> r.id; };
list<auto> nl = sort_descending(l, sort_func);
    @endcode

    @param l the list to sort
    @param f a @ref call_reference "call reference" or a @ref closure "closure" that accepts 2 arguments of the data
    type in the list; the code must return -1, 0, or 1 if the first is less than the second, if the first and second
    are equal, or if the first is greater than the second, respectively

    @return the sorted list

    @note This function uses an internal recursive quicksort algorithm that uses excessive stack space with large
    lists, therefore when the list size is > 1000 element, mergesort is used instead, which is equivalent to
    @ref sort_stable()

    @see
    - sort_stable(list, code)
    - sort_descendingStable(list, code)
    - sort(list, code)

    @since %Qore 0.8.12 as a replacement for deprecated camel-case sortDescending()
*/
list<auto> sort_descending(list<auto> l, code f) [flags=RET_VALUE_ONLY] {
   return l->sortDescending(f, xsink);
}

//! This function variant does nothing at all
/** It is only included for backwards-compatibility with qore prior to version 0.8.0 for functions that would ignore
    type errors in arguments
*/
auto sortStable(auto arg) [flags=NOOP,DEPRECATED] {
   return arg.refSelf();
}

//! Performs a stable sort in ascending order and returns the new list
/** This variant will only sort basic data types

    @param l the list to sort

    @return the sorted list

    @see
    - sort(list, string)
    - sort_descending(list, string)
    - sort_descending_stable(list, string)

    @deprecated use sort_stable(); camel-case function names were deprecated in %Qore 0.8.12
*/
list<auto> sortStable(list<auto> l) [flags=CONSTANT,DEPRECATED] {
   return l->sortStable(xsink);
}

//! Performs a stable sort in ascending order and returns the new list
/** Accepts the name of a function to use to sort complex data types or to give a special sort order

    @param l the list to sort
    @param func the name of a function accessible in the current scope that accepts 2 arguments of the data type in
    the list; the function must return -1, 0, or 1 if the first is less than the second, if the first and second are
    equal, or if the first is greater than the second, respectively

    @return the sorted list

    @see
    - sort(list, string)
    - sort_descending(list, string)
    - sort_descending_stable(list, string)

    @deprecated use sort_stable(); camel-case function names were deprecated in %Qore 0.8.12
*/
list<auto> sortStable(list<auto> l, string func) [flags=RET_VALUE_ONLY,DEPRECATED] {
   ReferenceHolder<ResolvedCallReferenceNode> fr(getCallReference(func, xsink), xsink);
   return !fr ? QoreValue() : l->sortStable(*fr, xsink);
}

//! Performs a stable sort in ascending order and returns the new list
/** Accepts a @ref call_reference "call reference" or a @ref closure "closure" to use to sort complex data types or to
    give a special sort order

    @par Example:
    @code{.py}
code sort_func = int sub (hash l, hash r) { return l.id <=> r.id; };
list<auto> nl = sortStable(l, sort_func);
    @endcode

    @param l the list to sort
    @param f a @ref call_reference "call reference" or a @ref closure "closure" that accepts 2 arguments of the data
    type in the list; the code must return -1, 0, or 1 if the first is less than the second, if the first and second
    are equal, or if the first is greater than the second, respectively

    @return the sorted list

    @see
    - sort(list, string)
    - sort_descending(list, string)
    - sort_descending_stable(list, string)

    @deprecated use sort_stable(); camel-case function names were deprecated in %Qore 0.8.12
*/
list<auto> sortStable(list<auto> l, code f) [flags=RET_VALUE_ONLY,DEPRECATED] {
   return l->sortStable(f, xsink);
}

//! This function variant does nothing at all
/** It is only included for backwards-compatibility with qore prior to version 0.8.0 for functions that would ignore
    type errors in arguments
*/
auto sort_stable(auto arg) [flags=NOOP] {
   return arg.refSelf();
}

//! Performs a stable sort in ascending order and returns the new list
/** This variant will only sort basic data types

    @par Example:
    @code{.py}
list<auto> nl = sort_stable(l);
    @endcode

    @param l the list to sort

    @return the sorted list

    @see
    - sort(list, string)
    - sort_descending(list, string)
    - sort_descending_stable(list, string)

    @since %Qore 0.8.12 as a replacement for deprecated camel-case sortStable()
*/
list<auto> sort_stable(list<auto> l) [flags=CONSTANT] {
   return l->sortStable(xsink);
}

//! Performs a stable sort in ascending order and returns the new list
/** Accepts the name of a function to use to sort complex data types or to give a special sort order

    @par Example:
    @code{.py}
list<auto> nl = sort_stable(l, "my_sort_function");
    @endcode

    @param l the list to sort
    @param func the name of a function accessible in the current scope that accepts 2 arguments of the data type in
    the list; the function must return -1, 0, or 1 if the first is less than the second, if the first and second are
    equal, or if the first is greater than the second, respectively

    @return the sorted list

    @see
    - sort(list, string)
    - sort_descending(list, string)
    - sort_descending_stable(list, string)

    @since %Qore 0.8.12 as a replacement for deprecated camel-case sortStable()
*/
list<auto> sort_stable(list<auto> l, string func) [flags=RET_VALUE_ONLY] {
   ReferenceHolder<ResolvedCallReferenceNode> fr(getCallReference(func, xsink), xsink);
   return !fr ? QoreValue() : l->sortStable(*fr, xsink);
}

//! Performs a stable sort in ascending order and returns the new list
/** Accepts a @ref call_reference "call reference" or a @ref closure "closure" to use to sort complex data types or to
    give a special sort order

    @par Example:
    @code{.py}
code sort_func = int sub (hash<auto> l, hash<auto> r) { return l.id <=> r.id; };
list<auto> nl = sort_stable(l, sort_func);
    @endcode

    @param l the list to sort
    @param f a @ref call_reference "call reference" or a @ref closure "closure" that accepts 2 arguments of the data
    type in the list; the code must return -1, 0, or 1 if the first is less than the second, if the first and second
    are equal, or if the first is greater than the second, respectively

    @return the sorted list

    @see
    - sort(list, string)
    - sort_descending(list, string)
    - sort_descending_stable(list, string)

    @since %Qore 0.8.12 as a replacement for deprecated camel-case sortStable()
*/
list<auto> sort_stable(list<auto> l, code f) [flags=RET_VALUE_ONLY] {
   return l->sortStable(f, xsink);
}

//! This function variant does nothing at all
/** It is only included for backwards-compatibility with qore prior to version 0.8.0 for functions that would ignore
    type errors in arguments
*/
auto sortDescendingStable(auto arg) [flags=NOOP,DEPRECATED] {
   return arg.refSelf();
}

//! Performs a stable sort in descending order and returns the new list
/** This variant will only sort basic data types

    @par Example:
    @code{.py}
list<auto> nl = sortDescendingStable(l);
    @endcode

    @param l the list to sort

    @return the sorted list

    @see
    - sort_stable(list, code)
    - sort_descending_stable(list, code)
    - sort(list, code)

    @deprecated use sort_descending_stable(); camel-case function names were deprecated in %Qore 0.8.12
*/
list<auto> sortDescendingStable(list<auto> l) [flags=CONSTANT,DEPRECATED] {
   return l->sortDescendingStable(xsink);
}

//! Performs a stable sort in descending order and returns the new list
/** Accepts the name of a function to use to sort complex data types or to give a special sort order

    @par Example:
    @code{.py}
list<auto> nl = sortDescending(l, "my_sort_function");
    @endcode

    @param l the list to sort
    @param func the name of a function accessible in the current scope that accepts 2 arguments of the data type in
    the list; the function must return -1, 0, or 1 if the first is less than the second, if the first and second are
    equal, or if the first is greater than the second, respectively

    @return the sorted list

    @see
    - sort_stable(list, code)
    - sort_descending_stable(list, code)
    - sort(list, code)

    @deprecated use sort_descending_stable(); camel-case function names were deprecated in %Qore 0.8.12
*/
list<auto> sortDescendingStable(list<auto> l, string func) [flags=RET_VALUE_ONLY,DEPRECATED] {
   ReferenceHolder<ResolvedCallReferenceNode> fr(getCallReference(func, xsink), xsink);
   return !fr ? QoreValue() : l->sortDescendingStable(*fr, xsink);
}

//! Performs a stable sort in descending order and returns the new list
/** Accepts a @ref call_reference "call reference" or a @ref closure "closure" to use to sort complex data types or to
    give a special sort order

    @par Example:
    @code{.py}
code sort_func = int sub (hash l, hash r) { return l.id <=> r.id; };
list<auto> nl = sortDescending(l, sort_func);
    @endcode

    @param l the list to sort
    @param f a @ref call_reference "call reference" or a @ref closure "closure" that accepts 2 arguments of the data
    type in the list; the code must return -1, 0, or 1 if the first is less than the second, if the first and second
    are equal, or if the first is greater than the second, respectively

    @return the sorted list

    @see
    - sort_stable(list, code)
    - sort_descending_stable(list, code)
    - sort(list, code)

    @deprecated use sort_descending_stable(); camel-case function names were deprecated in %Qore 0.8.12
*/
list<auto> sortDescendingStable(list<auto> l, code f) [flags=RET_VALUE_ONLY,DEPRECATED] {
   return l->sortDescendingStable(f, xsink);
}

//! This function variant does nothing at all
/** It is only included for backwards-compatibility with qore prior to version 0.8.0 for functions that would ignore
    type errors in arguments
*/
auto sort_descending_stable(auto arg) [flags=NOOP] {
   return arg.refSelf();
}

//! Performs a stable sort in descending order and returns the new list
/** This variant will only sort basic data types

    @par Example:
    @code{.py}
list<auto> nl = sort_descending_stable(l);
    @endcode

    @param l the list to sort

    @return the sorted list

    @see
    - sort_stable(list, code)
    - sort_descending_stable(list, code)
    - sort(list, code)

    @since %Qore 0.8.12 as a replacement for deprecated camel-case sortDescendingStable()
*/
list<auto> sort_descending_stable(list<auto> l) [flags=CONSTANT] {
   return l->sortDescendingStable(xsink);
}

//! Performs a stable sort in descending order and returns the new list
/** Accepts the name of a function to use to sort complex data types or to give a special sort order

    @par Example:
    @code{.py}
list<auto> nl = sort_descending_stable(l, "my_sort_function");
    @endcode

    @param l the list to sort
    @param func the name of a function accessible in the current scope that accepts 2 arguments of the data type in
    the list; the function must return -1, 0, or 1 if the first is less than the second, if the first and second are
    equal, or if the first is greater than the second, respectively

    @return the sorted list

    @see
    - sort_stable(list, code)
    - sort_descending_stable(list, code)
    - sort(list, code)

    @since %Qore 0.8.12 as a replacement for deprecated camel-case sortDescendingStable()
*/
list<auto> sort_descending_stable(list<auto> l, string func) [flags=RET_VALUE_ONLY] {
   ReferenceHolder<ResolvedCallReferenceNode> fr(getCallReference(func, xsink), xsink);
   return !fr ? QoreValue() : l->sortDescendingStable(*fr, xsink);
}

//! Performs a stable sort in descending order and returns the new list
/** Accepts a @ref call_reference "call reference" or a @ref closure "closure" to use to sort complex data types or to
    give a special sort order

    @par Example:
    @code{.py}
code sort_func = int sub (hash l, hash r) { return l.id <=> r.id; };
list<auto> nl = sort_descending_stable(l, sort_func);
    @endcode

    @param l the list to sort
    @param f a @ref call_reference "call reference" or a @ref closure "closure" that accepts 2 arguments of the data
    type in the list; the code must return -1, 0, or 1 if the first is less than the second, if the first and second
    are equal, or if the first is greater than the second, respectively

    @return the sorted list

    @see
    - sort_stable(list, code)
    - sort_descending_stable(list, code)
    - sort(list, code)

    @since %Qore 0.8.12 as a replacement for deprecated camel-case sortDescendingStable()
*/
list<auto> sort_descending_stable(list<auto> l, code f) [flags=RET_VALUE_ONLY] {
   return l->sortDescendingStable(f, xsink);
}

//! Returns the minumum value in a list
/** This variant will only work on basic data types

    @par Example:
    @code{.py}
auto v = min(l);
    @endcode

    @param l the list to process

    @return the minumum value in a list

    @see max(list)
*/
auto min(list<auto> l) [flags=CONSTANT] {
   return l->min(xsink);
}

//! Returns the minumum value in a list
/** Accepts the name of a function to use to compare complex data types or to give a special sort order

    @par Example:
    @code{.py}
auto v = min(l, "my_sort_function");
    @endcode

    @param l the list to sort
    @param func the name of a function accessible in the current scope that accepts 2 arguments of the data type in
    the list; the function must return -1, 0, or 1 if the first is less than the second, if the first and second are
    equal, or if the first is greater than the second, respectively

    @return the minumum value in a list

    @see max(list, string)
*/
auto min(list<auto> l, string func) [flags=RET_VALUE_ONLY] {
   ReferenceHolder<ResolvedCallReferenceNode> fr(getCallReference(func, xsink), xsink);
   return !fr ? QoreValue() : l->min(*fr, xsink);
}

//! Returns the minumum value in a list
/** Accepts a @ref call_reference "call reference" or a @ref closure "closure" to use to compare complex data types or
    to give a special sort order

    @par Example:
    @code{.py}
code sort_func = int sub (hash l, hash r) { return l.id <=> r.id; };
auto v = min(l, sort_func);
    @endcode

    @param l the list to sort
    @param f a @ref call_reference "call reference" or a @ref closure "closure" that accepts 2 arguments of the data
    type in the list; the @ref call_reference "call reference" or a @ref closure "closure" must return -1, 0, or 1 if
    the first is less than the second, if the first and second are equal, or if the first is greater than the second,
    respectively

    @return the minumum value in a list

    @see max(list, code)
*/
auto min(list<auto> l, code f) [flags=RET_VALUE_ONLY] {
   return l->min(f, xsink);
}

//! Returns the minumum value of the arguments passed to the function
/** This variant will only work on basic data types

    @par Example:
    @code{.py}
auto v = min(v1, v2, v3);
    @endcode

    @param ... the list of values to process given directly to the function

    @return the minumum value in a list

    @see max(...)
*/
auto min(...) [flags=CONSTANT] {
   return args ? args->min(xsink) : QoreValue();
}

//! Returns the maximum value in a list
/** This variant will only work on basic data types

    @par Example:
    @code{.py}
auto v = max(l);
    @endcode

    @param l the list to process

    @return the maximum value in a list

    @see min(list)
*/
auto max(list<auto> l) [flags=CONSTANT] {
   return l->max(xsink);
}

//! Returns the maximum value in a list
/** Accepts the name of a function to use to compare complex data types or to give a special sort order

    @par Example:
    @code{.py}
auto v = max(l, "my_sort_function");
    @endcode

    @param l the list to sort
    @param func the name of a function accessible in the current scope that accepts 2 arguments of the data type in
    the list; the function must return -1, 0, or 1 if the first is less than the second, if the first and second are
    equal, or if the first is greater than the second, respectively

    @return the maximum value in a list

    @see min(list, string)
*/
auto max(list<auto> l, string func) [flags=RET_VALUE_ONLY] {
   ReferenceHolder<ResolvedCallReferenceNode> fr(getCallReference(func, xsink), xsink);
   return !fr ? QoreValue() : l->max(*fr, xsink);
}

//! Returns the maximum value in a list
/** Accepts a @ref call_reference "call reference" or a @ref closure "closure" to use to compare complex data types or
    to give a special sort order

    @par Example:
    @code{.py}
code sort_func = int sub (hash l, hash r) { return l.id <=> r.id; };
auto v = max(l, sort_func);
    @endcode

    @param l the list to sort
    @param f a @ref call_reference "call reference" or a @ref closure "closure" that accepts 2 arguments of the data
    type in the list; the @ref call_reference "call reference" or a @ref closure "closure" must return -1, 0, or 1 if
    the first is less than the second, if the first and second are equal, or if the first is greater than the second,
    respectively

    @return the maximum value in a list

    @see min(list, code)
*/
auto max(list<auto> l, code f) [flags=RET_VALUE_ONLY] {
   return l->max(f, xsink);
}

//! Returns the maximum value of the arguments passed to the function
/** This variant will only work on basic data types

    @par Example:
    @code{.py}
auto v = max(v1, v2, v3);
    @endcode

    @param ... the list of values to process given directly to the function

    @return the maximum value in a list

    @see min(...)
*/
auto max(...) [flags=CONSTANT] {
   return args ? args->max(xsink) : QoreValue();
}

//! This function variant does nothing at all
/** It is only included for backwards-compatibility with qore prior to version 0.8.0 for functions that would ignore
    type errors in arguments
*/
nothing reverse() [flags=NOOP] {
}

//! Reverses a list and returns the new list
/**
    @par Example:
    @code{.py}
list<auto> nl = reverse(l);
    @endcode

    @param l the list to reverse

    @return the given list with all elements in reverse order

    @see reverse(string)
*/
list<auto> reverse(list<auto> l) [flags=CONSTANT] {
   return l->reverse();
}

//! This function variant does nothing at all
/** It is only included for backwards-compatibility with qore prior to version 0.8.0 for functions that would ignore
    type errors in arguments
*/
bool inlist() [flags=NOOP] {
   return false;
}

//! This function variant does nothing at all
/** It is only included for backwards-compatibility with qore prior to version 0.8.0 for functions that would ignore
    type errors in arguments
*/
bool inlist(any[doc] arg, nothing[doc] x) [flags=NOOP] {
   return false;
}

//! Returns @ref True if the first argument is a member of the second argument list using soft comparisons (with implicit type conversions), @ref False if not
/**
    @par Example:
    @code{.py}
if (inlist(str, strlist))
    printf("%y is in %y\n", str, strlist);
    @endcode

    @param arg the argument to look for in the list
    @param l the list to search for the first argument \a arg

    @return @ref True if the first argument is a member of the second argument list using soft comparisons (with
    implicit type conversions), @ref False if not

    @see inlist_hard(auto, softlist<auto>)
*/
bool inlist(auto arg, softlist<auto> l) [flags=RET_VALUE_ONLY] {
   return inlist_intern(arg, l, xsink);
}

//! This function variant does nothing at all
/** It is only included for backwards-compatibility with qore prior to version 0.8.0 for functions that would ignore
    type errors in arguments
*/
bool inlist_hard() [flags=NOOP] {
   return false;
}

//! This function variant does nothing at all
/** It is only included for backwards-compatibility with qore prior to version 0.8.0 for functions that would ignore
    type errors in arguments
*/
bool inlist_hard(any[doc] arg, nothing[doc] x) [flags=NOOP] {
   return false;
}

//! Returns @ref True if the first argument is a member of the second argument list using hard comparisons (without any implicit type conversions), @ref False if not
/**
    @par Example:
    @code{.py}
if (inlist_hard(str, strlist))
    printf("%y is in %y\n", str, strlist);
    @endcode

    @param arg the argument to look for in the list
    @param l the list to search for the first argument \a arg

    @return @ref True if the first argument is a member of the second argument list using hard comparisons (without
    any implicit type conversions), @ref False if not

    @see inlist(auto, softlist<auto>)
*/
bool inlist_hard(auto arg, softlist<auto> l) [flags=RET_VALUE_ONLY] {
    bool arg_is_nothing = arg.isNothing();

    ConstListIterator li(l);
    while (li.next()) {
        QoreValue lp = li.getValue();

        bool b;

        // do hard comparison inline
        if (lp.isNothing()) {
            b = arg_is_nothing;
        } else if (arg_is_nothing) {
            b = false;
        } else {
            b = arg.isEqualHard(lp);
            if (*xsink) {
                return QoreValue();
            }
        }

        if (b) {
            return true;
        }
    }
    return false;
}

//! Returns a list containing an arithmetic progression of integers.
/**
    @par Example:
    @code{.py}
range(2, 5); # (2, 3, 4, 5)
range(2, -2); # (2, 1, 0, -1, -2)
range(1, 10, 5); # (1, 6)
range(0, 10, 5); # (0, 5, 10)
range(-10, 10, 5); # (-10, -5, 0, 5, 10)
range(10, -10, 5); # (10, 5, 0, -5, -10)
    @endcode

    @param start the initial value
    @param stop the upper limit
    @param step the step; the default is 1; must be greater than 0; the function throws a \c RANGE-ERROR exception
    when this argument is < 1

    @return Returns a list containing an arithmetic progression of integers.

    @throw RANGE-ERROR this exception is thrown if \c step < 1

    @see xrange

    @note the main difference between range() and xrange() is that range returns real list and xrange returns a
    RangeIterator

    @since
    - %Qore 0.8.6
    - %Qore 0.9.5 does not include the upper limit in the range unless @ref broken-range "%broken-range" is set
*/
list<int> range(int start, int stop, int step = 1) [flags=RET_VALUE_ONLY] {
    return range_intern(start, stop, step, xsink);
}

//! Returns a list containing an arithmetic progression of integers with start = 0 and step = 1.
/**
    This is an overloaded version of range(int, int, int) meaning \c range(0, \c stop, 1)

    @par Example:
    @code{.py}
range(1); # (0, 1)
range(-3); # (0, -1, -2, -3)
    @endcode

    @param stop the final value

    @return Returns a list containing an arithmetic progression of integers with start = 0 and step = 1.

    @see xrange

    @note the main difference between range() and xrange() is that range returns real list and xrange returns a
    RangeIterator

    @since
    - %Qore 0.8.6
    - %Qore 0.9.5 does not include the upper limit in the range unless @ref broken-range "%broken-range" is set
 */
list<int> range(int stop) [flags=CONSTANT] {
    return range_intern(0, stop, 1, xsink);
}
///@}
