dvander@154: /* vim: set ts=4 sw=4 tw=99 et: dvander@154: * dvander@12: * Copyright (C) 2012 David Anderson dvander@12: * dvander@154: * This file is part of SourcePawn. dvander@12: * dvander@154: * SourcePawn is free software: you can redistribute it and/or modify it under dvander@12: * the terms of the GNU General Public License as published by the Free dvander@12: * Software Foundation, either version 3 of the License, or (at your option) dvander@12: * any later version. dvander@12: * dvander@154: * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY dvander@12: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS dvander@12: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. dvander@12: * dvander@12: * You should have received a copy of the GNU General Public License along with dvander@154: * SourcePawn. If not, see http://www.gnu.org/licenses/. dvander@12: */ danderson@91: #include dvander@12: #include "Array.h" dvander@12: #include "Heap.h" dvander@12: #include "Zone.h" dvander@154: #include "Structures.h" dvander@12: #include "Heap-inl.h" dvander@12: dvander@59: using namespace ke; dvander@12: dvander@12: ArrayMap * dvander@154: ArrayMap::New(Zone *zone, Handle type) dvander@12: { dvander@31: Local obj(zone, zone->allocateMap(MapKind_Array, sizeof(ArrayMap), MapKind_MetaArray)); dvander@12: if (!obj) dvander@12: return NULL; dvander@12: dvander@31: Local map(zone, ArrayMap::cast(obj)); dvander@13: map->type_ = type; dvander@12: return map; dvander@12: } dvander@12: dvander@169: ArrayMap * dvander@169: ArrayMap::Attach(Zone *zone, Handle type) dvander@169: { dvander@169: if (type->newMap()) dvander@169: return ArrayMap::cast(type->newMap()); dvander@169: dvander@169: Local map(zone, ArrayMap::New(zone, type)); dvander@169: if (!map) dvander@169: return NULL; dvander@169: dvander@169: // Ensure the inner type has an ArrayMap if needed. dvander@169: if (type->contained()->isArray()) { dvander@169: Local contained(zone, type->contained()); dvander@169: if (!ArrayMap::Attach(zone, contained)) dvander@169: return NULL; dvander@169: } dvander@169: dvander@169: type->setNewMap(map); dvander@169: return map; dvander@169: } dvander@169: dvander@12: static inline size_t dvander@12: SizeFor(Type *type, unsigned elements) dvander@12: { dvander@154: if (type->contained()->isTraceable()) dvander@59: return sizeof(Array) + elements * sizeof(ke::Object *); dvander@20: if (type->contained()->isInt32()) dvander@12: return sizeof(Array) + elements * sizeof(int); dvander@21: if (type->contained()->primitive() == PrimitiveType_Char) dvander@21: return sizeof(Array) + elements * sizeof(char); dvander@12: assert(type->contained()->isFloat()); dvander@53: return elements * sizeof(float); dvander@12: } dvander@12: dvander@12: Array * dvander@185: Array::New(Zone *zone, Handle map, Heap::Tenure tenure) dvander@185: { dvander@185: assert(map->type()->isFixedLength()); dvander@185: dvander@185: return Array::New(zone, map, map->type()->fixedLength(), tenure); dvander@185: } dvander@185: dvander@185: Array * dvander@27: Array::New(Zone *zone, Handle map, uint32 elements, Heap::Tenure tenure) dvander@12: { dvander@53: size_t elementBytes = SizeFor(map->type(), elements); dvander@53: size_t bytes = sizeof(Array) + elementBytes; dvander@31: Local array(zone, Array::cast(zone->allocate(map, bytes, tenure))); dvander@31: if (!array) dvander@12: return NULL; dvander@12: dvander@13: array->nelements_ = elements; dvander@66: array->elements_ = (Array *)array + 1; dvander@154: dvander@154: if (map->type()->contained()->isArray()) { dvander@154: Local childMap(zone, ArrayMap::cast(map->type()->contained()->newMap())); dvander@154: Local child(zone); dvander@154: for (unsigned i = 0; i < elements; i++) { dvander@184: child = Array::New(zone, childMap, map->type()->contained()->declaredLength(), tenure); dvander@154: if (!child) dvander@154: return NULL; dvander@154: dvander@154: array->writeObject(zone, i, child); dvander@154: } dvander@154: } else if (map->type()->contained()->isStruct()) { dvander@154: Local childMap(zone, StructMap::cast(map->type()->contained()->newMap())); dvander@154: Local child(zone); dvander@154: for (unsigned i = 0; i < elements; i++) { dvander@154: child = Struct::New(zone, childMap, tenure); dvander@154: if (!child) dvander@154: return NULL; dvander@154: dvander@154: array->writeObject(zone, i, child); dvander@154: } dvander@154: } else { dvander@154: memset(array->elements_, 0, elementBytes); dvander@154: } dvander@31: return array; dvander@12: } dvander@31: dvander@65: Array * dvander@169: Array::NewString(Zone *zone, Handle map, Address buffer, size_t length, Heap::Tenure tenure) dvander@169: { dvander@169: Local array(zone, Array::New(zone, map, length, tenure)); dvander@169: if (!array) dvander@169: return NULL; dvander@169: dvander@169: assert(array->length() >= length); dvander@169: memcpy(array->chars(), buffer, length); dvander@169: return array; dvander@169: } dvander@169: dvander@169: Array * dvander@65: Array::NewExternal(Zone *zone, Handle map, uint32 nelements, void *buffer, dvander@65: Heap::Tenure tenure) dvander@65: { dvander@65: Local array(zone, Array::cast(zone->allocate(map, sizeof(Array), tenure))); dvander@65: if (!array) dvander@65: return NULL; dvander@65: dvander@65: array->nelements_ = nelements; dvander@65: array->elements_ = buffer; dvander@65: return array; dvander@65: } dvander@154: