blob: d6677746419d3987d6ccabcbeb43be006aad2f96 [file] [log] [blame] [edit]
// Copyright (c) 2023, 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.
import 'dart:collection' show SplayTreeMap;
import 'package:kernel/ast.dart';
import 'class_info.dart';
/// Describes shape of a record as the number of positionals + set of field
/// names.
class RecordShape {
/// Number of positional fields.
final int positionals;
/// Maps names of the named fields in the record to their indices in the
/// record payload.
final SplayTreeMap<String, int> _names;
/// Names of named fields, sorted.
Iterable<String> get names => _names.keys;
/// Total number of fields.
int get numFields => positionals + _names.length;
/// Create a new [RecordShape] object by given number of
/// positional fields and named fields.
/// [names] should be sorted.
RecordShape(this.positionals, Iterable<String> names)
: _names = SplayTreeMap.fromIterables(
names, Iterable.generate(names.length, (i) => i + positionals));
RecordShape.fromType(RecordType recordType)
: this(recordType.positional.length,
recordType.named.map((ty) => ty.name));
@override
String toString() => 'Record(positionals: $positionals, names: $_names)';
@override
bool operator ==(Object other) {
if (other is! RecordShape) {
return false;
}
if (positionals != other.positionals) {
return false;
}
if (_names.length != other._names.length) {
return false;
}
final names1Iter = _names.keys.iterator;
final names2Iter = other._names.keys.iterator;
while (names1Iter.moveNext()) {
names2Iter.moveNext();
if (names1Iter.current != names2Iter.current) {
return false;
}
}
return true;
}
@override
int get hashCode => Object.hash(positionals, Object.hashAll(_names.keys));
/// Struct index of a positional field.
int getPositionalIndex(int position) => FieldIndex.recordFieldBase + position;
/// Struct index of a named field.
int getNameIndex(String name) =>
FieldIndex.recordFieldBase +
(_names[name] ??
(throw 'RecordImplementation.getNameIndex: '
'name $name not in record: $this'));
}