src/List.h
author Asher Baker <asherkin@gmail.com>
Mon Jun 10 15:52:44 2013 +0100 (2013-06-10)
changeset 265 3a903b89a514
parent 251 ca99a81745fe
permissions -rw-r--r--
Fixed type checking for multidimensional arrays.
dvander@251
     1
/* vim: set ts=4 sw=4 tw=99 et:
dvander@251
     2
 *
dvander@251
     3
 * Copyright (C) 2012 David Anderson
dvander@251
     4
 *
dvander@251
     5
 * This file is part of SourcePawn.
dvander@251
     6
 *
dvander@251
     7
 * SourcePawn is free software: you can redistribute it and/or modify it under
dvander@251
     8
 * the terms of the GNU General Public License as published by the Free
dvander@251
     9
 * Software Foundation, either version 3 of the License, or (at your option)
dvander@251
    10
 * any later version.
dvander@251
    11
 * 
dvander@251
    12
 * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
dvander@251
    13
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
dvander@251
    14
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
dvander@251
    15
 *
dvander@251
    16
 * You should have received a copy of the GNU General Public License along with
dvander@251
    17
 * SourcePawn. If not, see http://www.gnu.org/licenses/.
dvander@251
    18
 */
dvander@251
    19
#ifndef _include_sp2_list_h_
dvander@251
    20
#define _include_sp2_list_h_
dvander@251
    21
dvander@251
    22
#include "Objects.h"
dvander@251
    23
#include "FixedArray.h"
dvander@251
    24
#include "Zone.h"
dvander@251
    25
#include "Heap-inl.h"
dvander@251
    26
#include "Handles-inl.h"
dvander@251
    27
dvander@251
    28
namespace ke {
dvander@251
    29
dvander@251
    30
template <typename T>
dvander@251
    31
class List : public Object
dvander@251
    32
{
dvander@251
    33
  public:
dvander@251
    34
    static List *New(Zone *zone, Heap::Tenure tenure = Heap::Tenure_Default) {
dvander@251
    35
        Local<List> list(zone, List::cast(zone->allocate(MapKind_List, sizeof(List), tenure)));
dvander@251
    36
        if (!list)
dvander@251
    37
            return NULL;
dvander@251
    38
dvander@251
    39
        list->length_ = 0;
dvander@251
    40
        list->array_ = NULL;
dvander@251
    41
dvander@251
    42
        return list;
dvander@251
    43
    }
dvander@251
    44
dvander@251
    45
    bool append(Zone *zone, Handle<T> obj) {
dvander@251
    46
        Local<List> list(zone, this);
dvander@251
    47
        if (!Grow(zone, list, 1))
dvander@251
    48
            return false;
dvander@251
    49
dvander@251
    50
        list->array_->set(zone, list->length_, obj);
dvander@251
    51
        list->length_++;
dvander@251
    52
        return true;
dvander@251
    53
    }
dvander@251
    54
dvander@251
    55
    T *at(unsigned i) {
dvander@251
    56
        return T::cast(array_->at(i));
dvander@251
    57
    }
dvander@251
    58
dvander@251
    59
    unsigned length() {
dvander@251
    60
        return length_;
dvander@251
    61
    }
dvander@251
    62
dvander@251
    63
  private:
dvander@251
    64
    static bool Grow(Zone *zone, Handle<List> list, unsigned amount) {
dvander@251
    65
        if (!IsUint32AddSafe(list->length(), amount)) {
dvander@251
    66
            zone->reportAllocationOverflow();
dvander@251
    67
            return false;
dvander@251
    68
        }
dvander@251
    69
dvander@251
    70
        unsigned newlen = list->length() + amount;
dvander@251
    71
        if (list->array_ && newlen < list->array_->length())
dvander@251
    72
            return true;
dvander@251
    73
dvander@251
    74
        unsigned maxsize = list->array_ ? list->array_->length() : 8;
dvander@251
    75
        if (!IsUint32AddSafe(maxsize, amount)) {
dvander@251
    76
            zone->reportAllocationOverflow();
dvander@251
    77
            return false;
dvander@251
    78
        }
dvander@251
    79
dvander@251
    80
        while (newlen > maxsize) {
dvander@251
    81
            if (!IsUint32MultiplySafe(maxsize, 2)) {
dvander@251
    82
                zone->reportAllocationOverflow();
dvander@251
    83
                return false;
dvander@251
    84
            }
dvander@251
    85
            maxsize *= 2;
dvander@251
    86
        }
dvander@251
    87
dvander@251
    88
        Local<FixedArray> array(zone, FixedArray::New(zone, maxsize, Heap::Tenure_Default));
dvander@251
    89
        if (!array)
dvander@251
    90
            return false;
dvander@251
    91
dvander@251
    92
        for (unsigned i = 0; i < list->length_; i++)
dvander@251
    93
            array->set(zone, i, list->array_->at(i));
dvander@251
    94
dvander@251
    95
        list->array_ = array;
dvander@251
    96
        return true;
dvander@251
    97
    }
dvander@251
    98
dvander@251
    99
  public:
dvander@251
   100
dvander@251
   101
    // Begin GC descriptor.
dvander@251
   102
    static inline size_t offsetOfArray() {
dvander@251
   103
        return OFFSETOF(List, array_);
dvander@251
   104
    }
dvander@251
   105
    // End GC descriptor.
dvander@251
   106
dvander@251
   107
    static inline List *cast(Object *obj) {
dvander@251
   108
        assert(!obj || obj->is(MapKind_List));
dvander@251
   109
        return reinterpret_cast<List *>(obj);
dvander@251
   110
    }
dvander@251
   111
dvander@251
   112
  private:
dvander@251
   113
    unsigned length_;
dvander@251
   114
    FixedArray *array_;
dvander@251
   115
};
dvander@251
   116
dvander@251
   117
} // namespace ke
dvander@251
   118
dvander@251
   119
#endif // _include_sp2_list_h_