moved henge.h to ston.h
[henge/apc.git] / src / binaryout.c
index 39ece40..ad9c5cd 100644 (file)
 #include "../stb/stb_image.h"
 #define STB_IMAGE_WRITE_IMPLEMENTATION
 #include "../stb/stb_image_write.h"
+#include "../ston/ston.h"
 
 /* Public */
 void ir_binout_init(struct ir_class_t*);
-
+/* Private */
+static
+long file_ht_insert(long,int,int,int,uint32_t*,uint32_t,uint32_t);
 /* Memory Allocation */
 #define  struct_alloc(_T) ((struct _T*) stack_alloc(&datapages, sizeof(struct _T)))
 static
@@ -46,11 +49,11 @@ struct bin_ht_header_t {
   int entries;
   int size;
 };
-struct bin_default_ht_entry_t {
+struct bin_ht_entry_t {
   uint32_t key; 
   long value;
 };
-struct bin_var_ht_entry_t {
+struct bin_variant_ht_entry_t {
   uint32_t key;
   long vvalue;
   long mvalue;
@@ -81,7 +84,7 @@ struct bin_frame_header_t {
 };
 
 struct bin_pixel_t {
-  int x, y, z, num; //the x matching pixel 
+  int x, y, z;
   uint32_t ref;
   int attach_idx;
 };
@@ -121,13 +124,23 @@ struct bin_processed_links_t
   struct bin_linklist_t* dlink_list;
   int                    dlink_len;
 };
+struct bin_pixel_ht_entry_t
+{ uint16_t key;
+  uint16_t value;
+};
 
+struct bin_pixel_ht_t
+{ struct bin_pixel_ht_t* next;
+  struct bin_pixel_ht_entry_t* hash_entries;
+};
+
+static
 struct bin_attachment_list_t **attachment_stack, **asp; //attachment_stack, attachment_stack_pointer
+static
 FILE* binaryout;
 
-
 #define  NAMEHASH(name, domain) (XXH32(name, u8_strlen(name), 0XCEED ) & domain) 
-
+#define  REFHASH(ref, domain) (XXH32(&ref, sizeof(uint32_t), 0xCEED) & domain)
 static inline
 int bin_set_varcount
 ( ir_set set )
@@ -161,20 +174,6 @@ int bin_set_sibcount
   return count;
 }
 
-/* Given a position and a size, checks if the bytes are null and returns
-   the file position to where it started. 1 if not null, 0 if null*/
-/* TODO: Determine why fseeking file past end sets bytes to -1, and not 0 */
-static inline
-int bytes_null( int len, int pos )
-{ while(len--)
-    { if(fgetc(binaryout) > 0)
-       { fseek(binaryout, pos, SEEK_SET);        
-          return 1;
-       }
-    }
-  fseek(binaryout, pos, SEEK_SET);
-  return 0;
-}
 /* Checks if the key at entrypos is the same as the parameter key. Returns
    1 if so, 0 if not. */
 static inline
@@ -205,95 +204,128 @@ ir_binout_init(ir_class root_class)
   bin_traverse_class(root_class);
 }
 
-
+/* INSERT INTO HASH TABLE */
 /* Returns the key position where the hash table entry was inserted. */
-#define ENTRY_OCCUPIED() (bytes_null(uint32_t), entry_pos))
-#define LOOP_ENTRY(_HTSTART) (entry_pos = _HTSTART)
-#define WRITE_DEF_ENTRY() do {                                         \
-    if(fseek(binaryout, entry_pos, SEEK_SET) == -1) wprintf("fseek failed with %s", strerror(errno)); \
-    fwrite(&def_ht_entry, sizeof def_ht_entry, 1, binaryout);          \
+#define SEEK_TO(_FPOS) do {                                            \
+    errno = 0;                                                         \
+    if (fseek(binaryout, _FPOS, SEEK_SET))                             \
+      eprintf("Failed to seek to position %l: %s\n", _FPOS, strerror(errno)); \
   } while (0)
