@@ -119,6 +119,84 @@ public void Dispose()
119119 }
120120}
121121
122+ /// <summary>
123+ /// A coarse cache for color distance lookups that uses a fixed-size lookup table.
124+ /// </summary>
125+ /// <remarks>
126+ /// This cache uses a fixed lookup table with 2,097,152 bins, each storing a 2-byte value,
127+ /// resulting in a worst-case memory usage of approximately 4 MB. Lookups and insertions are
128+ /// performed in constant time (O(1)) via direct table indexing. This design is optimized for
129+ /// speed while maintaining a predictable, fixed memory footprint.
130+ /// </remarks>
131+ internal unsafe struct CoarseCache : IColorIndexCache < CoarseCache >
132+ {
133+ private const int IndexRBits = 5 ;
134+ private const int IndexGBits = 5 ;
135+ private const int IndexBBits = 5 ;
136+ private const int IndexABits = 6 ;
137+ private const int IndexRCount = 1 << IndexRBits ; // 32 bins for red
138+ private const int IndexGCount = 1 << IndexGBits ; // 32 bins for green
139+ private const int IndexBCount = 1 << IndexBBits ; // 32 bins for blue
140+ private const int IndexACount = 1 << IndexABits ; // 64 bins for alpha
141+ private const int TotalBins = IndexRCount * IndexGCount * IndexBCount * IndexACount ; // 2,097,152 bins
142+
143+ private readonly IMemoryOwner < short > binsOwner ;
144+ private readonly short * binsPointer ;
145+ private MemoryHandle binsHandle ;
146+
147+ private CoarseCache ( MemoryAllocator allocator )
148+ {
149+ this . binsOwner = allocator . Allocate < short > ( TotalBins ) ;
150+ this . binsOwner . GetSpan ( ) . Fill ( - 1 ) ;
151+ this . binsHandle = this . binsOwner . Memory . Pin ( ) ;
152+ this . binsPointer = ( short * ) this . binsHandle . Pointer ;
153+ }
154+
155+ /// <inheritdoc/>
156+ public static CoarseCache Create ( MemoryAllocator allocator ) => new ( allocator ) ;
157+
158+ /// <inheritdoc/>
159+ [ MethodImpl ( InliningOptions . ShortMethod ) ]
160+ public readonly bool TryAdd ( Rgba32 color , short value )
161+ {
162+ this . binsPointer [ GetCoarseIndex ( color ) ] = value ;
163+ return true ;
164+ }
165+
166+ /// <inheritdoc/>
167+ [ MethodImpl ( InliningOptions . ShortMethod ) ]
168+ public readonly bool TryGetValue ( Rgba32 color , out short value )
169+ {
170+ value = this . binsPointer [ GetCoarseIndex ( color ) ] ;
171+ return value > - 1 ; // Coarse match found
172+ }
173+
174+ [ MethodImpl ( InliningOptions . ShortMethod ) ]
175+ private static int GetCoarseIndex ( Rgba32 color )
176+ {
177+ int rIndex = color . R >> ( 8 - IndexRBits ) ;
178+ int gIndex = color . G >> ( 8 - IndexGBits ) ;
179+ int bIndex = color . B >> ( 8 - IndexBBits ) ;
180+ int aIndex = color . A >> ( 8 - IndexABits ) ;
181+
182+ return ( aIndex * IndexRCount * IndexGCount * IndexBCount ) +
183+ ( rIndex * IndexGCount * IndexBCount ) +
184+ ( gIndex * IndexBCount ) +
185+ bIndex ;
186+ }
187+
188+ /// <inheritdoc/>
189+ public readonly void Clear ( )
190+ => this . binsOwner . GetSpan ( ) . Fill ( - 1 ) ;
191+
192+ /// <inheritdoc/>
193+ public void Dispose ( )
194+ {
195+ this . binsHandle . Dispose ( ) ;
196+ this . binsOwner . Dispose ( ) ;
197+ }
198+ }
199+
122200/// <summary>
123201/// <para>
124202/// CoarseCache is a fast, low-memory lookup structure for caching palette indices associated with RGBA values,
@@ -147,7 +225,7 @@ public void Dispose()
147225/// making it ideal for applications such as color distance caching in images with a limited palette (up to 256 entries).
148226/// </para>
149227/// </summary>
150- internal unsafe struct CoarseCache : IColorIndexCache < CoarseCache >
228+ internal unsafe struct CoarseCacheLite : IColorIndexCache < CoarseCacheLite >
151229{
152230 // Use 5 bits per channel for R, G, and B: 32 levels each.
153231 // Total buckets = 32^3 = 32768.
@@ -158,15 +236,15 @@ internal unsafe struct CoarseCache : IColorIndexCache<CoarseCache>
158236 private readonly AlphaBucket * buckets ;
159237 private MemoryHandle bucketHandle ;
160238
161- private CoarseCache ( MemoryAllocator allocator )
239+ private CoarseCacheLite ( MemoryAllocator allocator )
162240 {
163241 this . bucketsOwner = allocator . Allocate < AlphaBucket > ( BucketCount , AllocationOptions . Clean ) ;
164242 this . bucketHandle = this . bucketsOwner . Memory . Pin ( ) ;
165243 this . buckets = ( AlphaBucket * ) this . bucketHandle . Pointer ;
166244 }
167245
168246 /// <inheritdoc/>
169- public static CoarseCache Create ( MemoryAllocator allocator ) => new ( allocator ) ;
247+ public static CoarseCacheLite Create ( MemoryAllocator allocator ) => new ( allocator ) ;
170248
171249 /// <inheritdoc/>
172250 public readonly bool TryAdd ( Rgba32 color , short paletteIndex )
0 commit comments