Manualmente
Si la memoria no es un recurso muy escaso, considero trabajar en fragmentos más grandes.
Aquí hay un pseudocódigo.
class Chunk {
Chunk new(int size) {...}
void setPixel(int x, int y, int value) {...}
int getPixel(int x, int y) {...}
}
class Grid {
Map<int, Map<Chunk>> chunks;
Grid new(int chunkSize) {...}
void setPixel(int x, int y, int value) {
getChunk(x,y).setPixel(x % chunkSize, y % chunkSize, value);//actually the modulo could be right in Chunk::setPixel and getPixel for more safety
}
int getPixel(int x, int y) { /*along the lines of setPixel*/ }
private Chunk getChunk(int x, int y) {
x /= chunkSize;
y /= chunkSize;
Map<Chunk> row = chunks.get(y);
if (row == null) chunks.set(y, row = new Map<Chunk>());
Chunk ret = row.get(x);
if (ret == null) row.set(x, ret = new Chunk(chunkSize));
return ret;
}
}
Esta implementación es bastante ingenua.
Por un lado, crea fragmentos en getPixel (básicamente estaría bien simplemente devolver 0 más o menos, si no se definieron fragmentos para esa posición). En segundo lugar, se basa en el supuesto de que tiene una implementación de Map lo suficientemente rápida y escalable. Que yo sepa, cada idioma decente tiene uno.
También tendrás que jugar con el tamaño del fragmento. Para mapas de bits densos, un tamaño de fragmento grande es bueno, para mapas de bits dispersos es mejor un tamaño de fragmento más pequeño. De hecho, para los muy dispersos, un "tamaño de fragmento" de 1 es el mejor, ya que los "fragmentos" quedan obsoletos y reducen la estructura de datos a un mapa int de un mapa int de píxeles.
Fuera de la plataforma
Otra solución podría ser mirar algunas bibliotecas de gráficos. En realidad, son bastante buenos para dibujar un búfer 2D en otro. Eso significaría que simplemente asignaría un búfer más grande y dibujaría el original en las coordenadas correspondientes.
Como estrategia general: cuando se tiene un "bloque de memoria en crecimiento dinámico", es una buena idea asignar un múltiplo de él, una vez que se agota. Esto es bastante intenso en memoria, pero reduce significativamente los costos de asignación y copia . La mayoría de las implementaciones de vectores asignan el doble de su tamaño, cuando se supera. Por lo tanto, especialmente si opta por la solución estándar, no extienda su búfer solo 1 píxel, porque solo se solicitó un píxel. La memoria asignada es barata. Reasignar, copiar y liberar es costoso.