Skip to content

Updates, tweaks, and fixes for copy-on-write behavior. #302

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -1 +1 @@
include: package:pedantic/analysis_options.yaml
include: package:lints/recommended.yaml
4 changes: 2 additions & 2 deletions benchmark/lib/benchmark.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class BuiltCollectionBenchmark {
Iterable<int> list = List<int>.generate(1000, (x) => x);
var fastLazyIterable = list.map((x) => x + 1);
var slowLazyIterable = list.map(_shortDelay);
var builderFactory = () => ListBuilder<int>()..addAll(list);
builderFactory() => ListBuilder<int>()..addAll(list);

_benchmark('ListBuilder.$name,list', function, builderFactory, list);
_benchmark('ListBuilder.$name,fast lazy iterable', function,
Expand All @@ -50,7 +50,7 @@ class BuiltCollectionBenchmark {
Iterable<int> list = List<int>.generate(1000, (x) => x);
var fastLazyIterable = list.map((x) => x + 1);
var slowLazyIterable = list.map(_shortDelay);
var builderFactory = () => SetBuilder<int>();
builderFactory() => SetBuilder<int>();

_benchmark('SetBuilder.$name,list', function, builderFactory, list);
_benchmark('SetBuilder.$name,fast lazy iterable', function,
Expand Down
4 changes: 4 additions & 0 deletions benchmark/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ publish_to: none
environment:
sdk: '>=2.12.0 <4.0.0'

dependencies:
built_collection:
path: ..

dev_dependencies:
build_runner: any
build_test: any
Expand Down
5 changes: 4 additions & 1 deletion example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ description: >
Example, not for publishing.
homepage: https://github.com/google/built_collection.dart

# This package is not intended for consumption on pub.dev. DO NOT publish.
publish_to: none

environment:
sdk: '>=2.12.0 <4.0.0'

dependency_overrides:
dependencies:
built_collection:
path: ..
11 changes: 6 additions & 5 deletions lib/built_collection.dart
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,10 @@
/// a copy, but return a copy-on-write wrapper. So, Built Collections can be
/// efficiently and easily used with code that needs core SDK collections but
/// does not mutate them.
library;

export 'src/list.dart' hide OverriddenHashcodeBuiltList;
export 'src/list_multimap.dart' hide OverriddenHashcodeBuiltListMultimap;
export 'src/map.dart' hide OverriddenHashcodeBuiltMap;
export 'src/set.dart' hide OverriddenHashcodeBuiltSet;
export 'src/set_multimap.dart' hide OverriddenHashcodeBuiltSetMultimap;
export 'src/list.dart' hide OverriddenHashCodeBuiltList;
export 'src/list_multimap.dart' hide OverriddenHashCodeBuiltListMultimap;
export 'src/map.dart' hide OverriddenHashCodeBuiltMap;
export 'src/set.dart' hide OverriddenHashCodeBuiltSet;
export 'src/set_multimap.dart' hide OverriddenHashCodeBuiltSetMultimap;
75 changes: 47 additions & 28 deletions lib/src/internal/copy_on_write_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,20 @@
// 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 ListBase;
import 'dart:math';

class CopyOnWriteList<E> implements List<E> {
class CopyOnWriteList<E> extends ListBase<E> {
bool _copyBeforeWrite;
final bool _growable;
List<E> _list;

CopyOnWriteList(this._list, this._growable) : _copyBeforeWrite = true;

// Read-only methods: just forward.
// Read-only methods returning values: just forward.
// Methods returning a lazy view use default list implementation
// until first write, to avoid capturing a `_list` which may be replaced
// on a write.

@override
int get length => _list.length;
Expand All @@ -26,10 +30,10 @@ class CopyOnWriteList<E> implements List<E> {
bool any(bool Function(E) test) => _list.any(test);

@override
Map<int, E> asMap() => _list.asMap();
Map<int, E> asMap() => _copyBeforeWrite ? super.asMap() : _list.asMap();

@override
List<T> cast<T>() => CopyOnWriteList<T>(_list.cast<T>(), _growable);
List<T> cast<T>() => _copyBeforeWrite ? super.cast<T>() : _list.cast<T>();

@override
bool contains(Object? element) => _list.contains(element);
Expand All @@ -41,7 +45,8 @@ class CopyOnWriteList<E> implements List<E> {
bool every(bool Function(E) test) => _list.every(test);

@override
Iterable<T> expand<T>(Iterable<T> Function(E) f) => _list.expand(f);
Iterable<T> expand<T>(Iterable<T> Function(E) f) =>
_copyBeforeWrite ? super.expand<T>(f) : _list.expand(f);

@override
E get first => _list.first;
Expand All @@ -55,16 +60,20 @@ class CopyOnWriteList<E> implements List<E> {
_list.fold(initialValue, combine);

@override
Iterable<E> followedBy(Iterable<E> other) => _list.followedBy(other);
Iterable<E> followedBy(Iterable<E> other) =>
_copyBeforeWrite ? super.followedBy(other) : _list.followedBy(other);

@override
void forEach(void Function(E) f) => _list.forEach(f);
void forEach(void Function(E) action) => _list.forEach(action);

@override
Iterable<E> getRange(int start, int end) => _list.getRange(start, end);
Iterable<E> getRange(int start, int end) => _copyBeforeWrite
? super.getRange(start, end)
: _list.getRange(start, end);

@override
int indexOf(E element, [int start = 0]) => _list.indexOf(element, start);
int indexOf(covariant E element, [int start = 0]) =>
_list.indexOf(element, start);

@override
int indexWhere(bool Function(E) test, [int start = 0]) =>
Expand All @@ -77,7 +86,8 @@ class CopyOnWriteList<E> implements List<E> {
bool get isNotEmpty => _list.isNotEmpty;

@override
Iterator<E> get iterator => _list.iterator;
Iterator<E> get iterator =>
_copyBeforeWrite ? super.iterator : _list.iterator;

@override
String join([String separator = '']) => _list.join(separator);
Expand All @@ -86,7 +96,8 @@ class CopyOnWriteList<E> implements List<E> {
E get last => _list.last;

@override
int lastIndexOf(E element, [int? start]) => _list.lastIndexOf(element, start);
int lastIndexOf(covariant E element, [int? start]) =>
_list.lastIndexOf(element, start);

@override
int lastIndexWhere(bool Function(E) test, [int? start]) =>
Expand All @@ -97,13 +108,15 @@ class CopyOnWriteList<E> implements List<E> {
_list.lastWhere(test, orElse: orElse);

@override
Iterable<T> map<T>(T Function(E) f) => _list.map(f);
Iterable<T> map<T>(T Function(E) f) =>
_copyBeforeWrite ? super.map(f) : _list.map(f);

@override
E reduce(E Function(E, E) combine) => _list.reduce(combine);

@override
Iterable<E> get reversed => _list.reversed;
Iterable<E> get reversed =>
_copyBeforeWrite ? super.reversed : _list.reversed;

@override
E get single => _list.single;
Expand All @@ -113,19 +126,23 @@ class CopyOnWriteList<E> implements List<E> {
_list.singleWhere(test, orElse: orElse);

@override
Iterable<E> skip(int count) => _list.skip(count);
Iterable<E> skip(int count) =>
_copyBeforeWrite ? super.skip(count) : _list.skip(count);

@override
Iterable<E> skipWhile(bool Function(E) test) => _list.skipWhile(test);
Iterable<E> skipWhile(bool Function(E) test) =>
_copyBeforeWrite ? super.skipWhile(test) : _list.skipWhile(test);

@override
List<E> sublist(int start, [int? end]) => _list.sublist(start, end);

@override
Iterable<E> take(int count) => _list.take(count);
Iterable<E> take(int count) =>
_copyBeforeWrite ? super.take(count) : _list.take(count);

@override
Iterable<E> takeWhile(bool Function(E) test) => _list.takeWhile(test);
Iterable<E> takeWhile(bool Function(E) test) =>
_copyBeforeWrite ? super.takeWhile(test) : _list.takeWhile(test);

@override
List<E> toList({bool growable = true}) => _list.toList(growable: growable);
Expand All @@ -134,10 +151,12 @@ class CopyOnWriteList<E> implements List<E> {
Set<E> toSet() => _list.toSet();

@override
Iterable<E> where(bool Function(E) test) => _list.where(test);
Iterable<E> where(bool Function(E) test) =>
_copyBeforeWrite ? super.where(test) : _list.where(test);

@override
Iterable<T> whereType<T>() => _list.whereType<T>();
Iterable<T> whereType<T>() =>
_copyBeforeWrite ? super.whereType<T>() : _list.whereType<T>();

// Mutating methods: copy first if needed.

Expand Down Expand Up @@ -166,9 +185,9 @@ class CopyOnWriteList<E> implements List<E> {
}

@override
void add(E value) {
void add(E element) {
_maybeCopyBeforeWrite();
_list.add(value);
_list.add(element);
}

@override
Expand Down Expand Up @@ -214,9 +233,9 @@ class CopyOnWriteList<E> implements List<E> {
}

@override
bool remove(Object? value) {
bool remove(Object? element) {
_maybeCopyBeforeWrite();
return _list.remove(value);
return _list.remove(element);
}

@override
Expand Down Expand Up @@ -256,15 +275,15 @@ class CopyOnWriteList<E> implements List<E> {
}

@override
void fillRange(int start, int end, [E? fillValue]) {
void fillRange(int start, int end, [E? fill]) {
_maybeCopyBeforeWrite();
_list.fillRange(start, end, fillValue);
_list.fillRange(start, end, fill);
}

@override
void replaceRange(int start, int end, Iterable<E> iterable) {
void replaceRange(int start, int end, Iterable<E> newContents) {
_maybeCopyBeforeWrite();
_list.replaceRange(start, end, iterable);
_list.replaceRange(start, end, newContents);
}

@override
Expand All @@ -275,6 +294,6 @@ class CopyOnWriteList<E> implements List<E> {
void _maybeCopyBeforeWrite() {
if (!_copyBeforeWrite) return;
_copyBeforeWrite = false;
_list = List<E>.from(_list, growable: _growable);
_list = List<E>.of(_list, growable: _growable);
}
}
6 changes: 2 additions & 4 deletions lib/src/internal/copy_on_write_map.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@
// All rights reserved. Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

typedef _MapFactory<K, V> = Map<K, V> Function();

class CopyOnWriteMap<K, V> implements Map<K, V> {
final _MapFactory<K, V>? _mapFactory;
final Map<K, V> Function()? _mapFactory;
bool _copyBeforeWrite;
Map<K, V> _map;

Expand Down Expand Up @@ -115,6 +113,6 @@ class CopyOnWriteMap<K, V> implements Map<K, V> {
_copyBeforeWrite = false;
_map = _mapFactory != null
? (_mapFactory!()..addAll(_map))
: Map<K, V>.from(_map);
: Map<K, V>.of(_map);
}
}
Loading