areacache.zig 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. const std = @import("std");
  2. const areaModule = @import("area.zig");
  3. const Area = areaModule.Area;
  4. pub const AreaHashContext = struct {
  5. pub fn hash(ctx: AreaHashContext, key: Area) u64 {
  6. _ = ctx;
  7. var hasher = std.hash.Wyhash.init(0);
  8. hasher.update(std.mem.asBytes(&key.rows));
  9. hasher.update(std.mem.asBytes(&key.cols));
  10. hasher.update(key.data);
  11. return hasher.final();
  12. }
  13. pub fn eql(ctx: AreaHashContext, a: Area, b: Area) bool {
  14. _ = ctx;
  15. if (a.rows != b.rows) {
  16. return false;
  17. }
  18. if (a.cols != b.cols) {
  19. return false;
  20. }
  21. return std.mem.eql(u8, a.data, b.data);
  22. }
  23. };
  24. const AreaCacheEntry = struct {
  25. possibleShapeCounts: std.ArrayList([]i32) = std.ArrayList([]i32).empty,
  26. impossibleShapeCounts: std.ArrayList([]i32) = std.ArrayList([]i32).empty,
  27. };
  28. const AreaHashMap = std.hash_map.HashMap(Area, AreaCacheEntry, AreaHashContext,
  29. std.hash_map.default_max_load_percentage);
  30. pub const AreaCacheResult = enum {
  31. kNotFound,
  32. kPossible,
  33. kImpossible
  34. };
  35. fn matchesPossible(shapeCounts: []i32, possibleShapeCounts: [][]i32) bool {
  36. for (possibleShapeCounts) |possibleShapeCount| {
  37. var isPossible = true;
  38. for (0 .. shapeCounts.len) |i| {
  39. if (shapeCounts[i] > possibleShapeCount[i]) {
  40. isPossible = false;
  41. break;
  42. }
  43. }
  44. if (isPossible) {
  45. return true;
  46. }
  47. }
  48. return false;
  49. }
  50. fn matchesImpossible(shapeCounts: []i32, impossibleShapeCounts: [][]i32) bool {
  51. for (impossibleShapeCounts) |impossibleShapeCount| {
  52. var isImpossible = true;
  53. for (0 .. shapeCounts.len) |i| {
  54. if (shapeCounts[i] < impossibleShapeCount[i]) {
  55. isImpossible = false;
  56. break;
  57. }
  58. }
  59. if (isImpossible) {
  60. return true;
  61. }
  62. }
  63. return false;
  64. }
  65. pub const AreaCache = struct {
  66. childAllocator: std.mem.Allocator,
  67. arenaAllocator: *std.heap.ArenaAllocator,
  68. allocator: std.mem.Allocator,
  69. context: AreaHashContext,
  70. entries: AreaHashMap,
  71. hitStat: u64,
  72. totalStat: u64,
  73. pub fn init(childAllocator: std.mem.Allocator) !AreaCache {
  74. var areaCache: AreaCache = undefined;
  75. areaCache.childAllocator = childAllocator;
  76. areaCache.arenaAllocator = try childAllocator.create(std.heap.ArenaAllocator);
  77. areaCache.arenaAllocator.* = std.heap.ArenaAllocator.init(childAllocator);
  78. areaCache.allocator = areaCache.arenaAllocator.allocator();
  79. areaCache.context = .{};
  80. areaCache.entries = AreaHashMap.initContext(areaCache.allocator, areaCache.context);
  81. areaCache.hitStat = 0;
  82. areaCache.totalStat = 0;
  83. return areaCache;
  84. }
  85. pub fn deinit(self: *const AreaCache) void {
  86. self.arenaAllocator.deinit();
  87. self.childAllocator.destroy(self.arenaAllocator);
  88. }
  89. pub fn addPossibleCacheEntry(self: *AreaCache, area: *const Area, shapeCounts: []i32) !void {
  90. var result = try self.entries.getOrPut(area.*);
  91. if (!result.found_existing) {
  92. result.key_ptr.data = try self.allocator.alloc(u8, area.data.len);
  93. std.mem.copyForwards(u8, result.key_ptr.data, area.data);
  94. result.value_ptr.* = .{};
  95. }
  96. const newShapeCounts = try result.value_ptr.possibleShapeCounts.addOne(self.allocator);
  97. newShapeCounts.* = try self.allocator.alloc(i32, shapeCounts.len);
  98. std.mem.copyForwards(i32, newShapeCounts.*, shapeCounts);
  99. }
  100. pub fn addImpossibleCacheEntry(self: *AreaCache, area: *const Area, shapeCounts: []i32) !void {
  101. var result = try self.entries.getOrPut(area.*);
  102. if (!result.found_existing) {
  103. result.key_ptr.data = try self.allocator.alloc(u8, area.data.len);
  104. std.mem.copyForwards(u8, result.key_ptr.data, area.data);
  105. result.value_ptr.* = .{};
  106. }
  107. const newShapeCounts = try result.value_ptr.impossibleShapeCounts.addOne(self.allocator);
  108. newShapeCounts.* = try self.allocator.alloc(i32, shapeCounts.len);
  109. std.mem.copyForwards(i32, newShapeCounts.*, shapeCounts);
  110. }
  111. pub fn check(self: *AreaCache, area: *const Area, shapeCounts: []i32) AreaCacheResult {
  112. self.totalStat += 1;
  113. if (self.entries.get(area.*)) |cacheEntry| {
  114. if (matchesPossible(shapeCounts, cacheEntry.possibleShapeCounts.items)) {
  115. self.hitStat += 1;
  116. return AreaCacheResult.kPossible;
  117. }
  118. if (matchesImpossible(shapeCounts, cacheEntry.impossibleShapeCounts.items)) {
  119. self.hitStat += 1;
  120. return AreaCacheResult.kImpossible;
  121. }
  122. }
  123. return AreaCacheResult.kNotFound;
  124. }
  125. };