#include <assert.h>
#include <string.h>
#include <yafl_usr.h>
#include <yafl_rnt.h>


/*********************************************************/
obj_ptr univ_clone YPARAMS2(obj_ptr,p)
{
  obj_ptr q;
  header *hea;
  unsigned a_size, a_level;

  if (!p)
    {
      yafl_err(YERR_BAD_CLONE);
      dump_trace();
      exit(1);
    }
  hea = HEADER(p);         
  a_size = HEADER_ARRAY_SIZE(hea);
  a_level = HEADER_ARRAY_LEVEL(hea);
  q = y_alloc((YINT)a_size, a_level, hea->dual);
  memcpy (q, p, alloc_size(a_size, a_level, hea->dual));
  if (a_level == 0)
    (*hea->dual->clone_func)(q,p);
  return q;
}
/*********************************************************/
obj_ptr univ_slice YPARAMS6(obj_ptr, p, YINT, from, YINT, len)
{
  obj_ptr q;
  char *ptr, a[200];
  int    el_size;
  unsigned a_size, a_level;
  header *hea;

  if (!p)
    {
      yafl_err(YERR_VOID_ARR);
      dump_trace();
      exit(1);
    }         
  hea = HEADER(p);
  a_level = HEADER_ARRAY_LEVEL(hea);
  a_size = HEADER_ARRAY_SIZE(hea);
  
  assert (a_level);
  q = y_alloc(len, a_level, hea->dual);
  if (len + from > a_size)
    len = a_size - from;
  el_size = element_size(a_level, hea->dual);
  ptr = (char *) p + el_size * from;
  if (el_size * len > alloc_size((int)len, a_level, hea->dual))
    {
      sprintf (a, "%d * %d  = %d     alloc_size = %d\n",
                el_size, len, el_size*len, alloc_size(len, a_level, 
                                                      hea->dual));
      emit_stdout(a);                
      assert(0);
    }
  memcpy (q, ptr, el_size * len);
  return q;
}
/*********************************************************/
obj_ptr univ_concat YPARAMS4(obj_ptr,p,obj_ptr,q)
{
  header *h1, *h2;
  obj_ptr res;
  int size, first_size;          
  unsigned size_1, size_2, a_level;

  if (!p)
    return q;
  if (!q)
    return p;
  h1 = HEADER(p);
  h2 = HEADER(q);
  size_1 = HEADER_ARRAY_SIZE(h1);
  size_2 = HEADER_ARRAY_SIZE(h2);
  a_level = HEADER_ARRAY_LEVEL(h1);
  res = y_alloc(size_1 + size_2, a_level, h1->dual);
  size = element_size(a_level, h1->dual);
  first_size = size * size_1;
  memcpy (res, p, first_size);
  memcpy (((char *)res) + first_size, q, size * size_2);
  return res;
}

/*********************************************************/
obj_ptr univ_concat3 YPARAMS6(obj_ptr,p,obj_ptr,q,obj_ptr,r)
{
  header *h1, *h2, *h3;
  obj_ptr res;
  int size, first_size;
  unsigned size_1, size_2, size_3, a_level;

  if (!p)
    return univ_concat(q,r);
  if (!q)
    return univ_concat(p,r);
  if (!r)  
    return univ_concat(p,q);
  h1 = HEADER(p);
  h2 = HEADER(q);
  h3 = HEADER(r);
  size_1 = HEADER_ARRAY_SIZE(h1);
  size_2 = HEADER_ARRAY_SIZE(h2);
  size_3 = HEADER_ARRAY_SIZE(h3);
  a_level = HEADER_ARRAY_LEVEL(h1);
  res = y_alloc(size_1 + size_2 + size_3, a_level, h1->dual);
  size = element_size(a_level, h1->dual);
  first_size = size * size_1;
  memcpy (res, p, first_size);
  memcpy (((char *)res) + first_size, q, size * size_2);
  first_size += size * size_2;
  memcpy (((char *)res) + first_size, r, size * size_3);
  return res;
}

/*********************************************************/
obj_ptr univ_concat4 YPARAMS8(obj_ptr,p,obj_ptr,q,obj_ptr,r,obj_ptr,s)
{
  header *h1, *h2, *h3, *h4;
  obj_ptr res;
  int size, first_size;
  unsigned size_1, size_2, size_3, size_4, a_level;

  if (!p)
    return univ_concat3(q,r,s);
  if (!q)
    return univ_concat3(p,r,s);
  if (!r)  
    return univ_concat3(p,q,s);
  if (!s)  
    return univ_concat3(p,q,r);
  h1 = HEADER(p);
  h2 = HEADER(q);
  h3 = HEADER(r);
  h4 = HEADER(s);
  size_1 = HEADER_ARRAY_SIZE(h1);
  size_2 = HEADER_ARRAY_SIZE(h2);
  size_3 = HEADER_ARRAY_SIZE(h3);
  size_4 = HEADER_ARRAY_SIZE(h4);
  a_level = HEADER_ARRAY_LEVEL(h1);
  res = y_alloc(size_1 + size_2 + size_3 + size_4, a_level, h1->dual);
  size = element_size(a_level, h1->dual);
  first_size = size * size_1;
  memcpy (res, p, first_size);
  memcpy (((char *)res) + first_size, q, size * size_2);
  first_size += size * size_2;
  memcpy (((char *)res) + first_size, r, size * size_3);
  first_size += size * size_3;
  memcpy (((char *)res) + first_size, s, size * size_4);
  return res;
}

/*********************************************************/
obj_ptr univ_concat5 YPARAMS10(obj_ptr,p,obj_ptr,q,obj_ptr,r,obj_ptr,s,
                              obj_ptr,t)
{
  header *h1, *h2, *h3, *h4, *h5;
  obj_ptr res;
  int size, first_size;
  unsigned size_1, size_2, size_3, size_4, size_5, a_level;

  if (!p)
    return univ_concat4(q,r,s,t);
  if (!q)
    return univ_concat4(p,r,s,t);
  if (!r)  
    return univ_concat4(p,q,s,t);
  if (!s)  
    return univ_concat4(p,q,r,t);
  if (!t)  
    return univ_concat4(p,q,r,s);
  h1 = HEADER(p);
  h2 = HEADER(q);
  h3 = HEADER(r);
  h4 = HEADER(s);
  h5 = HEADER(t);
  size_1 = HEADER_ARRAY_SIZE(h1);
  size_2 = HEADER_ARRAY_SIZE(h2);
  size_3 = HEADER_ARRAY_SIZE(h3);
  size_4 = HEADER_ARRAY_SIZE(h4);
  size_5 = HEADER_ARRAY_SIZE(h5);
  a_level = HEADER_ARRAY_LEVEL(h1);
  res = y_alloc(size_1 + size_2 + size_3 + size_4 + size_5, a_level, h1->dual);
  size = element_size(a_level, h1->dual);
  first_size = size * size_1;
  memcpy (res, p, first_size);
  memcpy (((char *)res) + first_size, q, size * size_2);
  first_size += size * size_2;
  memcpy (((char *)res) + first_size, r, size * size_3);
  first_size += size * size_3;
  memcpy (((char *)res) + first_size, s, size * size_4);
  first_size += size * size_4;
  memcpy (((char *)res) + first_size, t, size * size_5);
  return res;
}

/**************************************************/
void default_clone YPARAMS4(obj_ptr,p,obj_ptr,q)
{
}

