From 4c06eb64cbed3562e428ce59857d1763098638f3 Mon Sep 17 00:00:00 2001 From: Nathan Reiner Date: Wed, 19 Nov 2025 09:15:49 +0100 Subject: allow images to upload and sort if according to their datetime --- src/storage/image-manager/root.zig | 79 +++++++++++++++++++++++++++++--------- 1 file changed, 60 insertions(+), 19 deletions(-) (limited to 'src/storage/image-manager/root.zig') diff --git a/src/storage/image-manager/root.zig b/src/storage/image-manager/root.zig index 7742df2..7fa1607 100644 --- a/src/storage/image-manager/root.zig +++ b/src/storage/image-manager/root.zig @@ -1,24 +1,30 @@ const std = @import("std"); -const Storage = @import("../root.zig"); +const memora = @import("memora"); +const Storage = memora.Storage; pub const Image = @import("image.zig"); const Self = @This(); pub const empty: Self = .{}; -items: std.ArrayList(Image) = .empty, -rw_lock: std.Thread.RwLock = .{}, +const Timestamp = struct { + index: usize, + node: std.DoublyLinkedList.Node, -pub const LockedImages = struct { - images: []Image, - rw_lock: *std.Thread.RwLock, + pub fn next(self: *Timestamp) ?*Timestamp { + return @fieldParentPtr("node", self.node.next orelse return null); + } - pub fn deinit(self: *const @This()) void { - self.rw_lock.unlockShared(); + 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, @@ -35,32 +41,67 @@ pub fn init( while (try iterator.next()) |entry| { if (entry.kind == .file and std.mem.endsWith(u8, entry.name, ".jpg")) { - try self.items.append( + try self.add( storage.allocator, - try .init(storage.allocator, entry.name[0..entry.name.len - 4]) + try .init(storage, entry.name[0..entry.name.len - 4]) ); } } } -pub fn add( +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; + + if (current == null) { + const timestamp = try allocator.create(Timestamp); + timestamp.index = self.items.items.len - 1; + self.timestamp_order.append(×tamp.node); + return; + } + + 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); + break; + } + + current = c.next; + } +} + +pub fn save( self: *Self, storage: *Storage, reader: *std.Io.Reader, size: usize, ) !void { - self.rw_lock.lock(); - defer self.rw_lock.unlock(); + return self.add(storage.allocator, try Image.new(storage, reader, size)); +} - try self.items.append( - 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 list(self: *Self) LockedImages { +pub fn first_by_timestamp(self: *Self) memora.locked.Shared(?*Timestamp) { + self.rw_lock.lockShared(); return .{ - .images = self.items.items, + .value = if (self.timestamp_order.first) |first| @fieldParentPtr("node", first) + else null, .rw_lock = &self.rw_lock, }; } -- cgit v1.2.3-70-g09d2