1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
const std = @import("std");
const memora = @import("memora");
const Storage = memora.Storage;
pub const Image = @import("image.zig");
const Self = @This();
pub const empty: Self = .{};
const Timestamp = struct {
index: usize,
node: std.DoublyLinkedList.Node,
pub fn next(self: *Timestamp) ?*Timestamp {
return @fieldParentPtr("node", self.node.next orelse return null);
}
pub fn prev(self: *Timestamp) ?*Timestamp {
return @fieldParentPtr("node", self.node.prev orelse return null);
}
};
items: std.ArrayList(Image) = .empty,
rw_lock: std.Thread.RwLock = .{},
timestamp_order: std.DoublyLinkedList = .{},
pub fn init(
self: *Self,
storage: *Storage,
) !void {
var dir = storage.dir.openDir("image", .{ .iterate = true }) catch blk: {
try storage.dir.makeDir("image");
break :blk try storage.dir.openDir("image", .{ .iterate = true });
};
defer dir.close();
var iterator = dir.iterate();
errdefer self.items.deinit(storage.allocator);
while (try iterator.next()) |entry| {
if (entry.kind == .file and std.mem.endsWith(u8, entry.name, ".jpg")) {
try self.add(
storage.allocator,
try .init(storage, entry.name[0..entry.name.len - 4])
);
}
}
}
pub fn add(self: *Self, allocator: std.mem.Allocator, image: Image) !void {
self.rw_lock.lock();
defer self.rw_lock.unlock();
try self.items.append(
allocator,
image,
);
var current = self.timestamp_order.first;
while (current) |c| {
const index = @as(*Timestamp, @fieldParentPtr("node", c)).index;
if (image.timestamp orelse 0 > self.items.items[index].timestamp orelse 0) {
const timestamp = try allocator.create(Timestamp);
timestamp.index = self.items.items.len - 1;
self.timestamp_order.insertBefore(c, ×tamp.node);
return;
}
current = c.next;
}
const timestamp = try allocator.create(Timestamp);
timestamp.index = self.items.items.len - 1;
self.timestamp_order.append(×tamp.node);
return;
}
pub fn save(
self: *Self,
storage: *Storage,
reader: *std.Io.Reader,
size: usize,
) !void {
return self.add(storage.allocator, try Image.new(storage, reader, size));
}
pub fn list(self: *Self) memora.locked.Shared([]Image) {
self.rw_lock.lockShared();
return .{
.value = self.items.items,
.rw_lock = &self.rw_lock,
};
}
pub fn first_by_timestamp(self: *Self) memora.locked.Shared(?*Timestamp) {
self.rw_lock.lockShared();
return .{
.value = if (self.timestamp_order.first) |first| @fieldParentPtr("node", first)
else null,
.rw_lock = &self.rw_lock,
};
}
|