Skip to content

Commit

Permalink
feat: use jenkins hash (#28)
Browse files Browse the repository at this point in the history
  • Loading branch information
felangel authored May 27, 2024
1 parent 96a1856 commit 0f91229
Show file tree
Hide file tree
Showing 13 changed files with 64 additions and 21 deletions.
6 changes: 2 additions & 4 deletions lib/data_class_macro.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import 'package:collection/collection.dart';
/// Experimental support for data classes in Dart using package:macros.
library data_class_macro;

export 'src/constructable_macro.dart' show Constructable;
export 'src/copyable_macro.dart' show Copyable;
export 'src/data_macro.dart' show Data;
export 'src/equatable_macro.dart' show Equatable;
export 'src/stringable_macro.dart' show Stringable;

final deepEquals = const DeepCollectionEquality().equals;
const undefined = Object();
48 changes: 48 additions & 0 deletions lib/src/_data_class_macro.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import 'package:collection/collection.dart';

// Libraries used in augmented code.
final dartCore = Uri.parse('dart:core');
final dataClassMacro = Uri.parse(
'package:data_class_macro/src/_data_class_macro.dart',
);

// Methods used in augmented code.
const undefined = Object();
final deepEquals = const DeepCollectionEquality().equals;

// TODO(felangel): use jenkins hash from `package:equatable`
// once https://github.com/felangel/equatable/pull/174 is published.
/// Generate a hash for the provided [fields].
int hashAll(Iterable<Object?>? fields) {
return _finish(fields == null ? 0 : fields.fold(0, _combine));
}

int _combine(int hash, Object? object) {
if (object is Map) {
object.keys
.sorted((Object? a, Object? b) => a.hashCode - b.hashCode)
.forEach((Object? key) {
hash = hash ^ _combine(hash, [key, (object! as Map)[key]]);
});
return hash;
}
if (object is Set) {
object = object.sorted((Object? a, Object? b) => a.hashCode - b.hashCode);
}
if (object is Iterable) {
for (final value in object) {
hash = hash ^ _combine(hash, value);
}
return hash ^ object.length;
}

hash = 0x1fffffff & (hash + object.hashCode);
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
return hash ^ (hash >> 6);
}

int _finish(int hash) {
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
hash = hash ^ (hash >> 11);
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
}
1 change: 1 addition & 0 deletions lib/src/copyable_macro.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:core';

import 'package:collection/collection.dart';
import 'package:data_class_macro/src/_data_class_macro.dart';
import 'package:data_class_macro/src/macro_extensions.dart';
import 'package:macros/macros.dart';

Expand Down
9 changes: 5 additions & 4 deletions lib/src/equatable_macro.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:collection/collection.dart';
import 'package:data_class_macro/src/_data_class_macro.dart';
import 'package:data_class_macro/src/macro_extensions.dart';
import 'package:macros/macros.dart';

Expand Down Expand Up @@ -129,9 +130,9 @@ macro class Equatable implements ClassDeclarationsMacro, ClassDefinitionMacro {
);
if (hashCode == null) return;

final (hashCodeMethod, object, fields) = await (
final (hashCodeMethod, hashAll, fields) = await (
builder.buildMethod(hashCode.identifier),
builder.codeFrom(dartCore, 'Object'),
builder.codeFrom(dataClassMacro, 'hashAll'),
builder.allFieldsOf(clazz),
).wait;

Expand All @@ -141,8 +142,8 @@ macro class Equatable implements ClassDeclarationsMacro, ClassDefinitionMacro {
FunctionBodyCode.fromParts(
[
'=> ',
object,
'.hashAll([',
hashAll,
'([',
fieldNames.join(', '),
']);',
],
Expand Down
6 changes: 0 additions & 6 deletions lib/src/macro_extensions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -248,9 +248,3 @@ extension TypeAnnotationX on TypeAnnotation {
return null;
}
}

// Used libraries
final dartCore = Uri.parse('dart:core');
final dataClassMacro = Uri.parse(
'package:data_class_macro/data_class_macro.dart',
);
1 change: 1 addition & 0 deletions lib/src/stringable_macro.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:core';

import 'package:collection/collection.dart';
import 'package:data_class_macro/src/_data_class_macro.dart';
import 'package:data_class_macro/src/macro_extensions.dart';
import 'package:macros/macros.dart';

Expand Down
2 changes: 1 addition & 1 deletion test/src/data_macro/empty_class_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ void main() {
});

test('hashCode is correct', () {
expect(EmptyClass().hashCode, equals(Object.hashAll([])));
expect(EmptyClass().hashCode, equals(EmptyClass().hashCode));
});

test('toString is correct', () {
Expand Down
2 changes: 1 addition & 1 deletion test/src/data_macro/empty_nested_subclass_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ void main() {
});

test('hashCode is correct', () {
expect(EmptyNestedSubClass().hashCode, equals(Object.hashAll([])));
expect(EmptyNestedSubClass().hashCode, equals(EmptyNestedSubClass().hashCode));
});

test('toString is correct', () {
Expand Down
2 changes: 1 addition & 1 deletion test/src/data_macro/empty_subclass_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ void main() {
});

test('hashCode is correct', () {
expect(EmptySubClass().hashCode, equals(Object.hashAll([])));
expect(EmptySubClass().hashCode, equals(EmptySubClass().hashCode));
});

test('toString is correct', () {
Expand Down
2 changes: 1 addition & 1 deletion test/src/equatable_macro/empty_class_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ void main() {
});

test('hashCode is correct', () {
expect(EmptyClass().hashCode, equals(Object.hashAll([])));
expect(EmptyClass().hashCode, equals(EmptyClass().hashCode));
});
});
}
2 changes: 1 addition & 1 deletion test/src/equatable_macro/empty_nested_subclass_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ void main() {
});

test('hashCode is correct', () {
expect(EmptyNestedSubClass().hashCode, equals(Object.hashAll([])));
expect(EmptyNestedSubClass().hashCode, equals(EmptyNestedSubClass().hashCode));
});
});
}
2 changes: 1 addition & 1 deletion test/src/equatable_macro/empty_subclass_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ void main() {
});

test('hashCode is correct', () {
expect(EmptySubClass().hashCode, equals(Object.hashAll([])));
expect(EmptySubClass().hashCode, equals(EmptySubClass().hashCode));
});
});
}
2 changes: 1 addition & 1 deletion test/src/equatable_macro/static_field_class_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ void main() {
});

test('hashCode is correct', () {
expect(StaticFieldClass().hashCode, equals(Object.hashAll([])));
expect(StaticFieldClass().hashCode, equals(StaticFieldClass().hashCode));
});
});
}

0 comments on commit 0f91229

Please sign in to comment.