Source

arana-main / arana / tuple.c

Full commit
/*
 * tuple.c
 *
 * (c) Copyright 2009 by Armin Ronacher.
 */

#include "arana.h"

AR
arana_tuple_new(AR_SIG, Ar_size_t size)
{
    if (size == 0 && AR_SINGLETON(EMPTY_TUPLE))
        return AR_SINGLETON(EMPTY_TUPLE);
    ArTuple *self = (ArTuple *)AR_ALLOCTE(ArTuple, sizeof(AR) * size);
    if (!self)
        AR_RAISE_OOM();
    AR_OBJECT_INIT(self, ArTupleType);
    self->size = size;
    return (AR)self;
}

AR
arana_tuple_pack(AR_SIG, ...)
{
    Ar_size_t i, size = 0;
    AR result, *items;
    va_list vargs;

    va_start(vargs, AR_SIG_LASTARG);
    while (va_arg(vargs, void *))
        size++;
    va_end(vargs);

    va_start(vargs, AR_SIG_LASTARG);
    result = AR_TUPLE(size);
    items = ((ArTuple *)result)->items;
    for (i = 0; i < size; ++i)
        items[i] = va_arg(vargs, AR);
    va_end(vargs);

    return result;
}

AR
arana_tuple_from_list(AR_SIG, AR list)
{
    ArTuple *result = (ArTuple *)AR_TUPLE(AR_LIST_SIZE(list));
    Ar_size_t index;
    for (index = 0; index < AR_LIST_SIZE(list); ++index)
        result->items[index] = AR_LIST_GET(list, index);
    return (AR)result;
}

/* invoked by AR_TUPLE_CONCAT */
AR
_arana_api_tuple_concat(AR_SIG, AR self, AR other)
{
    Ar_size_t i;
    Ar_size_t size = AR_TUPLE_SIZE(self) + AR_TUPLE_SIZE(other);
    AR result = AR_TUPLE(size);
    for (i = 0; i < AR_TUPLE_SIZE(self); i++)
        AR_TUPLE_PUT(result, i, AR_TUPLE_GET(self, i));
    for (; i < size; i++)
        AR_TUPLE_PUT(result, i, AR_TUPLE_GET(other, AR_TUPLE_SIZE(self) - i));
    return result;
}

static AR
arana_tuple_concat(AR_SIG, AR self, AR args)
{
    AR other;
    AR_PARSE(args, "O::concat", &other);
    if (!AR_IS_TUPLE(other))
        AR_RAISE(AR_ARGUMENT_ERROR(NULL, 0, "tuples can only be concatenated "
                                   "with other tuples."));
    return AR_TUPLE_CONCAT(self, other);
}

static AR
arana_tuple_get(AR_SIG, AR self, AR args)
{
    AR index;
    AR_PARSE(args, "O::getitem", &index);
    if (index >= ((ArTuple *)self)->size || index < 0)
        AR_RAISE(AR_INDEX_ERROR(index, "List index out of range"));
    return AR_TUPLE_GET(self, index);
}

static AR
arana_tuple_length_get(AR_SIG, AR self, AR args)
{
    AR_ASSERT_EMPTY_ARGS(args, "length:get");
    return AR_INTEGER(AR_TUPLE_SIZE(self));
}

static AR
arana_tuple_to_string(AR_SIG, AR self, AR args)
{
    Ar_size_t i;
    AR builder = AR_STRINGBUILDER();
    AR_STRINGBUILDER_APPEND(builder, "(");
    for (i = 0; i < AR_TUPLE_SIZE(self); ++i) {
        AR itemrepr = AR_REPR(AR_TUPLE_GET(self, i));
        if (i)
            AR_STRINGBUILDER_APPEND(builder, ", ");
        AR_STRINGBUILDER_APPEND_STRING(builder, itemrepr);
    }
    if (AR_TUPLE_SIZE(self) == 1)
        AR_STRINGBUILDER_APPEND(builder, ",");
    AR_STRINGBUILDER_APPEND(builder, ")");
    return AR_STRINGBUILDER_TO_STRING(builder);
}

static AR
arana_tuple_get_iterator(AR_SIG, AR self, AR args)
{
    ArTupleIterator *iterator;
    AR_ASSERT_EMPTY_ARGS(args, "get_iterator");
    iterator = (ArTupleIterator *)
        AR_ALLOCATE_OBJECT(ArTupleIterator, ArTupleIteratorType);
    iterator->pos = 0;
    iterator->tuple = self;
    return (AR)iterator;
}

static AR
arana_tuple_iterator_next(AR_SIG, AR self, AR args)
{
    ArTupleIterator *iter = (ArTupleIterator *)self;
    AR_ASSERT_EMPTY_ARGS(args, "next");
    if (iter->pos >= AR_TUPLE_SIZE(iter->tuple))
        AR_RAISE(AR_STOP_ITERATION());
    return AR_TUPLE_GET(iter->tuple, iter->pos++);
}

ArObjectType ArTupleType = {
    .name = "Tuple",
    .parent = &ArTypeType
};

ArObjectType ArTupleIteratorType = {
    .name = "TupleIterator",
    .parent = &ArTypeType
};

AR
arana_create_tuple_type(AR_SIG)
{
    AR type = AR_CREATE_TYPE(ArTupleType);
    AR_BIND_METHOD(type, ":getitem", arana_tuple_get);
    AR_BIND_METHOD(type, ":concat", arana_tuple_concat);
    AR_BIND_METHOD(type, "length:get", arana_tuple_length_get);
    AR_BIND_METHOD(type, "to_string", arana_tuple_to_string);
    AR_BIND_METHOD(type, "get_iterator", arana_tuple_get_iterator);
    return type;
}

AR
arana_create_tuple_iterator_type(AR_SIG)
{
    AR type = AR_CREATE_TYPE(ArTupleIteratorType);
    AR_BIND_METHOD(type, "next", arana_tuple_iterator_next);
    AR_BIND_METHOD(type, "get_iterator", arana_generic_get_self_iterator);
    return type;
}