-#define INC_DEF_ENTRY() do { \
-    entry_pos += sizeof(def_ht_entry);                                 \
-    if(fseek(binaryout, entry_pos, SEEK_SET) == -1) eprintf("fseek failed with %s", strerror(errno)); \
+#define SEEK_REL(_FPOS) do {                                           \
+    errno = 0;                                                         \
+    if (fseek(binaryout, _FPOS, SEEK_CUR))                             \
+      eprintf("Failed to seek to position %l: %s\n", _FPOS, strerror(errno)); \
+  } while (0)
+#define READ_DATA_AND_INCREMENT(_DATA,_SIZE) do {              \
+    errno = 0;                                                 \
+    if (fread(_DATA, _SIZE, 1, binaryout) != 1)                        \
+      eprintf("Failed to read data at file position %l: %s\n", \
+             ftell(binaryout),                                 \
+             strerror(errno));                                 \
+  } while (0)
+#define READ_DATA(_DATA,_SIZE) do {            \
+  READ_DATA_AND_INCREMENT(_DATA,_SIZE);                \
+  SEEK_REL(-_SIZE);                            \
+  } while (0)
+#define WRITE_DATA_AND_INCREMENT(_DATA,_SIZE) do {                     \
+  errno = 0;                                                           \
+  if (fwrite(_DATA, _SIZE, 1, binaryout) != 1)                         \
+    eprintf("Failed to write data to file at position %l: %s\n",       \
+           ftell(binaryout),                                           \
+           strerror(errno));                                           \
+  } while (0)
+#define WRITE_DATA(_DATA,_SIZE) do {           \
+    WRITE_DATA_AND_INCREMENT(_DATA,_SIZE);     \
+    SEEK_REL(-_SIZE);                          \
   } while (0)
