Cog/Utils/RedundantPlaylistDataStore.m
Christopher Snowhill da4630f4c5 Add a metadata loader cache
Promote the Plugin Controller source file to Objective-C++, and add a
simple data cache that holds on to requests for up to 5 seconds after
their last access, for preventing spammed requests from hitting files
over and over. This is apparently really relevant to the CUESheet reader
and its embedded CUESheet handling, as that tends to reread the same
file over and over as it populates the playlist with tracks. The nested
reader can also lead to repeated reading even on files without CUESheets
embedded.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-26 23:24:32 -08:00

77 lines
1.8 KiB
Objective-C

//
// RedundantPlaylistDataStore.m
// Cog
//
// Created by Christopher Snowhill on 2/16/22.
//
// Coalesce an entryInfo dictionary from tag loading into a common data dictionary, to
// reduce the memory footprint of adding a lot of tracks to the playlist.
#import "RedundantPlaylistDataStore.h"
#import "SHA256Digest.h"
@implementation RedundantPlaylistDataStore
- (id)init {
self = [super init];
if(self) {
stringStore = [[NSMutableArray alloc] init];
artStore = [[NSMutableDictionary alloc] init];
}
return self;
}
- (NSString *)coalesceString:(NSString *)in {
if(in == nil) return in;
NSUInteger index = [stringStore indexOfObject:in];
if(index == NSNotFound) {
[stringStore addObject:in];
return in;
} else {
return [stringStore objectAtIndex:index];
}
}
- (NSData *)coalesceArt:(NSData *)in {
if(in == nil) return in;
NSString *key = [SHA256Digest digestDataAsString:in];
NSData *ret = [artStore objectForKey:key];
if(ret == nil) {
[artStore setObject:in forKey:key];
return in;
} else {
return ret;
}
}
- (NSDictionary *)coalesceEntryInfo:(NSDictionary *)entryInfo {
__block NSMutableDictionary *ret = [[NSMutableDictionary alloc] initWithCapacity:[entryInfo count]];
[entryInfo enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL *_Nonnull stop) {
if([obj isKindOfClass:[NSString class]]) {
NSString *stringObj = (NSString *)obj;
[ret setObject:[self coalesceString:stringObj] forKey:key];
} else if([obj isKindOfClass:[NSData class]]) {
NSData *dataObj = (NSData *)obj;
[ret setObject:[self coalesceArt:dataObj] forKey:key];
} else {
[ret setObject:obj forKey:key];
}
}];
return [NSDictionary dictionaryWithDictionary:ret];
}
- (void)reset {
[stringStore removeAllObjects];
[artStore removeAllObjects];
}
@end