letyletylety / deepcopy

recursive deep copy for nested collections
https://pub.dev/packages/deepcopy
BSD 2-Clause "Simplified" License
2 stars 2 forks source link

Support generics #2

Open ivanmem opened 2 months ago

ivanmem commented 2 months ago

I would like to see generic support added to the library. Here is an example implementation:

class ClonerService {
  static List<T> deepcopyList<T>(List<T> list) {
    List<T> copy = [];
    for (final item in list) {
      if (item is Map) {
        copy.add(deepcopyMap(item) as T);
      } else if (item is List) {
        copy.add(deepcopyList(item) as T);
      } else if (item is Set) {
        copy.add(deepcopySet(item) as T);
      } else {
        copy.add(item);
      }
    }
    return copy;
  }

  static Map<TKey, TValue> deepcopyMap<TKey, TValue>(Map<TKey, TValue> map) {
    Map<TKey, TValue> copy = {};
    for (final entry in map.entries) {
      final key = entry.key;
      final value = entry.value;

      if (value is Map) {
        copy[key] = deepcopyMap(value) as TValue;
      } else if (value is List) {
        copy[key] = deepcopyList(value) as TValue;
      } else if (value is Set) {
        copy[key] = deepcopySet(value) as TValue;
      } else {
        copy[key] = value;
      }
    }
    return copy;
  }

  static Set<T> deepcopySet<T>(Set<T> set) {
    Set<T> copy = {};
    for (final item in set) {
      if (item is Map) {
        copy.add(deepcopyMap(item) as T);
      } else if (item is List) {
        copy.add(deepcopyList(item) as T);
      } else if (item is Set) {
        copy.add(deepcopySet(item) as T);
      } else {
        copy.add(item);
      }
    }
    return copy;
  }
}

extension MapExtensions<TKey, TValue> on Map<TKey, TValue> {
  Map<TKey, TValue> deepcopy() {
    return ClonerService.deepcopyMap<TKey, TValue>(this);
  }
}

extension ListExtensions<TKey, T> on List<T> {
  List<T> deepcopy() {
    return ClonerService.deepcopyList<T>(this);
  }
}

extension SetExtensions<T> on Set<T> {
  Set<T> deepcopy() {
    return ClonerService.deepcopySet<T>(this);
  }
}

Tests:

void main() {
  group('cloner', () {
    testWidgets('Map<int, Map>', (tester) async {
      final Map<int, Map> original = {
        1: {
          'abc': {'abc': 'abc'}
        }
      };
      final copy = original.deepcopy();
      expect(original.values.first.entries.first != copy.values.first.entries.first,
          true);
    });

    testWidgets('List<Map>', (tester) async {
      final List<Map> original = [
        {
          'abc': {'abc': 'abc'}
        }
      ];
      final copy = original.deepcopy();
      expect(original.first.entries.first != copy.first.entries.first, true);
    });

    testWidgets('Set<Map>', (tester) async {
      final Set<Map> original = {
        {
          'abc': {'abc': 'abc'}
        }
      };
      final copy = original.deepcopy();
      expect(original.first.entries.first != copy.first.entries.first, true);
    });
  });
}
letyletylety commented 2 months ago

Thanks for this suggestion.

The first issue of this repo was also "support generics".

You can't see The original issue because it is deleted (I think the issuer did)

I reject that pull request because of some reasons. I cant remember all of that. But the core reason was...

  1. the lack of simplicity (dynamic is more simpler)
  2. The performance of generic API is Lower than dynamic one.

I replyed the previous one with the benchmark test (you can use that benchmark code in the branch rv/1) and detailed explanation.

Unfortunately, I'm in vacation.

So I can't review your code now.

When i return to my home, I will resolve this issue firstly.

If you show me the benchmark result, it will be easy and quick task.

You may test with my bench code in branch rv/1.

Or you can use your benchmark code.

ivanmem commented 2 months ago

I didn't change the implementation. Here only generics have been added. In theory, performance should not have changed, nor would complexity.

letyletylety commented 2 months ago

Okay, I see. I'll check it out after my vacation, just give me a few days.

letyletylety commented 2 months ago

It was a PR, not an issue, I was mistaken. you can check this #1

ivanmem commented 2 months ago

Maybe the inclusion of the isSubtype function in this PR is causing a slowdown in performance. I'm uncertain of the necessity of invoking this function since the code appears to function properly without it. It's probable that I'm overlooking some minor details.