-#define HT_END(_HTEND) (entry_pos >= _HTEND) //just in case at last entry
-long
-bin_insert_default_ht_entry
-( long ht_start,
-  int ht_size,
-  struct bin_def_ht_entry_t* def_ht_entry,
-  int overwrite
-)
-{ long entry_pos, ht_end;
 
-  ht_end = ht_start + ht_size; 
-  entry_pos = ht_start + sizeof(ht_entry) * ht_entry->key;
-  fseek(binaryout, entry_pos, SEEK_SET);
-  
-  if (!ENTRY_OCCUPIED())
-    { uprintf("key not occupied\n");
-      WRITE_DEF_ENTRY();
+/* Insert a value into an arbitrary hash table in-file */
+static
+long file_ht_insert
+( long      ht_start,
+  int       ht_row_values,
+  int       ht_which_value,
+  int       ht_rows,
+  uint32_t* overwrite,
+  uint32_t  key,
+  uint32_t  value
+)
+{ uint32_t entry[ht_row_values];
+# define   ENTRY_VAL(N) entry[N]
+# define   ENTRY_KEY    ENTRY_VAL(0)
+  uint8_t  looped = 0;
+  size_t   entry_row = key & (ht_rows - 1);
+  int      i;
+  long     writepos, startpos;
+  startpos = ftell(binaryout);
+ next_entry:
+  SEEK_TO(ht_start + (entry_row * sizeof(entry)));
+  READ_DATA(entry, sizeof(uint32_t) * ht_row_values);
+  for (i = 0; i < ht_row_values; i++)
+    if (entry[i] != 0)
+      goto populated;
+ write_position:
+  SEEK_REL(sizeof(uint32_t) * ht_which_value);
+  WRITE_DATA(entry + ht_which_value, sizeof(*entry));
+  writepos = ftell(binaryout);
+  SEEK_TO(startpos);
+  return writepos;
+ populated:
+  if (ENTRY_KEY == key)
+    { if (overwrite != NULL)
+       *overwrite = ENTRY_VAL(ht_which_value);
+      ENTRY_VAL(ht_which_value) = value;
+      goto write_position;
     }
-  while( ENTRY_OCCUPIED() )
-    { if(overwrite)
-       { if(bin_keys_identical(entry_pos, ht_entry->key))
-           break;      
-         else 
-          { eprintf("error in hashtable insertion, keys are identical");
-          }
-       }
-      if (HT_END(ht_end))
-       LOOP_ENTRY(ht_start);
-      else 
-       INC_DEF_ENTRY();
+  if (entry_row < ht_rows)
+    entry_row++;
+  else if (looped)
+    eprintf("cannot insert into filled hashtable\n");
+  else
+    { looped++;
+      entry_row = 0;
     }
-  WRITE_DEF_ENTRY();
-
-  return entry_pos;
-    
+  goto next_entry;
 }
-long
-#define WRITE_VAR_ENTRY() do { \
-   if(fseek(binaryout, entry_pos, SEEK_SET) == -1) wprintf("fseek failed with %s", strerror(errno)); \
-   fwrite(&var_ht_entry, sizeof var_ht_entry, 1, binaryout);   \
-} while (0)
-#define INC_VAR_ENTRY() do { \
-    entry_pos += sizeof(var_ht_entry);                                 \
-    if(fseek(binaryout, entry_pos, SEEK_SET) == -1) eprintf("fseek failed with %s", strerror(errno)); \
-  } while (0)
-bin_insert_var_ht_entry
-( long ht_start,
-  int ht_size,
-  struct bin_var_ht_entry_t* var_ht_entry,
-  int overwrite
-)
-{ long entry_pos, ht_end;
 
-  ht_end = ht_start + ht_size; 
-  entry_pos = ht_start + sizeof(var_ht_entry) * ht_entry->key;
-  fseek(binaryout, entry_pos, SEEK_SET);
-  
-  if (!ENTRY_OCCUPIED())
-    { uprintf("key not occupied\n");
-      WRITE_VAR_ENTRY();
+static
+uint32_t* mem_ht_insert
+( void*     ht_start,
+  int       ht_row_values,
+  int       ht_which_value,
+  int       ht_rows,
+  uint32_t* overwrite,
+  uint32_t  key,
+  uint32_t  value
+)
+{ uint32_t* entry;
+  uint8_t   looped = 0;
+  size_t    entry_row = key & (ht_rows - 1);
+  int       i;
+ next_entry:
+  entry = (uint32_t*)ht_start + (ht_row_values * entry_row);
+  for (i = 0; i < ht_row_values; i++)
+    if (entry[i] != 0)
+      goto populated;
+ write_position:
+  entry[ht_which_value] = value;
+  return &entry[ht_which_value];
+ populated:
+  if (ENTRY_KEY == key)
+    { if (overwrite != NULL)
+       *overwrite = ENTRY_VAL(ht_which_value);
+      goto write_position;
     }
-  while( ENTRY_OCCUPIED() )
-    { if(overwrite)
-       { if(bin_keys_identical(entry_pos, ht_entry->key))
-           break;      
-         else 
-          { eprintf("error in hashtable insertion, keys are identical");
-          }
-       }
-      if (HT_END(ht_end))
-       LOOP_ENTRY(ht_start);
-      else 
-       INC_VAR_ENTRY();
+  if (entry_row < ht_rows)
+    entry_row++;
+  else if (looped)
+    eprintf("cannot insert into filled hashtable\n");
+  else
+    { looped++;
+      entry_row = 0;
     }
-  WRITE_VAR_ENTRY();
-
-  return entry_pos;
+  goto next_entry;
+}
 
 /** @see http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 */
 static inline
@@ -337,19 +369,20 @@ bin_traverse_class
 { ir_class citer;
   ir_set siter;
   struct bin_class_header_t class_header;
-  struct bin_def_ht_entry_t ht_entry;
   long class_start, classht_start, classht_size, rootsetht_start, rootsetht_size;
   int num_class_entries, num_rootset_entries;
   uint8_t* class_name;
 
+  class_header.namelen = u8_strlen(class_name);
+  
+
   class_start = ftell(binaryout);
   class_name = ir_class_name(class);
 
   num_class_entries = bin_calculate_ht_entries(bin_class_sibcount(class));
-  num_rootset_entries = bin_calculate_ht_entries(ir_class_rootset(class));
+  num_rootset_entries = bin_calculate_ht_entries(bin_set_sibcount(ir_class_rootset(class)));
 
   /* alloc space (before hash tables) for class header */
-  class_header.namelen = u8_strlen(class_name);
   fseek(binaryout, class_start + sizeof(class_header) + class_header.namelen ,SEEK_SET);
   
   DEF_HT_INIT(classht_start, classht_size, num_class_entries);
@@ -370,9 +403,11 @@ bin_traverse_class
   /* Start populating root_set hash table */
   for ( siter = ir_class_rootset(class); siter != NULL; siter = ir_set_nextsib(siter))
     { fseek(binaryout, 0, SEEK_END);
-      ht_entry.key = NAMEHASH(ir_set_name(siter), num_rootset_entries);
-      ht_entry.value = bin_traverse_set(siter);
-      bin_insert_def_ht_entry(rootsetht_start, rootsetht_size, &ht_entry, 0);      
+      file_ht_insert(rootsetht_start, 2, 1,
+                    rootsetht_size,
+                    &old_value,
+                    NAMEHASH(ir_set_name(siter), num_rootset_entries),
+                    bin_traverse_set(siter));
     }
 
   /* Start populating class child hash table */
@@ -380,9 +415,11 @@ bin_traverse_class
     { if(chdir((char*) class_name))
        eprintf("CHDIR %U from %s\n",(char*) class_name,getcwd(NULL,255));
       fseek(binaryout, 0, SEEK_END);
-      ht_entry.key = NAMEHASH(ir_class_name(citer), num_class_entries);     
-      ht_entry.value = bin_traverse_class(citer);
-      bin_insert_def_ht_entry(classht_start, classht_size, &ht_entry, 0);
+      file_ht_insert(classht_start, 2, 1,
+                    classht_size,
+                    &old_value,
+                    NAMEHASH(ir_class_name(citer), num_class_entries),
+                    bin_traverse_class(citer));
       if (chdir(".."))
        eprintf("CHDIR ..\n");
     }
@@ -439,7 +476,7 @@ bin_traverse_set
     { fseek(binaryout, 0, SEEK_END);
       ht_entry.key = NAMEHASH(ir_set_name(iter), num_entries);
       ht_entry.value = bin_traverse_set(iter);
-      bin_insert_def_ht_entry(childht_start, childht_size, &ht_entry, 0);      
+      bin_insert_ht_entry(childht_start, childht_size, &ht_entry, 0);      
     }
   
 
@@ -785,6 +822,23 @@ bin_process_framebox
   
   return framebox_start;
 }
+static inline
+struct bin_pixel_ht_t* bin_pixel_ht_alloc
+()
+{ struct bin_pixel_ht_t* htp;
+  if(!(htp = (struct bin_pixel_ht_t*) malloc(sizeof(bin_pixel_ht_t) + )))
+     eprintf("error mallocing pixel_ht\n");
+
+       return htp;
+}
+int bin_insert_pixel_ht_entry
+( struct bin_pixel_ht_t* ht,
+  struct bin_pixel_ht_entry_t* ht_entry
+)
+{ 
+
+}
+
 void
 bin_process_frameboxes
 ( ir_set set,
@@ -792,12 +846,26 @@ bin_process_frameboxes
   struct bin_pixel_node_t* default_pixel_list
 )
 { struct bin_ht_entry_t ht_entry;
+  struct bin_pixel_ht_t* ht;
+  struct bin_pixel_node_t* pixeliter;
   ir_setdata fiter;
+
+  /* create the default ht */
+  ht = bin_ht_alloc();
+  for(pixeliter = default_pixel_list; pixeliter != NULL; pixeliter = pixeliter->next)
+    { ht_entry.val = 1;
+      ht_entry.key = pixel_iter->data.ref;
+      bin_insert_pixel_ht_entry(&ht, ;
+    }
+  
+
+
   
   /* Insert variants into hash table to overwrite olink insertions*/
   for ( fiter = ir_set_framebox(set); fiter != NULL; fiter = ir_setdata_nextsib(fiter))
     { fseek(binaryout, 0, SEEK_END);
-      ht_entry.key = NAMEHASH(ir_setdata_name(fiter), ht->entries);  
+      ht_entry.key = NAMEHASH(ir_setdata_name(fiter), ht->entries);
+        /* create the copy, pass the copy */
       ht_entry.value = bin_process_framebox(set, fiter, default_pixel_list);
       bin_insert_var_ht_entry(ht->start, ht->entries * sizeof(ht_entry), &ht_entry, 1);     
     }
@@ -889,7 +957,7 @@ bin_process_facing
 
 /* pixel_list == ops, output up to fwidth amount of them */
 void
-bin_output_pixel_list(struct bin_pixel_node_t* map_pixel_list)
+bin_output_pixel_list(struct bin_pixel_node_t* map_pixel_list);
 
 /* TODO: Please rename all the functions jhc*/
 static inline
@@ -923,29 +991,65 @@ int bin_set_map_pixel_list_attach_idxs
        defaultiter = defaultiter->next;
     }
 }
+int bin_ref_in_pixel_list
+( struct bin_pixel_node_t* pixel_list,
+  uint32_t ref
+)
+{ struct bin_pixel_node_t* iter;
+  for(iter = pixel_list; iter != NULL; iter = iter->next)
+    { if(ref == iter.data.ref)
+       return 1;
+    }
+  return 0;
+}
+
+struct bin_pixel_ht_t*
+#define PIXEL_HT_SIZE() (sizeof(bin_pixel_ht_entry_t) * SYS_PAGESIZE + sizeof(bin_pixel_ht_t*))
+bin_pixel_ht_alloc
+( void )
+{ struct bin_pixel_ht_t* ht;
 
-/* map_pixel_list cannot have more pixels. for all of its pixels,
-   the refs must be represented in default pixel list. 0 if invalid, 1 if valid */
+  if(!(ht = (struct bin_pixel_ht_t*) malloc( PIXEL_HT_SIZE())))
+   eprintf("Memory allocation error in bin_pixel_ht_alloc\n");
+  memset(ht, 0, PIXEL_HT_SIZE());
+
+  return ht;
+}
+
+void
+bin_insert_pixel_ht_entry
+( struct bin_pixel_ht_t** ht,
+  struct bin_pixel_ht_entry_t* ht_entry
+)
+{ if(*ht == NULL)
+    *ht = bin_pixel_ht_alloc();
+    
+}
+
+/* Determines if the multiset map_pixel is a subset of the multiset default pixel list.
+   0 if invalid, 1 if valid */
 static inline
 int bin_valid_map_pixel_list
-( struct bin_pixel_node_t* default_pixel_list,
+( struct bin_pixel_ht_t* default_ht,
   struct bin_pixel_node_t* map_pixel_list
 )
-{ struct bin_pixel_node_t* mapiter, *defaultiter;
+{ struct bin_pixel_node_t* mapiter, *defaultiter, *tmpdefault, tmpmap;
+  int i;
   defaultiter = default_pixel_list;
-  /* check length of each to make sure default < max */
-  /* for each pixel node in default and map */
-  /* TODO: Implement:: basically just checkking if map_pixel_list is subset of default_pixel_list
-     which means is the intersection of default_pl and map_pl == default_pl */
-  
+  mapiter = map_pixel_list;
 
+  while(mapiter != NULL)
+    { /* hash the ref*/
+      /* compare against the default ht */
+      /* decrement the value of the found ht_entry */
+      /* if(value == 0) */
+      /*  return 0 */
 
-  if(!mapiter && defaultiter) //defaultiter is longer so error!
-    return 0;
 
+    }
   
-  
-  
+  return 1;
     
 }
 static inline 
@@ -963,7 +1067,7 @@ int bin_process_map_pixel_list
 }
 
 void
-bin_assign_pixel_idxs
+ bin_assign_pixel_idxs
 ( struct bin_pixel_node_t* pixel_list )
 { 
 }
@@ -972,111 +1076,65 @@ bin_assign_pixel_idxs
 /* number the pixels as you insert them */
 struct bin_pixel_node_t*
 bin_insert_node_into_list
-( struct bin_pixel_node_t* pixel_list_root,
+( struct bin_pixel_node_t** pixel_list_root,
   struct bin_pixel_node_t* pixel_node
 )
-{ struct bin_pixel_node_t* head_node, * prev_node;
+{ struct bin_pixel_node_t** head_node;
 
+  head_node = pixel_list_root;
 
-  if(pixel_list_root == NULL)
-    { pixel_list_root = pixel_node;
-    }
-  
-  prev_node = head_node = pixel_list_root;  
-  while(head_node != NULL)
-    { if(pixel_node->data.z > head_node->data.z)
-       { if(head_node->next)
-           { prev_node = head_node;
-             head_node = head_node->next;
-           }
-         else
-           { head_node->next = pixel_node;
-             break;
-           }
-       }
-      else if (pixel_node->data.z < head_node->data.z)
-       { pixel_node->num++;
-         prev_node->next = pixel_node;
-         pixel_node->next = head_node;
-         break;
-       }
-      else // pixel_node->data.z == head_node->data.z
-       { pixel_node->num = head_node->num + 1;
-         prev_node->next = pixel_node;
-         pixel_node->next = head_node;
-       }
-    }
+  while(*head_node != NULL && head_node->data.ref < pixel_node->data.ref)
+    head_node = &((*head_node)->next);
+
+  pixel_node->next = *head_node;
+  *head_node = pixel_node;
 
   return pixel_list_root;
 
 
 }
 
-/* Returns the non null pixels of a single map */
-/* TODO: Finish this */
-struct bin_pixel_node_t* 
+/* Returns the non null pixels of a single mapframe (unaligned or not) 
+   given any  height and width */
+struct bin_pixel_node_t*
 bin_mapframe_to_pixel_list
 ( struct bin_img_info_t* img_info,
   int init_height,
   int init_width,
   RBGA_t* data
 )
-{ int x, y, fheight, fwidth;
+{ int j, i, fheight, fwidth, fhsize, fwsize;
+  RGBA_t* p;
   struct bin_pixel_node_t* pixel_list,* pixel_node;
 
   pixel_list = NULL;
 
   /* if frame clips, process unclippign frames */
-  if( img_info->unaligned_width )
-    { if(img_info->height < img_info->fheight)
-       fheight = img_info->height;
-      else
-       fheight = img_info->fheight;
-     }
-  else
-    fheight = img_info->fheight;
-  if (img_info->unaligned_height )
-    { if(img_info->width < img_info->fwidth)
-       fwidth = img_info->width;
-      else
-       fwidth = img_info->fwidth;
-    }
-  else
-    fwidth = img_info->fwidth;
+  
+  fwsize = img_info->unaligned_width ? img_info->unaligned_width : img_info->fwidth;
+  fhsize = img_info->unaligned_height ? img_info->unaligned_height : img_info->fwidth;
+
+
+  fwidth = img_info->fwidth;
+  fheight = img_info->fheight;
     
   
   /* Process the map*/
-  for (y = 0; y < fheight ; y++)
-    { for ( x = 0; x < fwidth; x++ )
-      { if (*data)
+  for (i = init_height; i < fhsize; i++)
+    { for ( j = init_width; j < fwsize; j++ )
+       { if (p = data[i*img_info->width+j])
          { pixel_node = struct_alloc(bin_pixel_node_t);
            /* get ref from 4 bytes of data */  
-           pixel_node->data.ref =  (*data) >> 8;
+           pixel_node->data.ref =  (*p) >> 8;
            /* bitshift by ? to get Z */
-           pixel_node->data.z = (*data & 0xFF);
+           pixel_node->data.z = (*p & 0xFF);
            /* set x and y */
-           pixel_node->data.x = x + init_width;
-           pixel_node->data.y = y + init_width;
-           pixel_list = bin_insert_node_into_list(pixel_list, pixel_node);
+           pixel_node->data.x = j;
+           pixel_node->data.y = i;
+           pixel_node->data.num = 0; 
+           pixel_list = bin_insert_node_into_list(&pixel_list, pixel_node);
          }
-       data++;
       }
-      data += img_info->width - img_info->fwidth; //stride TODO: isnt this null at the last iteration?
-    }
-  //TODO: fix these two for loops why dontcha
-  for ( x = 0; x < fwidth; x++ )
-    { if (*data)
-       { pixel_node = struct_alloc(bin_pixel_node_t);
-         /* get ref from 4 bytes of data */  
-         pixel_node->data.ref =  (*data) >> 8;
-         /* bitshift by ? to get Z */
-         pixel_node->data.z = (*data & 0xFF);
-         /* set x and y */
-         pixel_node->data.x = x + init_width;
-         pixel_node->data.y = y + init_width;
-         pixel_list = bin_insert_node_into_list(pixel_list, pixel_node);
-       }
-      data++;
     }
   
   return pixel_list;
@@ -1095,7 +1153,7 @@ int bin_pixel_list_len
     }    
   return count;
 }
-
+/* TODO: what are the qualifications for the default pixel list? len and __? */
 struct bin_pixel_node_t* 
 bin_cmp_default_pixel_lists
 ( struct bin_pixel_node_t* pl1,