Beispiel #1
0
mcxHash* mcxHashNew
(  dim         n_buckets
,  u32         (*hash)(const void *a)
,  int         (*cmp) (const void *a, const void *b)
)
   {  mcxHash  *h
   ;  mcxbool ok  = FALSE
      
   ;  u8 n_bits   =  0

   ;  if (!n_buckets)
      {  mcxErr("mcxHashNew strange", "void alloc request")
      ;  n_buckets = 2
   ;  }

      if (!(h = mcxAlloc(sizeof(mcxHash), RETURN_ON_FAIL)))
      return NULL

   ;  while(n_buckets)
      {  n_buckets >>=  1
      ;  n_bits++
   ;  }

      h->load           =  0.5
   ;  h->n_entries      =  0
   ;  h->n_buckets      =  n_buckets = (1 << n_bits)
   ;  h->cmp            =  cmp
   ;  h->hash           =  hash
   ;  h->options        =  MCX_HASH_OPT_DEFAULTS

   ;  h->src_link       =  NULL

   ;  while (1)                        /* fixme 2nd arg below, have better choice? */
      {  h->src_link = mcxGrimNew(sizeof(hash_link), h->n_buckets, MCX_GRIM_ARITHMETIC)
      ;  if (!h->src_link)
         break

      ;  if
         (! (  h->buckets
            =  mcxNAlloc
               (  h->n_buckets
               ,  sizeof(mcx_bucket)
               ,  mcx_bucket_init
               ,  RETURN_ON_FAIL
         )  )  )
         break

      ;  ok = TRUE
      ;  break
   ;  }

      if (!ok)
      {  mcxGrimFree(&(h->src_link))
      ;  mcxFree(h)
      ;  return NULL
   ;  }

      return h
;  }
static dim do_a_file
(  aggr** collectpp
,  const char* fname
,  dim collect_n
)
   {  mcxIO* xf = mcxIOnew(fname, "r")
   ;  mcxTing* buf = mcxTingEmpty(NULL, 100)
   ;  mcxTing* lbl = mcxTingEmpty(NULL, 100)
   ;  mcxstatus status = STATUS_OK
   ;  aggr* collect = *collectpp
   ;  dim ct = 0, collect_alloc = 0

   ;  if (!collect_n)
         collect_alloc = 100
      ,  collect = mcxNAlloc(collect_alloc, sizeof collect[0], NULL, EXIT_ON_FAIL)

   ;  mcxIOopen(xf, EXIT_ON_FAIL)

   ;  while (STATUS_OK == (status = mcxIOreadLine(xf, buf, MCX_READLINE_CHOMP)))
      {  double val
      ;  const char* tabchar = NULL
      ;  mcxbool get_header = collect_g != 'p' && !ct ? TRUE : FALSE

      ;  mcxTingEnsure(lbl, buf->len)

               /* if header_g && !ct && !paste create/check label */
               /* body of this while loop does too many things, refactor */
      ;  if (collect_g == 'p' || get_header)
         {  if (!(tabchar = strchr(buf->str, '\t')))
            mcxDie(1, me, "paste error at line %d file %s (no tab)", (int) xf->lc, fname)
         ;  mcxTingNWrite(lbl, buf->str, tabchar - buf->str)
      ;  }
         else
         {  if (2 != sscanf(buf->str, "%s%lg", lbl->str, &val))
            mcxDie(1, me, "parse error at line %d file %s", (int) xf->lc, fname)
         ;  lbl->len = strlen(lbl->str)
      ;  }

         if (!collect_n)
         {  if (ct >= collect_alloc)
            {  dim collect_realloc = collect_alloc * 1.44
            ;  collect = mcxNRealloc(collect, collect_realloc, collect_alloc, sizeof collect[0], NULL, EXIT_ON_FAIL)
            ;  collect_alloc = collect_realloc
         ;  }
            collect[ct].label = mcxTingStr(lbl)
         ;  collect[ct].val = collect_g == 'p' || get_header ? 0.0 : val
         ;  collect[ct].columns
            =      collect_g == 'p' || get_header
                ?  mcxTingNew(tabchar + (get_header ? 1 : 0))
                :  NULL
      ;  }
         else
         {  if (ct >= collect_n)
            mcxDie(1, me, "additional lines in file %s", fname)
         ;  if (strcmp(collect[ct].label, lbl->str))
            mcxDie
            (  1
            ,  me
            ,  "label conflict %s/%s at line %d in file %s"
            ,  collect[ct].label
            ,  lbl->str
            ,  (int) xf->lc, fname
            )
         ;  if (get_header)            /* only need to check identity */
            {  if (strcmp(tabchar+1, collect[ct].columns->str))
               mcxDie(1, me, "different columns <%s> and <%s>", collect[ct].columns->str, tabchar+1)
         ;  }
            else if (collect_g == 'p')          /* tack it on */
            mcxTingNAppend(collect[ct].columns, tabchar, buf->len - lbl->len)
         ;  else
            collect[ct].val += val 
      ;  }
         ct++
   ;  }

      if (collect_n)
      {  if (ct != collect_n)
         mcxDie(1, me, "not enough lines in file %s", fname)
   ;  }
      else
      {  if (!ct)
         mcxDie(1, me, "empty file(s)")
      ;  *collectpp = collect
   ;  }

      mcxIOfree(&xf)
   ;  return ct
;  }