Ejemplo n.º 1
0
Archivo: yadac.c Proyecto: pruiz/yada
static void ayadavar(autobuf_t *buf, yadac_param_t param, char *name)
{
  switch(param)
    {
  case(YADAC_INT):
    if(name)
      aprintf(buf, "int %s", name);
    else
      acopy(buf, "int");
    break;
  case(YADAC_FLOAT):
    if(name)
      aprintf(buf, "double %s", name);
    else
      acopy(buf, "double");
    break;
  case(YADAC_LONG):
    if(name)
      aprintf(buf, "long long %s", name);
    else
      acopy(buf, "long long");
    break;
  case(YADAC_BINARY):
  case(YADAC_STRING):
    if(name)
      aprintf(buf, "char *%s", name);
    else
      acopy(buf, "char*");
    break;
  case(YADAC_INTP):
    if(name)
      aprintf(buf, "int *%s", name);
    else
      acopy(buf, "int*");
    break;
  case(YADAC_FLOATP):
    if(name)
      aprintf(buf, "double *%s", name);
    else
      acopy(buf, "double*");
    break;
  case(YADAC_LONGP):
    if(name)
      aprintf(buf, "long long *%s", name);
    else
      acopy(buf, "long long*");
    break;
  case(YADAC_BINARYP):
  case(YADAC_STRINGP):
    if(name)
      aprintf(buf, "char *%s", name);
    else
      acopy(buf, "char*");
    break;
    }
}
Ejemplo n.º 2
0
Archivo: yadac.c Proyecto: pruiz/yada
static void ayadatypes(autobuf_t *buf, yadac_param_t *param, int params)
{
  int loop;


  for(loop=0; loop<params; param++, loop++)
    {
    switch(*param)
      {
    case(YADAC_INT):
      acopy(buf, "?d");
      break;
    case(YADAC_FLOAT):
      acopy(buf, "?f");
      break;
    case(YADAC_LONG):
      acopy(buf, "?l");
      break;
    case(YADAC_BINARY):
      acopy(buf, "?b");
      break;
    case(YADAC_STRING):
      acopy(buf, "?s");
      break;
    case(YADAC_INTP):
      acopy(buf, "?pd");
      break;
    case(YADAC_FLOATP):
      acopy(buf, "?pf");
      break;
    case(YADAC_LONGP):
      acopy(buf, "?pl");
      break;
    case(YADAC_BINARYP):
      acopy(buf, "?pb");
      break;
    case(YADAC_STRINGP):
      acopy(buf, "?ps");
      break;
      }
    } /* foreach(param) */
}
Ejemplo n.º 3
0
void preserves_input(dofft_closure *k, aconstrain constrain,
		     int n, C *inA, C *inB, C *outB, int rounds)
{
     int j;
     int recopy_input = k->recopy_input;

     k->recopy_input = 1;
     for (j = 0; j < rounds; ++j) {
	  arand(inA, n);
	  if (constrain)
	       constrain(inA, n);
	  
	  acopy(inB, inA, n);
	  k->apply(k, inB, outB);
	  acmp(inB, inA, n, "preserves_input", 0.0);
     }
     k->recopy_input = recopy_input;
}
Ejemplo n.º 4
0
Archivo: yadac.c Proyecto: pruiz/yada
static inline void aiproto(autobuf_t *buf, yadac_binding_t *binding)
{
  int idx;


  /* input struct bound, use it */
  if(binding->istruct)
    {
    aprintf(buf, ", %s *in", binding->istruct->type);
    return;
    }

  /* no input variables needed */
  if(!binding->iparams)
    return;

  /* loop through input paramters making variables */
  for(idx=0; idx<binding->iparams; idx++)
    {
    acopy(buf, ", ");
    ayadavar(buf, binding->iparam[idx], "in");
    aprintf(buf, "%u", (idx + 1));
    }
}
void access(Array& A, const const_array_tag&) {
  typedef boost::multi_array<int,3> array3;
  array3 acopy(A);
  BOOST_CHECK(equal(acopy,A));
  ++tests_run;
}
	void test_block_solver () {
		if (!process_messenger) process_messenger.reset (new mpi::messenger ());	

		int timesteps = 1;
		int id = process_messenger->get_id ();
		int np = process_messenger->get_np ();
		int n = 10, nrhs = 10, ntop = 0, nbot = 0;
		if (id != 0) {
			ntop = 1;
		}
		if (id != np - 1) {
			nbot = 1;
		}
		int lda = n + ntop + nbot, ldx = 0, ldb = lda;
	
		std::vector <int> ns (process_messenger->get_np ());
		process_messenger->gather <int> (1, &ntop, &ns [0]);
		if (process_messenger->get_id () == 0) {
			for (int i = 0; i < process_messenger->get_np (); ++i) {
				ldx += ns [i];
			}
		} else {
			ldx = ntop + nbot;
		}
		
		std::vector <double> bufftop (ntop * nrhs), buffbot (nbot * nrhs), rbufftop (ntop * nrhs), rbuffbot (nbot * nrhs);
	
		std::vector <double> a (lda * lda), acopy (lda * lda);
		std::vector <double> b (lda * nrhs), bcopy (lda * nrhs);
		std::vector <int> ipiv (lda);
		std::vector <double> x (ldx * ldx);
		std::vector <int> xipiv (ldx);
		int info;
	
		srand (2);
	
		for (int i = 0; i < lda; ++i) {
			for (int j = 0; j < lda; ++j) {
				a [j * lda + i] = rand () % 100;
			}
			for (int j = 0; j < nrhs; ++j) {
				b [j * ldb + i] = rand () % 100;
				bcopy [j * ldb + i] = b [j * ldb + i];
			}
		}
	
		linalg::matrix_copy (lda, lda, &a [0], &acopy [0], lda, lda);
	
		// clock_t corig_begin, corig_end;
		// std::chrono::time_point <std::chrono::system_clock> orig_begin, orig_end;
	
		// corig_begin = clock ();
		// orig_begin = std::chrono::system_clock::now ();
	
		linalg::matrix_factorize (n, n, &a [0], &ipiv [0], &info, lda);
		linalg::matrix_solve (n, &a [0], &ipiv [0], &b [0], &info, nrhs, lda, ldb);
	
		// corig_end = clock ();
		// orig_end = std::chrono::system_clock::now ();
	
		// std::chrono::duration <double> orig_total = orig_end - orig_begin;
	
		// printf ("[%i] Orig CPU Time: %f\n", id, ((double) (corig_end - corig_begin))/CLOCKS_PER_SEC);
		// printf ("[%i] Orig Wall Time: %f\n", id, (double) orig_total.count ());
	
		// clock_t cbegin, cmid, cend;
		// std::chrono::time_point <std::chrono::system_clock> begin, mid, end;
	
		// std::chrono::duration <double> mb, em, eb;
		// double cmb = 0.0, cem = 0.0, ceb = 0.0;
	
		for (int i = 0; i < timesteps; ++i) {
			for (int i = 0; i < lda; ++i) {
				for (int j = 0; j < lda; ++j) {
					a [j * lda + i] = rand () % 100;
					acopy [j * lda + i] = a [j * lda + i];
				}
				for (int j = 0; j < nrhs; ++j) {
					b [j * ldb + i] = rand () % 100;
					bcopy [j * ldb + i] = b [j * ldb + i];
				}
			}
			
			// cbegin = clock ();
			// begin = std::chrono::system_clock::now ();
		
			linalg::block::matrix_factorize (process_messenger->get_id (), process_messenger->get_np (), n, ntop, nbot, &a [0], &ipiv [0], &x [0], &xipiv [0], &ns [0], &info, lda, ldx);
	
			// cmid = clock ();
			// mid = std::chrono::system_clock::now ();
		
			// mb += mid - begin;
			// cmb += cmid - cbegin;
		
			linalg::block::matrix_solve (process_messenger->get_id (), process_messenger->get_np (), n, ntop, nbot, &a [0], &ipiv [0], &b [0], &x [0], &xipiv [0], &ns [0], &info, nrhs, lda, ldx, ldb);
	
			// cend = clock ();
			// end = std::chrono::system_clock::now ();
		
			// em += end - mid;
			// eb += end - begin;
			// cem += cend - cmid;
			// ceb += cend - cbegin;
			
			linalg::matrix_matrix_multiply (n + ntop + nbot, nrhs, n + ntop + nbot, 1.0, &acopy [0], &b [0], -1.0, &bcopy [0]);
			
			if (id != 0) {
				linalg::matrix_copy (ntop, nrhs, &bcopy [0], &bufftop [0], ldb, ntop);
				process_messenger->send (ntop * nrhs, &bufftop [0], id - 1, 0);
			}
			if (id != np - 1) {
				linalg::matrix_copy (nbot, nrhs, &bcopy [n + ntop], &buffbot [0], ldb, nbot);
				process_messenger->recv (nbot * nrhs, &rbuffbot [0], id + 1, 0);
				process_messenger->send (nbot * nrhs, &buffbot [0], id + 1, 1);
				linalg::matrix_add_scaled (nbot, nrhs, 1.0, &rbuffbot [0], &bcopy [n + ntop], nbot, ldb);
			}
			if (id != 0) {
				process_messenger->recv (ntop * nrhs, &rbufftop [0], id - 1, 1);
				linalg::matrix_add_scaled (ntop, nrhs, 1.0, &rbufftop [0], &bcopy [0], ntop, ldb);
			}
			
			for (int i = 0; i < n + ntop + nbot; ++i) {
				for (int j = 0; j < nrhs; ++j) {
					TSM_ASSERT_DELTA ("Block solver failure", bcopy [j * ldb + i], 0.0, TEST_TINY);
				}
			}
		}
	
		// printf ("[%i] Avg CPU Time: %f + %f = %f\n", id, ((double) (cmb))/CLOCKS_PER_SEC/timesteps, ((double) (cem))/CLOCKS_PER_SEC/timesteps, ((double) (ceb))/CLOCKS_PER_SEC/timesteps);
		// printf ("[%i] Avg Wall Time: %f + %f = %f\n", id, (double) mb.count ()/timesteps, (double) em.count ()/timesteps, (double) eb.count ()/timesteps);
	}
