blob: 6a6afc43a176cafdba9094df27a7eb22234824c8 [file] [log] [blame]
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
/// Indexed entity interfaces for modeling elements derived from Kernel IR.
import '../elements/entities.dart';
abstract class _Indexed {
int _index;
}
abstract class IndexedLibrary extends _Indexed implements LibraryEntity {
/// Library index used for fast lookup in [KernelToElementMapBase].
int get libraryIndex => _index;
@override
int get hashCode => 7 * _index + 2;
}
abstract class IndexedClass extends _Indexed implements ClassEntity {
/// Class index used for fast lookup in [KernelToElementMapBase].
int get classIndex => _index;
@override
int get hashCode => 7 * _index + 1;
}
abstract class IndexedMember extends _Indexed implements MemberEntity {
/// Member index used for fast lookup in [KernelToElementMapBase].
int get memberIndex => _index;
@override
int get hashCode => 7 * _index;
}
abstract class IndexedFunction extends _Indexed
implements IndexedMember, FunctionEntity {}
abstract class IndexedConstructor
implements IndexedFunction, ConstructorEntity {}
abstract class IndexedField implements IndexedMember, FieldEntity {}
abstract class IndexedTypeVariable extends _Indexed
implements TypeVariableEntity {
/// Type variable index used for fast lookup in [KernelToElementMapBase].
int get typeVariableIndex => _index;
}
abstract class IndexedTypedef extends _Indexed implements TypedefEntity {
/// Typedef index used for fast lookup in [KernelToElementMapBase].
int get typedefIndex => _index;
}
abstract class IndexedLocal extends _Indexed implements Local {
int get localIndex => _index;
}
/// Base implementation for an index based map of entities of type [E].
abstract class EntityMapBase<E extends _Indexed> {
bool _closed = false;
int _size = 0;
List<E> _list = <E>[];
/// Returns the [index]th entity in the map.
E getEntity(int index) => _list[index];
/// Returns the number of non-null entities in the map.
int get size => _size;
/// Returns the number (null and non-null) entities in the map.
int get length => _list.length;
/// Closes the entity map, prohibiting further registration.
///
/// This is used to ensure that no new entities are added while serializing
/// modular code generation data.
void close() {
_closed = true;
}
}
/// Index based map of entities of type [E].
class EntityMap<E extends _Indexed> extends EntityMapBase<E> {
/// Registers a new [entity].
///
/// The index of [entity] is set to match its index in the entity list in this
/// map.
E0 register<E0 extends E>(E0 entity) {
assert(
!_closed, "Trying to register $entity @ ${_list.length} when closed.");
assert(entity != null);
assert(entity._index == null);
entity._index = _list.length;
_list.add(entity);
_size++;
return entity;
}
/// Registers a new [entity] by the given [index].
E0 registerByIndex<E0 extends E>(int index, E0 entity) {
assert(index >= _list.length);
_list.length = index;
return register(entity);
}
/// Calls [f] for each non-null entity.
void forEach<E0 extends E>(void f(E0 entity)) {
for (int index = 0; index < _list.length; index++) {
E entity = _list[index];
if (entity != null) {
f(entity);
}
}
}
}
/// Base implementation of an index based map of entities of type [E] with a
/// corresponding data object of type [D].
abstract class EntityDataMapBase<E extends _Indexed, D>
extends EntityMapBase<E> {
List<D> _data = <D>[];
/// Returns the data object stored for the [index]th entity.
D getData(E entity) {
int index = entity._index;
if (index < _list.length && index >= _data.length) {
throw new StateError(
'Data is in the process of being created for ${_list[index]}.');
}
return _data[index];
}
}
/// Index based map of entities of type [E] with a corresponding data object
/// of type [D].
class EntityDataMap<E extends _Indexed, D> extends EntityDataMapBase<E, D> {
/// Mark entity [index] as missing
void skipIndex(int index) {
assert(index == _list.length);
_list.add(null);
_data.add(null);
}
/// Registers a new [entity] with an associated [data] object.
///
/// The index of [entity] is set to match its index in the entity and data
/// lists in this map.
E0 register<E0 extends E, D0 extends D>(E0 entity, D0 data) {
assert(
!_closed, "Trying to register $entity @ ${_list.length} when closed.");
assert(entity != null);
assert(entity._index == null);
assert(
_list.length == _data.length,
'Data list length ${_data.length} inconsistent '
'with entity list length ${_list.length}.');
entity._index = _list.length;
_list.add(entity);
_size++;
assert(data != null);
_data.add(data);
return entity;
}
/// Registers a new [entity] with an associated [data] object by the given
/// [index].
E0 registerByIndex<E0 extends E, D0 extends D>(
int index, E0 entity, D0 data) {
assert(index >= _list.length);
_list.length = _data.length = index;
return register(entity, data);
}
/// Calls [f] for each non-null entity with its corresponding data object.
void forEach<E0 extends E, D0 extends D>(void f(E0 entity, D0 data)) {
if (_list.length != _data.length) {
throw new StateError('Data is in the process of being created.');
}
for (int index = 0; index < _list.length; index++) {
E entity = _list[index];
if (entity != null) {
f(entity, _data[index]);
}
}
}
}
/// Base implementation for an index based of entities of type [E] with a
/// corresponding data object of type [D] and an environment of type [V].
abstract class EntityDataEnvMapBase<E extends _Indexed, D, V>
extends EntityDataMapBase<E, D> {
List<V> _env = <V>[];
/// Returns the environment object stored for the [index]th entity.
V getEnv(E entity) {
int index = entity._index;
if (index < _list.length && index >= _env.length) {
throw new StateError(
'Env is in the process of being created for ${_list[index]}.');
}
return _env[index];
}
}
/// Index based of entities of type [E] with a corresponding data object of
/// type [D] and an environment of type [V].
class EntityDataEnvMap<E extends _Indexed, D, V>
extends EntityDataEnvMapBase<E, D, V> {
/// Registers a new [entity] with an associated [data] object and environment
/// [env].
///
/// The index of [entity] is set to match its index in the entity, data and
/// environment lists in this map.
E0 register<E0 extends E, D0 extends D, V0 extends V>(
E0 entity, D0 data, V0 env) {
assert(
!_closed, "Trying to register $entity @ ${_list.length} when closed.");
assert(entity != null);
assert(entity._index == null);
assert(
_list.length == _data.length,
'Data list length ${_data.length} inconsistent '
'with entity list length ${_list.length}.');
assert(
_list.length == _env.length,
'Env list length ${_env.length} inconsistent '
'with entity list length ${_list.length}.');
entity._index = _list.length;
_list.add(entity);
_size++;
assert(data != null);
_data.add(data);
assert(env != null);
_env.add(env);
return entity;
}
/// Registers a new [entity] with an associated [data] object and environment
/// [env] by the given [index].
E0 registerByIndex<E0 extends E, D0 extends D, V0 extends V>(
int index, E0 entity, D0 data, V0 env) {
assert(index >= _list.length);
_list.length = _data.length = _env.length = index;
return register(entity, data, env);
}
/// Calls [f] for each non-null entity with its corresponding data object and
/// environment.
void forEach<E0 extends E, D0 extends D, V0 extends V>(
void f(E0 entity, D0 data, V0 env)) {
if (_list.length != _data.length) {
throw new StateError('Data is in the process of being created.');
}
if (_list.length != _env.length) {
throw new StateError('Env is in the process of being created.');
}
for (int index = 0; index < _list.length; index++) {
E entity = _list[index];
if (entity != null) {
f(entity, _data[index], _env[index]);
}
}
}
}