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 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
|
// This file is part of Golly.
// See docs/License.html for the copyright notice.
/**
* This is the fast "conventional" life algorithm code.
*/
#ifndef QLIFEALGO_H
#define QLIFEALGO_H
#include "lifealgo.h"
#include "liferules.h"
#include <vector>
/*
* The smallest unit of the universe is the `slice', which is a
* 4 (horizontal) by 8 (vertical) chunk of the world. Each slice
* is stored in a 32-bit word. The most significant bit of the
* word is the upper left bit; the remaining bits go across
* horizontally then down vertically.
*
* We always recompute in units of a slice. This is smaller than the
* 8x8 in some programs, and in this particular case adds to the
* efficiency.
*
* This arrangment of bits was selected to minimize the bit
* twiddling needed for lookup; in general, we use a lookup table
* that takes a 4x4 current-generation and figures out the values
* of the inner 2x2 cells.
*
* A `brick' is composed of eight slices for the even generation and
* eight slices for the odd generation. This is a total of 16
* 32-bit words. The slices are concatenated horizontally so each
* brick contains two generations of a 32x8 section of the universe.
*
* No other data is stored directly into the bricks; various flags are
* stored in the next level up. We try and minimize the size of the
* data for a given universe so that we can minimize the number of
* data cache misses and TLB misses. For almost all universes, the
* bulk of the allocated data is in these 64-byte bricks.
*
* We use a stagger-step type algorithm to minimize the number of
* neighbors that need to be examined (thanks, Alan!) for each slice.
* Thus, a brick that holds (0,0)-(31,7) for the even generation would
* hold (1,1)-(32,8) in the odd generations.
*/
struct brick { /* 64 bytes */
unsigned int d[16] ;
} ;
/*
* A tile contains the flags for four bricks, and pointers to the bricks
* themselves. These pointers are never null; if the portion of the
* universe is completely empty, they point to a unique allocated
* `emptybrick'. This means that we do not need to check if the pointers
* are null; we can simply always dereference and get valid data. Thus,
* each tile corresponds to a 32x32 section of the universe.
*
* The c flags indicate that, in the previous computation,
* the data was found to change in some slice or
* subslice. The least significant bit in each c01 flag corresponds
* to the last (8th) slice for phase 0->1, and to the first slice for
* phase 1->0.
*
* There are ten valid bits in c flags 1-4, one for each slice,
* one most significant one that indicates that the rightmost (leftmost)
* two columns of the first (eighth) slice changed in phase 0->1 (1->0)
* (and thus, the next brick to the left (right) needs to be recomputed).
* The tenth bit is just the ninth bit from the previous generation.
*
* For c flags 0 and 5, we only have the first nine bits as above.
*
* We need six flags; four for the slices themselves, and one indicating
* that the top two rows of a particular slice has changed, and thus
* the next brick up needs to be recomputed, and one indicating that the
* bottom two rows of a particular slice has changed.
*
* In all cases, tiles only contain data about what has happened completely
* within their borders; indicating that the next slice over needs to be
* recomputed is handled by always inspecting the neighboring slices
* *before* a recomputation.
*
* The flags int is divided into two 12-bit fields, each holding a population
* count, and one eight-bit field, holding dirty flags.
*
* Note that tiles only point `down' to bricks, never to each other or to
* higher-level supertiles.
*
* Tiles are numbered as level `0' of the universe tree.
*
* The tiles are 32 bytes each; they can hold up to four bricks, so the
* memory consumption of the tiles tends to be small.
*/
struct tile { /* 32 bytes */
struct brick *b[4] ;
short c[6] ;
int flags ;
} ;
/*
* Supertiles hold pointers to eight subtiles, which can either be
* tiles or supertiles themselves. Supertiles are numbered as levels `1' on
* up of the universe tree.
*
* Odd levels stack their subtiles horizontally; even levels stack their
* subtiles vertically. Thus, each supertile at level 1 corresponds to
* a 256x32 section of the universe. Each supertile at level 2 corresponds
* to a 256x256 section of the universe. And so on.
*
* Levels are never skipped (that is, each pointer in a supertile at
* level `n' points to a valid supertile or tile at level `n-1').
*
* The c flag indicates that changes have happened in the subtiles.
* The least significant eight bits indicate that changes have occurred
* anywhere in the subtile; the least significant bit (bit 0) is associated
* with the first subtile for phase 0->1 and the eighth subtile for phase
* 1->0, and bit 7 is associated with other. Bit number 8 indicates that
* some bits on the right (left) edge of the eighth (first) subtile have
* changed for phase 0->1 (1->0). Bits numbered 9 through 16 indicate that
* bits on the bottom (top) of the corresponding subtile have changed, and
* bit number 17 indicates that a bit in the lower right (upper left) corner
* of the eighth (first) subtile has changed.
*
* Bit 18 through 27 correspond to the previous generation's bits 8 through
* 17. Bits 28 through 31 are the dirty bits; we currently use three of
* them.
*
* The above description corresponds to odd levels. For even levels,
* since tiles are stacked vertically instead of horizontally, change
* `lower' to `right' and `right' to `lower'.
*
* The dirty flags again are used to indicate that this tile needed to
* be recomputed since the last time the dirty bit was cleared.
*
* The two pop values hold a population count, if the appropriate dirty
* bit is clear. These counts will never hold values greater than
* 500M, so that a sum of the eight in unsigned arithmetic is guaranteed
* to never overflow.
*
* This completes the universe data structures. Note that there is no
* limit (other than the size of a pointer and memory constraints) on
* the size of the universe. For instance, using these data structures
* we can easily build a universe with elements separated by 2^200
* pixels.
*
* The supertiles are 44 bytes each; they correspond to at least a
* 256x32 chunk of the universe, so the total memory consumption due to
* supertiles tends to be small.
*/
struct supertile { /* 44 bytes */
struct supertile *d[8] ;
int flags ;
int pop[2] ;
} ;
/*
* This is a common header for chunks of memory linked together.
*/
struct linkedmem {
struct linkedmem *next ;
} ;
/*
* This structure contains all of our variables that pertain to a
* particular universe. (Thus, we support multiple universes.)
*
* The minx, miny, maxx, and maxy values describe the borders of
* the universe dictated by the level of the root supertile. If
* ever during computation these bounds are found to be too tight,
* another supertile is added on top of the root, expanding these
* bounds.
*
* These bounds currently limit the size of the universe to 2^32 in
* each direction; however, they are only used during the set call
* (when initially setting up the universe). Changing them to
* doubles or 64-bit ints will relax this limitation. For now we
* leave them as is.
*
* The rootlev variable contains the supertile level of the root node.
*
* The tilelist, supertilelist, and bricklist are freelists for the
* appropriate type of structure.
*
* The memused is a linked list of all memory blocks allocated; this
* enables us to free the universe and all of its memory without actually
* walking the entire life tree.
*
* The emptybrick pointer points to the unique brick that is guaranteed
* to always be empty. The emptytile pointer is similar.
*
* Finally, root is the top of the current life tree. Nullroot is the
* topmost empty supertile allocated, and nullroots[] holds the empty
* supertiles at each level. Setting this to 40 limits the number of
* levels to 40, which is sufficient for a 2^65x2^62 universe.
*/
class qlifealgo : public lifealgo {
public:
qlifealgo() ;
virtual ~qlifealgo() ;
virtual void clearall() ;
virtual int setcell(int x, int y, int newstate) ;
virtual int getcell(int x, int y) ;
virtual int nextcell(int x, int y, int &v) ;
// call after setcell/clearcell calls
virtual void endofpattern() {
// AKT: unnecessary (and prevents shrinking selection while generating)
// poller->bailIfCalculating() ;
popValid = 0 ;
}
virtual void setIncrement(bigint inc) { increment = inc ; }
virtual void setIncrement(int inc) { increment = inc ; }
virtual void setGeneration(bigint gen) { generation = gen ; }
virtual const bigint &getPopulation() ;
virtual int isEmpty() ;
// can we do the gen count doubling? only hashlife
virtual int hyperCapable() { return 0 ; }
virtual void setMaxMemory(int m) ;
virtual int getMaxMemory() { return (int)(maxmemory >> 20) ; }
virtual const char *setrule(const char *s) ;
virtual const char *getrule() { return qliferules.getrule() ; }
virtual void step() ;
virtual void* getcurrentstate() { return 0 ; }
virtual void setcurrentstate(void *) {}
virtual void draw(viewport &view, liferender &renderer) ;
virtual void fit(viewport &view, int force) ;
virtual void lowerRightPixel(bigint &x, bigint &y, int mag) ;
virtual void findedges(bigint *t, bigint *l, bigint *b, bigint *r) ;
virtual const char *writeNativeFormat(std::ostream &, char *) {
return "No native format for qlifealgo yet." ;
}
static void doInitializeAlgoInfo(staticAlgoInfo &) ;
private:
linkedmem *filllist(int size) ;
brick *newbrick() ;
tile *newtile() ;
supertile *newsupertile(int lev) ;
void uproot() ;
int doquad01(supertile *zis, supertile *edge,
supertile *par, supertile *cor, int lev) ;
int doquad10(supertile *zis, supertile *edge,
supertile *par, supertile *cor, int lev) ;
int p01(tile *p, tile *pr, tile *pd, tile *prd) ;
int p10(tile *plu, tile *pu, tile *pl, tile *p) ;
G_INT64 find_set_bits(supertile *p, int lev, int gm1) ;
int isEmpty(supertile *p, int lev, int gm1) ;
supertile *mdelete(supertile *p, int lev) ;
G_INT64 popcount() ;
int uproot_needed() ;
void dogen() ;
void renderbm(int x, int y) ;
void renderbm(int x, int y, int xsize, int ysize) ;
void BlitCells(supertile *p, int xoff, int yoff, int wd, int ht, int lev) ;
void ShrinkCells(supertile *p, int xoff, int yoff, int wd, int ht, int lev) ;
int nextcell(int x, int y, supertile *n, int lev) ;
void fill_ll(int d) ;
int lowsub(vector<supertile*> &src, vector<supertile*> &dst, int lev) ;
int highsub(vector<supertile*> &src, vector<supertile*> &dst, int lev) ;
void allsub(vector<supertile*> &src, vector<supertile*> &dst, int lev) ;
int gethbitsfromleaves(vector<supertile *> v) ;
int getvbitsfromleaves(vector<supertile *> v) ;
supertile *markglobalchange(supertile *, int, int &) ;
void markglobalchange() ; // call if the rule changes
/* data elements */
int min, max, rootlev ;
int minlow32 ;
bigint bmin, bmax ;
bigint population ;
int popValid ;
linkedmem *tilelist, *supertilelist, *bricklist ;
linkedmem *memused ;
brick *emptybrick ;
tile *emptytile ;
supertile *root, *nullroot, *nullroots[40] ;
int cleandowncounter ;
g_uintptr_t maxmemory, usedmemory ;
char *ruletable ;
// when drawing, these are used
liferender *renderer ;
viewport *view ;
int uviewh, uvieww, viewh, vieww, mag, pmag, kadd ;
int oddgen ;
int bmleft, bmtop, bmlev, shbmsize, logshbmsize ;
int quickb, deltaforward ;
int llbits, llsize ;
char *llxb, *llyb ;
liferules qliferules ;
} ;
#endif
|