//------------------------------------------------------------------------
// Test exceptions safety (from allocator and items constructors)
//------------------------------------------------------------------------
void TestExceptions() {
    typedef static_counting_allocator<debug_allocator<FooWithAssign>, std::size_t> allocator_t;
    typedef tbb::concurrent_vector<FooWithAssign, allocator_t> vector_t;

    enum methods {
        zero_method = 0,
        ctor_copy, ctor_size, assign_nt, assign_ir, op_equ, reserve, compact, grow,
        all_methods
    };
    ASSERT( !FooCount, NULL );

    try {
        vector_t src(FooIterator(0), FooIterator(N)); // original data

        for(int t = 0; t < 2; ++t) // exception type
        for(int m = zero_method+1; m < all_methods; ++m)
        {
            ASSERT( FooCount == N, "Previous iteration miss some Foo's de-/initialization" );
            allocator_t::init_counters();
            if(t) MaxFooCount = FooCount + N/4;
            else allocator_t::set_limits(N/4);
            vector_t victim;
            try {
                switch(m) {
                case ctor_copy: {
                        vector_t acopy(src);
                    } break; // auto destruction after exception is checked by ~Foo
                case ctor_size: {
                        vector_t sized(N);
                    } break; // auto destruction after exception is checked by ~Foo
                // Do not test assignment constructor due to reusing of same methods as below 
                case assign_nt: {
                        victim.assign(N, FooWithAssign());
                    } break;
                case assign_ir: {
                        victim.assign(FooIterator(0), FooIterator(N));
                    } break;
                case op_equ: {
                        victim.reserve(2); victim = src; // fragmented assignment
                    } break;
                case reserve: {
                        try {
                            victim.reserve(victim.max_size()+1);
                        } catch(std::length_error &) {
                        } catch(...) {
                            KNOWN_ISSUE("ERROR: unrecognized exception - known compiler issue\n");
                        }
                        victim.reserve(N);
                    } break;
                case compact: {
                        if(t) MaxFooCount = 0; else allocator_t::set_limits(); // reset limits
                        victim.reserve(2); victim = src; // fragmented assignment
                        if(t) MaxFooCount = FooCount + 10; else allocator_t::set_limits(1, false); // block any allocation, check NULL return from allocator
                        victim.shrink_to_fit(); // should start defragmenting first segment
                    } break;
                case grow: {
                        tbb::task_scheduler_init init(2);
                        if(t) MaxFooCount = FooCount + 31; // these numbers help to reproduce the live lock for versions < TBB2.2
                        try {
                            tbb::parallel_for( tbb::blocked_range<int>(0, N, 70), GrowBy<vector_t>(victim) );
                        } catch(...) {
#if TBB_USE_CAPTURED_EXCEPTION
                            throw tbb::bad_last_alloc();
#else
                            throw;
#endif
                        }
                    } break;
                default:;
                }
                if(!t || m != reserve) ASSERT(false, "should throw an exception");
            } catch(std::bad_alloc &e) {
                allocator_t::set_limits(); MaxFooCount = 0;
                size_t capacity = victim.capacity();
                size_t size = victim.size();
#if TBB_DEPRECATED
                size_t req_size = victim.grow_by(0);
#else
                size_t req_size = victim.grow_by(0) - victim.begin();
#endif
                ASSERT( size <= capacity, NULL);
                ASSERT( req_size >= size, NULL);
                switch(m) {
                case reserve:
                    if(t) ASSERT(false, NULL);
                case assign_nt:
                case assign_ir:
                    if(!t) {
                        ASSERT(capacity < N/2, "unexpected capacity");
                        ASSERT(size == 0, "unexpected size");
                        break;
                    } else {
                        ASSERT(size == N, "unexpected size");
                        ASSERT(capacity >= N, "unexpected capacity");
                        int i;
                        for(i = 1; ; ++i)
                            if(!victim[i].zero_bar()) break;
                            else ASSERT(victim[i].bar() == (m == assign_ir)? i : initial_value_of_bar, NULL);
                        for(; size_t(i) < size; ++i) ASSERT(!victim[i].zero_bar(), NULL);
                        ASSERT(size_t(i) == size, NULL);
                        break;
                    }
                case grow:
                case op_equ:
                    if(!t) {
                        ASSERT(capacity > 0, NULL);
                        ASSERT(capacity < N, "unexpected capacity");
                    }
                    {
                        vector_t copy_of_victim(victim);
                        ASSERT(copy_of_victim.size() > 0, NULL);
                        for(int i = 0; ; ++i) {
                            try {
                                FooWithAssign &foo = victim.at(i);
                                if( !foo.is_valid_or_zero() ) {
                                    std::printf("i: %d size: %u req_size: %u  state: %d\n", i, unsigned(size), unsigned(req_size), foo.state);
                                }
                                int bar = foo.zero_bar();
                                if(m != grow) ASSERT( bar == i || (t && bar == 0), NULL);
                                if(size_t(i) < copy_of_victim.size()) ASSERT( copy_of_victim[i].bar() == bar, NULL);
                            } catch(std::range_error &) { // skip broken segment
                                ASSERT( size_t(i) < req_size, NULL );
                                if(m == op_equ) break;
                            } catch(std::out_of_range &){
                                ASSERT( i > 0, NULL ); break;
                            } catch(...) {
                                KNOWN_ISSUE("ERROR: unrecognized exception - known compiler issue\n"); break;
                            }
                        }
                        vector_t copy_of_victim2(10); copy_of_victim2 = victim;
                        ASSERT(copy_of_victim == copy_of_victim2, "assignment doesn't match copying");
                        if(m == op_equ) {
                            try {
                                victim = copy_of_victim2;
                            } catch(tbb::bad_last_alloc &) { break;
                            } catch(...) {
                                KNOWN_ISSUE("ERROR: unrecognized exception - known compiler issue\n"); break;
                            }
                            ASSERT(t, NULL);
                        }
                    } break;
                case compact:
                    ASSERT(capacity > 0, "unexpected capacity");
                    ASSERT(victim == src, "shrink_to_fit() is broken");
                    break;

                default:; // nothing to check here
                }
                REMARK("Exception %d: %s\t- ok\n", m, e.what());
            }
        }
    } catch(...) {
        ASSERT(false, "unexpected exception");
    }
}
void TestExceptions() {
    typedef local_counting_allocator<tbb::tbb_allocator<MyData2> > allocator_t;
    typedef tbb::concurrent_hash_map<MyKey,MyData2,MyHashCompare,allocator_t> ThrowingTable;
    enum methods {
        zero_method = 0,
        ctor_copy, op_assign, op_insert,
        all_methods
    };
    REMARK("testing exception-safety guarantees\n");
    ThrowingTable src;
    FillTable( src, 1000 );
    ASSERT( MyDataCount==1000, NULL );

    try {
        for(int t = 0; t < 2; t++) // exception type
        for(int m = zero_method+1; m < all_methods; m++)
        {
            allocator_t a;
            if(t) MyDataCountLimit = 101;
            else a.set_limits(101);
            ThrowingTable victim(a);
            MyDataCount = 0;

            try {
                switch(m) {
                case ctor_copy: {
                        ThrowingTable acopy(src, a);
                    } break;
                case op_assign: {
                        victim = src;
                    } break;
                case op_insert: {
                        FillTable( victim, 1000 );
                    } break;
                default:;
                }
                ASSERT(false, "should throw an exception");
            } catch(std::bad_alloc &e) {
                MyDataCountLimit = 0;
                size_t size = victim.size();
                switch(m) {
                case op_assign:
                    ASSERT( MyDataCount==100, "data leak?" );
                    ASSERT( size>=100, NULL );
                    CheckAllocator(victim, 100+t, t);
                case ctor_copy:
                    CheckTable(src, 1000);
                    break;
                case op_insert:
                    ASSERT( size==size_t(100-t), NULL );
                    ASSERT( MyDataCount==100-t, "data leak?" );
                    CheckTable(victim, 100-t);
                    CheckAllocator(victim, 100, t);
                    break;

                default:; // nothing to check here
                }
                REMARK("Exception %d: %s\t- ok ()\n", m, e.what());
            }
            catch ( ... ) {
                ASSERT ( __TBB_EXCEPTION_TYPE_INFO_BROKEN, "Unrecognized exception" );
            }
        }
    } catch(...) {
        ASSERT(false, "unexpected exception");
    }
    src.clear(); MyDataCount = 0;
}
Ejemplo n.º 9
0
Archivo: yadac.c Proyecto: pruiz/yada
static char* gen_header(yadac_t *tree, int *siz,
 char *src_fname, char *fname, char *prefix)
{
  char tag[32];
  char *ptr, *in, *out;
  int loop, idx;
  yadac_binding_t *binding;
  autobuf_t *buf;


  /* convert prefix to caps */
  snprintf(tag, sizeof(tag), "%s", prefix);
  for(ptr=tag; *ptr; ptr++)
    *ptr = toupper(*ptr);

  /* remove path from source filename */
  in = strrchr(src_fname, '/');
  in = (in ? (in + 1) : src_fname);

  /* remove path from output filename */
  out = strrchr(fname, '/');
  out = (out ? (out + 1) : fname);

  /* allocate new autobuf */
  if(!(buf = calloc(1, sizeof(autobuf_t))))
    return(NULL);

  acopy(buf, "\n/*******************************************************");
  acopy(buf, "***********************\n ********************************");
  acopy(buf, "**********************************************/\n\n");

  aprintf(buf, "/** \\file %s\n", out);
  aprintf(buf, " *  automatically generated from: %s\n */\n\n", in);
  aprintf(buf, "#ifndef __YADAC_%s_H__\n", tag);
  aprintf(buf, "#define __YADAC_%s_H__\n\n", tag);

  acopy(buf, "/*********************************************************");
  acopy(buf, "*********************\n * I N C L U D E S ****************");
  acopy(buf, "********************************************\n ***********");
  acopy(buf, "**********************************************************");
  acopy(buf, "*********/\n\n");

  acopy(buf, "#include <yada.h>\n\n");

  /* list included files */
  if(tree->incs)
    {
    for(loop=0; loop<tree->incs; loop++)
      aprintf(buf, "#include \"%s\"\n", tree->inc[loop]);
    acopy(buf, "\n");
    }

  acopy(buf, "/*********************************************************");
  acopy(buf, "*********************\n * T Y P E D E F S ****************");
  acopy(buf, "********************************************\n ***********");
  acopy(buf, "**********************************************************");
  acopy(buf, "*********/\n\n");

  acopy(buf, "#ifndef __YADAC_T_\n");
  acopy(buf, "#define __YADAC_T_\n\n");

  acopy(buf, "typedef struct\n{\n");
  acopy(buf, "  yada_t *db;\n");
  acopy(buf, "  int sz;\n  int rcs;\n");
  acopy(buf, "  yada_rc_t **rc;\n");
  acopy(buf, "} yadac_t;\n\n");

  acopy(buf, "#endif\n\n");

  acopy(buf, "/*********************************************************");
  acopy(buf, "*********************\n * P R O T O T Y P E S ************");
  acopy(buf, "********************************************\n ***********");
  acopy(buf, "**********************************************************");
  acopy(buf, "*********/\n\n");

  aprintf(buf, "/* init / destroy %s functions */\n", prefix);
  aprintf(buf, "yadac_t* %s_init(yadac_t *db, ...);\n", prefix);
  aprintf(buf, "void %s_free(yadac_t *yc);\n\n", prefix);
  aprintf(buf, "void %s_destroy(yadac_t *yc);\n\n", prefix);

  /* output prototypes */
  acopy(buf, "/* compiled queries */\n");
  for(loop=0, binding=tree->bind; loop<tree->binds; binding++, loop++)
    {
    switch(binding->rtype)
      {
    /************************************************/
    case(YADAC_STATUS):
    /************************************************/
      aprintf(buf, "int %s_%s(yadac_t *yc", prefix, binding->name);
      aiproto(buf, binding);
      acopy(buf, ");\n\n");
      break;
    /************************************************/
    case(YADAC_SIMPLE):
    /************************************************/
      ayadavar(buf, *binding->oparam, NULL);
      aprintf(buf, " %s_%s(yadac_t *yc, ", prefix, binding->name);
      ayadavar(buf, *binding->oparam, "errval");

      aiproto(buf, binding);
      acopy(buf, ");\n\n");
      break;
    /************************************************/
    case(YADAC_SINGLE):
    /************************************************/
      aprintf(buf, "int %s_%s(yadac_t *yc", prefix, binding->name);
      aiproto(buf, binding);
      for(idx=0; idx<binding->oparams; idx++)
        {
        acopy(buf, ", ");
        if(binding->oparam[idx] == YADAC_STRING)
          ayadavar(buf, binding->oparam[idx], "out");
        else
          ayadavar(buf, binding->oparam[idx], "*out");
        aprintf(buf, "%u", (idx + 1));
        }
      acopy(buf, ");\n\n");
      break;
    /************************************************/
    case(YADAC_STRUCT):
    /************************************************/
      aprintf(buf, "int %s_%s(yadac_t *yc", prefix, binding->name);
      aiproto(buf, binding);
      aprintf(buf, ", %s *out);\n\n", binding->ostruct->type);
      break;
    /************************************************/
    case(YADAC_MULTIROW):
    /************************************************/
      aprintf(buf, "int %s_%s(yadac_t *yc", prefix, binding->name);
      aiproto(buf, binding);
      for(idx=0; idx<binding->oparams; idx++)
        {
        acopy(buf, ", ");
        if(binding->oparam[idx] == YADAC_STRING)
          ayadavar(buf, binding->oparam[idx], "out");
        else
          ayadavar(buf, binding->oparam[idx], "*out");
        aprintf(buf, "%u", (idx + 1));
        }
      acopy(buf, ");\n");

      aprintf(buf, "int %s_%s_fetch(yadac_t *yc);\n", prefix, binding->name);
      break;
    /************************************************/
    case(YADAC_MULTISTRUCT):
    /************************************************/
      aprintf(buf, "int %s_%s(yadac_t *yc", prefix, binding->name);
      aiproto(buf, binding);
      aprintf(buf, ", %s *out);\n\n", binding->ostruct->type);
      aprintf(buf, "int %s_%s_fetch(yadac_t *yc);\n", prefix, binding->name);
      break;
    /************************************************/
      } /* switch(rtype) */
    } /* foreach(binding) */

  acopy(buf, "/*********************************************************");
  acopy(buf, "*********************/\n\n");


  aprintf(buf, "#endif /* end __YADAC_%s_H__ */\n\n", tag);

  acopy(buf, "/*********************************************************");
  acopy(buf, "*********************\n **********************************");
  acopy(buf, "********************************************/\n\n");

  /* check if any errors occured */
  if(buf->errs)
    {
    free(buf->ptr);
    free(buf);
    return(NULL);
    }

  /* set size if needed */
  if(siz)
    *siz = buf->siz;

  /* shrink and return buffer */
  ptr = realloc(buf->ptr, buf->siz);
  free(buf);
  return(ptr);
}
Ejemplo n.º 10
0
Archivo: yadac.c Proyecto: pruiz/yada
static char* gen_source(yadac_t *tree, int *siz,
 char *src_fname, char *fname, char *hdr_fname, char *prefix)
{
  char tag[32];
  char *ptr, *in, *out, *hdr;
  int loop, idx;
  autobuf_t *buf;
  yadac_binding_t *binding;


  /* convert prefix to caps */
  snprintf(tag, sizeof(tag), "%s", prefix);
  for(ptr=tag; *ptr; ptr++)
    *ptr = toupper(*ptr);

  /* remove path from source filename */
  in = strrchr(src_fname, '/');
  in = (in ? (in + 1) : src_fname);

  /* remove path from output filename */
  out = strrchr(fname, '/');
  out = (out ? (out + 1) : fname);

  /* remove path from header filename */
  hdr = strrchr(hdr_fname, '/');
  hdr = (hdr ? (hdr + 1) : hdr_fname);

  /* allocate new autobuf */
  if(!(buf = calloc(1, sizeof(autobuf_t))))
    return(NULL);


  acopy(buf, "\n/*******************************************************");
  acopy(buf, "***********************\n ********************************");
  acopy(buf, "**********************************************/\n\n");

  aprintf(buf, "/** \\file %s\n", out);
  aprintf(buf, " *  automatically generated from: %s\n */\n\n", in);

  acopy(buf, "/*********************************************************");
  acopy(buf, "*********************\n * D E F I N E S ******************");
  acopy(buf, "********************************************\n ***********");
  acopy(buf, "**********************************************************");
  acopy(buf, "*********/\n\n");

  aprintf(buf, "#define __YADAC_%s_LIBSRC_\n", tag);
  aprintf(buf, "#define YADAC_%s_CHUNK_SZ 8\n\n", tag);

  acopy(buf, "/*********************************************************");
  acopy(buf, "*********************\n * I N C L U D E S ****************");
  acopy(buf, "********************************************\n ***********");
  acopy(buf, "**********************************************************");
  acopy(buf, "*********/\n\n");

  acopy(buf, "#include <stdarg.h>\n\n");
  acopy(buf, "#include <stdlib.h>\n\n");
  acopy(buf, "#include <yada.h>\n\n");
  aprintf(buf, "#include \"%s\"\n\n", hdr);

  acopy(buf, "/*********************************************************");
  acopy(buf, "*********************\n * S Q L **************************");
  acopy(buf, "********************************************\n ***********");
  acopy(buf, "**********************************************************");
  acopy(buf, "*********/\n\n");

  /* output SQL for each query */
  for(loop=0, binding=tree->bind; loop<tree->binds; binding++, loop++)
    {
    aprintf(buf, "#define SQL_%s \\\n", binding->upper);
    for(idx=0; idx<binding->lines; idx++)
      {
      aindent(buf, binding->line[idx].indent);
      if((idx + 1) < binding->lines)
        aprintf(buf, "\"%s \"\\\n", binding->line[idx].text);
      else
        aprintf(buf, "\"%s\"\n", binding->line[idx].text);
      }
    acopy(buf, "\n");
    }

  acopy(buf, "/*********************************************************");
  acopy(buf, "*********************\n * G L O B A L S ******************");
  acopy(buf, "********************************************\n ***********");
  acopy(buf, "**********************************************************");
  acopy(buf, "*********/\n\n");

  acopy(buf, "/* saved database pointer */\n");
  acopy(buf, "static yadac_t *yadac;\n\n");

  /* output statement pointer for each query */
  aprintf(buf, "/* %s statements */\n", prefix);
  for(loop=0, binding=tree->bind; loop<tree->binds; binding++, loop++)
    aprintf(buf, "static yada_rc_t *stmt_%s = NULL;\n", binding->name);
  acopy(buf, "\n");

  acopy(buf, "/*********************************************************");
  acopy(buf, "*********************\n * F U N C T I O N S **************");
  acopy(buf, "********************************************\n ***********");
  acopy(buf, "**********************************************************");
  acopy(buf, "*********/\n\n");

  acopy(buf, "/*********************************************************");
  acopy(buf, "*********************/\n");
  aprintf(buf, "/** prepare %s statements\n", prefix);
  acopy(buf, " * @param yc yadac_t to use\n");
  acopy(buf, " * @param yada_t* db if yc is null, alloc new and use this db\n");
  acopy(buf, " * @return yadac_t* on success, NULL on error\n */\n");

  aprintf(buf, "\nyadac_t* %s_init(yadac_t *yc, ...)\n{\n", prefix);
  acopy(buf, "  int err = 0;\n  va_list ap;\n  yada_t *db;\n\n\n");

  /* create yadac */
  acopy(buf, "  if(!yc)\n    {\n");
  acopy(buf, "    if(!(yadac = calloc(1, sizeof(yadac_t))) || ");
  aprintf(buf, "!(yadac->rc = malloc(YADAC_%s_CHUNK_SZ * ", tag);
  acopy(buf, "sizeof(yadac_t*))))\n      {\n      free(yadac);\n");
  aprintf(buf, "      return(NULL);\n      }\n", prefix);
  acopy(buf, "    va_start(ap, yc);\n    yadac->db = va_arg(ap, yada_t*);\n");
  acopy(buf, "    va_end(ap);\n");
  aprintf(buf, "    yadac->sz = YADAC_%s_CHUNK_SZ;\n    }\n", tag);
  acopy(buf, "  else\n    yadac = yc;\n\n");
  acopy(buf, "  db = yadac->db;\n\n");

  /* code to prepare statements */
  aprintf(buf, "  /* prepare %s statements */\n", prefix);
  for(loop=0, binding=tree->bind; loop<tree->binds; binding++, loop++)
    aprintf(buf, "  err |= !(stmt_%s = db->%s(db, SQL_%s, 0));\n",
     binding->name, (binding->ptype ? "yprepare" : "prepare"), binding->upper);
  acopy(buf, "\n");

  /* output error check */
  acopy(buf, "  /* check for errors */\n");
  acopy(buf, "  if(err)\n    {\n");
  aprintf(buf, "    %s_destroy(yadac);\n    return(NULL);\n    }\n\n", prefix);

  acopy(buf, "  return(yadac);\n}\n\n");

  acopy(buf, "/*********************************************************");
  acopy(buf, "*********************/\n");
  aprintf(buf, "/** free %s queries and bindsets\n */\n", prefix);

  aprintf(buf, "\nvoid %s_free(yadac_t *yc)\n{\n", prefix);

  /* make sure yadac instance was specified */
  acopy(buf, "  if(!yc)\n    yc = yadac;\n\n");
  acopy(buf, "  if(!yc->rcs)\n    return;\n\n");

  acopy(buf, "  while(yc->rcs--)\n");
  acopy(buf, "    yc->db->free(yc->db, yc->rc[yc->rcs]);\n\n");
  acopy(buf, "  yc->rcs = 0;\n}\n\n");

  acopy(buf, "/*********************************************************");
  acopy(buf, "*********************/\n");
  aprintf(buf, "/** destroy %s statements\n */\n", prefix);

  aprintf(buf, "\nvoid %s_destroy(yadac_t *yc)\n{\n", prefix);
  acopy(buf, "  yada_t *db;\n\n\n");

  /* make sure yadac instance was specified */
  acopy(buf, "  if(!yc)\n    yc = yadac;\n");
  acopy(buf, "  db = yc->db;\n\n");

  /* cleanup each statement */
  for(loop=0, binding=tree->bind; loop<tree->binds; binding++, loop++)
    {
    aprintf(buf, "  if(stmt_%s)\n", binding->name);
    aprintf(buf, "    db->free(db, stmt_%s);\n", binding->name);
    aprintf(buf, "  stmt_%s = NULL;\n\n", binding->name);
    }

  /* cleanup results and free yadac */
  aprintf(buf, "  %s_free(yc);\n  free(yc->rc);\n  free(yc);\n", prefix);
  acopy(buf, "  if(yc == yadac)\n    yadac = NULL;\n");
  acopy(buf, "}\n\n");

  acopy(buf, "/*********************************************************");
  acopy(buf, "*********************/\n");
  aprintf(buf, "/** push rcs onto yadac\n", prefix);
  acopy(buf, " * @return 0 on success, -1 on error\n */\n");

  acopy(buf, "\ninline static int _yadac_push(yadac_t *yc, ");
  acopy(buf, "yada_rc_t *query, yada_rc_t *bs)\n{\n");
  acopy(buf, "  yada_rc_t **tmp;\n\n\n");

  /* grow yadac rc array if needed */
  acopy(buf, "  if(yc->rcs + 1 >= yc->sz)\n    {\n");
  acopy(buf, "    if(!(tmp = realloc(yc->rc, sizeof(yada_rc_t*) * (yc->sz + ");
  aprintf(buf, "YADAC_%s_CHUNK_SZ))))\n      return(-1);\n", tag);
  aprintf(buf, "    yc->rc = tmp;\n    yc->sz += YADAC_%s_CHUNK_SZ;\n    }\n\n",
   tag);

  /* set rcs */
  acopy(buf, "  yc->rc[yc->rcs++] = query;\n  yc->rc[yc->rcs++] = bs;\n");
  acopy(buf, "  return(0);\n}\n\n");

  /* actual statement functions */
  for(loop=0, binding=tree->bind; loop<tree->binds; binding++, loop++)
    {
    acopy(buf, "/*********************************************************");
    acopy(buf, "*********************/\n");

    switch(binding->rtype)
      {
    /************************************************/
    case(YADAC_STATUS):
    /************************************************/
      aprintf(buf, "/** %s (STATUS operation)\n", binding->name);
      acopy(buf, " * @return num rows affected on success, ");
      acopy(buf, "-1 on error\n */\n\n");
      aprintf(buf, "int %s_%s(yadac_t *yc", prefix, binding->name);

      /* add input variables */
      aiproto(buf, binding);
      acopy(buf, ")\n{\n  yada_t *db;\n\n\n");

      /* make sure yadac instance was specified */
      acopy(buf, "  if(!yc)\n    yc = yadac;\n");
      acopy(buf, "  db = yc->db;\n\n");

      acopy(buf, "  /* execute statement */\n");
      aprintf(buf, "  return(db->execute(db, stmt_%s", binding->name);
      aivars(buf, binding);
      acopy(buf, "));\n}\n\n");
      break;
    /************************************************/
    case(YADAC_SIMPLE):
    /************************************************/
      aprintf(buf, "/** %s (SIMPLE operation)\n", binding->name);
      acopy(buf, " * @param errval value to return on error\n");
      acopy(buf, " * @return value on success, errval on error\n */\n\n");
      ayadavar(buf, *binding->oparam, NULL);
      aprintf(buf, " %s_%s(yadac_t *yc, ", prefix, binding->name);
      ayadavar(buf, *binding->oparam, "errval");
      aiproto(buf, binding);
      acopy(buf, ")\n{\n  ");

      ayadavar(buf, *binding->oparam, "out");
      acopy(buf, ";\n  int rval;\n");
      acopy(buf, "  yada_t *db;\n  yada_rc_t *bs, *query;\n\n\n");

      /* make sure yadac instance was specified */
      acopy(buf, "  if(!yc)\n    yc = yadac;\n");
      acopy(buf, "  db = yc->db;\n\n");

      acopy(buf, "  /* bind output variables */\n");
      acopy(buf, "  if(!(bs = db->bind(db, \"");
      ayadatypes(buf, binding->oparam, binding->oparams);
      acopy(buf, "\", &out)))\n    return(errval);\n\n");

      acopy(buf, "  /* perform query */\n");
      aprintf(buf, "  if(!(query = db->query(db, stmt_%s", binding->name);
      aivars(buf, binding);
      acopy(buf, ")))\n    {\n");
      acopy(buf, "    db->free(db, bs);\n");
      acopy(buf, "    return(errval);\n");
      acopy(buf, "    }\n\n");

      acopy(buf, "  /* fetch result */\n");
      acopy(buf, "  rval = db->fetch(db, query, bs);\n");
      acopy(buf, "  if(!rval || db->error || _yadac_push(yc, query, bs))\n");
      acopy(buf, "    {\n    db->free(db, query);\n    db->free(db, bs);\n");
      acopy(buf, "    return(errval);\n    }\n\n");

      acopy(buf, "  return(out);\n}\n\n");
      break;
    /************************************************/
    case(YADAC_SINGLE):
    /************************************************/
      aprintf(buf, "/** %s (SINGLE operation)\n", binding->name);
      acopy(buf, " * @return 0 on success, -1 on error\n */\n\n");
      aprintf(buf, "int %s_%s(yadac_t *yc", prefix, binding->name);
      aiproto(buf, binding);
      for(idx=0; idx<binding->oparams; idx++)
        {
        acopy(buf, ", ");
        if(binding->oparam[idx] == YADAC_STRING)
          ayadavar(buf, binding->oparam[idx], "out");
        else
          ayadavar(buf, binding->oparam[idx], "*out");
        aprintf(buf, "%u", (idx + 1));
        }
      acopy(buf, ")\n{\n");
      acopy(buf, "  int rval;\n");
      acopy(buf, "  yada_t *db;\n  yada_rc_t *bs, *query;\n\n\n");

      /* make sure yadac instance was specified */
      acopy(buf, "  if(!yc)\n    yc = yadac;\n");
      acopy(buf, "  db = yc->db;\n\n");

      acopy(buf, "  /* bind output variables */\n");
      acopy(buf, "  if(!(bs = db->bind(db, \"");
      ayadatypes(buf, binding->oparam, binding->oparams);
      acopy(buf, "\"");
      for(idx=0; idx<binding->oparams; idx++)
        aprintf(buf, ", out%u", (idx + 1));
      acopy(buf, ")))\n    return(-1);\n\n");

      acopy(buf, "  /* perform query */\n");
      aprintf(buf, "  if(!(query = db->query(db, stmt_%s", binding->name);
      aivars(buf, binding);
      acopy(buf, ")))\n    {\n");
      acopy(buf, "    db->free(db, bs);\n");
      acopy(buf, "    return(-1);\n");
      acopy(buf, "    }\n\n");

      acopy(buf, "  /* fetch result */\n");
      acopy(buf, "  rval = db->fetch(db, query, bs);\n");
      acopy(buf, "  if(!rval || db->error || _yadac_push(yc, query, bs))\n");
      acopy(buf, "    {\n    db->free(db, query);\n    db->free(db, bs);\n");
      acopy(buf, "    return(db->error ? -1 : 1);\n    }\n\n");

      acopy(buf, "  return(0);\n}\n\n");
      break;
    /************************************************/
    case(YADAC_STRUCT):
    /************************************************/
      aprintf(buf, "/** %s (%s STRUCT operation)\n", binding->name,
       binding->ostruct->type);
      acopy(buf, " * @return 0 on success, -1 on error, 1 no results\n */\n\n");
      aprintf(buf, "int %s_%s(yadac_t *yc", prefix, binding->name);
      aiproto(buf, binding);
      aprintf(buf, ", %s *out)\n{\n", binding->ostruct->type);
      acopy(buf, "  int rval;\n");
      acopy(buf, "  yada_t *db;\n  yada_rc_t *bs, *query;\n\n\n");

      /* make sure yadac instance was specified */
      acopy(buf, "  if(!yc)\n    yc = yadac;\n");
      acopy(buf, "  db = yc->db;\n\n");

      acopy(buf, "  /* bind output variables */\n");
      acopy(buf, "  if(!(bs = db->bind(db, \"");
      ayadatypes(buf, binding->oparam, binding->oparams);
      acopy(buf, "\"");
      for(idx=0; idx<binding->ostruct->list->tokens; idx++)
        if(*binding->ostruct->list->token[idx] < 0x2b)
          aprintf(buf, ", %cout->%s", binding->ostruct->list->token[idx][0],
           &binding->ostruct->list->token[idx][1]);
        else
          aprintf(buf, ", out->%s", binding->ostruct->list->token[idx]);
      acopy(buf, ")))\n    return(-1);\n\n");

      acopy(buf, "  /* perform query */\n");
      aprintf(buf, "  if(!(query = db->query(db, stmt_%s", binding->name);
      aivars(buf, binding);
      acopy(buf, ")))\n    {\n");
      acopy(buf, "    db->free(db, bs);\n");
      acopy(buf, "    return(-1);\n");
      acopy(buf, "    }\n\n");

      acopy(buf, "  /* fetch result */\n");
      acopy(buf, "  rval = db->fetch(db, query, bs);\n");
      acopy(buf, "  if(!rval || db->error || _yadac_push(yc, query, bs))\n");
      acopy(buf, "    {\n    db->free(db, query);\n    db->free(db, bs);\n");
      acopy(buf, "    return(db->error ? -1 : 1);\n    }\n\n");

      acopy(buf, "  return(0);\n}\n\n");
      break;
    /************************************************/
    case(YADAC_MULTIROW):
    /************************************************/
      aprintf(buf, "/** %s (MULTIROW operation)\n", binding->name);
      acopy(buf, " * @return 0 on success, -1 on error\n */\n\n");
      aprintf(buf, "int %s_%s(yadac_t *yc", prefix, binding->name);
      aiproto(buf, binding);
      for(idx=0; idx<binding->oparams; idx++)
        {
        acopy(buf, ", ");
        if(binding->oparam[idx] == YADAC_STRING)
          ayadavar(buf, binding->oparam[idx], "out");
        else
          ayadavar(buf, binding->oparam[idx], "*out");
        aprintf(buf, "%u", (idx + 1));
        }
      acopy(buf, ")\n{\n");
      acopy(buf, "  yada_t *db;\n  yada_rc_t *bs, *query;\n\n\n");

      /* make sure yadac instance was specified */
      acopy(buf, "  if(!yc)\n    yc = yadac;\n");
      acopy(buf, "  db = yc->db;\n\n");

      acopy(buf, "  /* bind output variables */\n");
      acopy(buf, "  if(!(bs = db->bind(db, \"");
      ayadatypes(buf, binding->oparam, binding->oparams);
      acopy(buf, "\"");
      for(idx=0; idx<binding->oparams; idx++)
        aprintf(buf, ", out%u", (idx + 1));
      acopy(buf, ")))\n    return(-1);\n\n");

      acopy(buf, "  /* perform query */\n");
      aprintf(buf, "  if(!(query = db->query(db, stmt_%s", binding->name);
      aivars(buf, binding);
      acopy(buf, ")))\n    {\n");
      acopy(buf, "    db->free(db, bs);\n");
      acopy(buf, "    return(-1);\n    }\n\n");

      acopy(buf, "  if(_yadac_push(yc, query, bs))\n");
      acopy(buf, "    {\n    db->free(db, query);\n    db->free(db, bs);\n");
      acopy(buf, "    return(-1);\n    }\n\n");

      acopy(buf, "  return(0);\n}\n\n");

      acopy(buf, "/*******************************************************");
      acopy(buf, "***********************/\n");
      aprintf(buf, "/** %s (MULTIROW operation) fetch routine\n",
       binding->name);
      acopy(buf, " * @return 0 on completion, 1 if incomplete, "\
       "-1 on error\n */\n\n");
      aprintf(buf, "int %s_%s_fetch(yadac_t *yc)\n{\n",
       prefix, binding->name);

      /* make sure yadac instance was specified */
      acopy(buf, "  if(!yc)\n    yc = yadac;\n\n");

      acopy(buf, "  /* fetch result */\n");
      acopy(buf, "  if(yc->db->fetch(yc->db, ");
      acopy(buf, "yc->rc[yc->rcs - 2], yc->rc[yc->rcs - 1]))\n");
      acopy(buf, "    return(1);\n\n");

      acopy(buf, "  /* check for errors */\n");
      acopy(buf, "  return(yc->db->error ? -1 : 0);\n}\n\n");
      break;
    /************************************************/
    case(YADAC_MULTISTRUCT):
    /************************************************/
      aprintf(buf, "/** %s (%s MULTISTRUCT operation)\n", binding->name,
       binding->ostruct->type);
      acopy(buf, " * @return 0 on success, -1 on error, 1 no results\n */\n\n");
      aprintf(buf, "int %s_%s(yadac_t *yc", prefix, binding->name);
      aiproto(buf, binding);
      aprintf(buf, ", %s *out)\n{\n", binding->ostruct->type);
      acopy(buf, "  yada_t *db;\n  yada_rc_t *bs, *query;\n\n\n");

      /* make sure yadac instance was specified */
      acopy(buf, "  if(!yc)\n    yc = yadac;\n");
      acopy(buf, "  db = yc->db;\n\n");

      acopy(buf, "  /* bind output variables */\n");
      acopy(buf, "  if(!(bs = db->bind(db, \"");
      ayadatypes(buf, binding->oparam, binding->oparams);
      acopy(buf, "\"");
      for(idx=0; idx<binding->ostruct->list->tokens; idx++)
        if(*binding->ostruct->list->token[idx] < 0x2b)
          aprintf(buf, ", %cout->%s", binding->ostruct->list->token[idx][0],
           &binding->ostruct->list->token[idx][1]);
        else
          aprintf(buf, ", out->%s", binding->ostruct->list->token[idx]);
      acopy(buf, ")))\n    return(-1);\n\n");

      acopy(buf, "  /* perform query */\n");
      aprintf(buf, "  if(!(query = db->query(db, stmt_%s", binding->name);
      aivars(buf, binding);
      acopy(buf, ")))\n    {\n");
      acopy(buf, "    db->free(db, bs);\n");
      acopy(buf, "    return(-1);\n");
      acopy(buf, "    }\n\n");

      acopy(buf, "  if(_yadac_push(yc, query, bs))\n");
      acopy(buf, "    {\n    db->free(db, query);\n    db->free(db, bs);\n");
      acopy(buf, "    return(-1);\n    }\n\n");

      acopy(buf, "  return(0);\n}\n\n");

      acopy(buf, "/*******************************************************");
      acopy(buf, "***********************/\n");
      aprintf(buf, "/** %s (MULTISTRUCT operation) fetch routine\n",
       binding->name);
      acopy(buf, " * @return 0 on completion, 1 if incomplete, "\
       "-1 on error\n */\n\n");
      aprintf(buf, "int %s_%s_fetch(yadac_t *yc)\n{\n", prefix, binding->name);

      /* make sure yadac instance was specified */
      acopy(buf, "  if(!yc)\n    yc = yadac;\n\n");

      acopy(buf, "  /* fetch result */\n");
      acopy(buf, "  if(yc->db->fetch(yc->db, ");
      acopy(buf, "yc->rc[yc->rcs - 2], yc->rc[yc->rcs - 1]))\n");
      acopy(buf, "    return(1);\n\n");

      acopy(buf, "  /* check for errors */\n");
      acopy(buf, "  return(yc->db->error ? -1 : 0);\n}\n\n");

      break;
    /************************************************/
      } /* switch(rtype) */
    } /* foreach(binding) */

  acopy(buf, "/*********************************************************");
  acopy(buf, "*********************\n **********************************");
  acopy(buf, "********************************************/\n\n");

  /* check if any errors occured */
  if(buf->errs)
    {
    free(buf->ptr);
    free(buf);
    return(NULL);
    }

  /* set size if needed */
  if(siz)
    *siz = buf->siz;

  /* shrink and return buffer */
  ptr = realloc(buf->ptr, buf->siz);
  free(buf);
  return(ptr);
}