Skip to content
Snippets Groups Projects
record_of.c 206 KiB
Newer Older
Elemer Lelik's avatar
Elemer Lelik committed
/******************************************************************************
 * Copyright (c) 2000-2021 Ericsson Telecom AB
Elemer Lelik's avatar
Elemer Lelik committed
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v2.0
Elemer Lelik's avatar
Elemer Lelik committed
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
Elemer Lelik's avatar
Elemer Lelik committed
 *
 * Contributors:
 *   Baji, Laszlo
 *   Balasko, Jeno
 *   Baranyi, Botond
 *   Beres, Szabolcs
 *   Delic, Adam
 *   Forstner, Matyas
 *   Kovacs, Ferenc
 *   Raduly, Csaba
 *   Szabados, Kristof
 *   Szabo, Bence Janos
 *   Szabo, Janos Zoltan – initial implementation
 *   Szalai, Gabor
 *   Zalanyi, Balazs Andor
 *
 ******************************************************************************/
#include "../common/memory.h"
#include "datatypes.h"
#include "record_of.h"
#include "encdec.h"

#include "main.hh"
#include "ttcn3/compiler.h"

/** code generation for original runtime */
static void defRecordOfClass1(const struct_of_def *sdef, output_struct *output);
static void defRecordOfTemplate1(const struct_of_def *sdef, output_struct *output);
/** code generation for alternative runtime (TITAN_RUNTIME_2) */
static void defRecordOfClass2(const struct_of_def *sdef, output_struct *output);
static void defRecordOfTemplate2(const struct_of_def *sdef, output_struct *output);

void defRecordOfClass(const struct_of_def *sdef, output_struct *output)
{
  if (use_runtime_2) defRecordOfClass2(sdef, output);
  else defRecordOfClass1(sdef, output);
}

void defRecordOfTemplate(const struct_of_def *sdef, output_struct *output)
{
  if (use_runtime_2) defRecordOfTemplate2(sdef, output);
  else defRecordOfTemplate1(sdef, output);
}

/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */

void defRecordOfClass1(const struct_of_def *sdef, output_struct *output)
{
  char *def = NULL, *src = NULL;
  const char *name = sdef->name, *dispname = sdef->dispname;
  const char *type = sdef->type;
Elemer Lelik's avatar
Elemer Lelik committed
  boolean ber_needed = force_gen_seof || (sdef->isASN1 && enable_ber());
  boolean raw_needed = force_gen_seof || (sdef->hasRaw && enable_raw());
  boolean text_needed = force_gen_seof || (sdef->hasText && enable_text());
  boolean xer_needed = force_gen_seof || (sdef->hasXer && enable_xer());
  boolean json_needed = force_gen_seof || (sdef->hasJson && enable_json());
  boolean oer_needed = force_gen_seof || (sdef->hasOer && enable_oer());

  /* Class definition and private data members */
  def = mputprintf(def,
#ifndef NDEBUG
    "// written by %s in " __FILE__ " at %d\n"
#endif
    "class %s : public Base_Type {\n"
    "struct recordof_setof_struct {\n"
    "int ref_count;\n"
    "int n_elements;\n"
    "%s **value_elements;\n"
    "} *val_ptr;\n"
#ifndef NDEBUG
      , __FUNCTION__, __LINE__
#endif
    , name, type);

  /* constant unbound element */
  def = mputprintf(def, "\nstatic const %s UNBOUND_ELEM;\n", type);
  src = mputprintf(src, "\nconst %s %s::UNBOUND_ELEM;\n", type, name);

  /* private member functions */
  def = mputprintf(def,
    "private:\n"
    "friend boolean operator==(null_type null_value, "
	  "const %s& other_value);\n", name);

  if (sdef->kind == SET_OF) {
    /* callback function for comparison */
    def = mputstr(def, "static boolean compare_function("
	"const Base_Type *left_ptr, int left_index, "
        "const Base_Type *right_ptr, int right_index);\n");
    src = mputprintf(src, "boolean %s::compare_function("
	"const Base_Type *left_ptr, int left_index, "
        "const Base_Type *right_ptr, int right_index)\n"
        "{\n"
        "if (((const %s*)left_ptr)->val_ptr == NULL) "
        "TTCN_error(\"The left operand of comparison is an unbound value of "
        "type %s.\");\n"
        "if (((const %s*)right_ptr)->val_ptr == NULL) "
        "TTCN_error(\"The right operand of comparison is an unbound value of "
        "type %s.\");\n"
        "if (((const %s*)left_ptr)->val_ptr->value_elements[left_index] != NULL){\n"
        "if (((const %s*)right_ptr)->val_ptr->value_elements[right_index] != NULL){\n"
        "return *((const %s*)left_ptr)->val_ptr->value_elements[left_index] == "
        "*((const %s*)right_ptr)->val_ptr->value_elements[right_index];\n"
        "} else return FALSE;\n"
        "} else {\n"
        "return ((const %s*)right_ptr)->val_ptr->value_elements[right_index] == NULL;\n"
        "}\n"
        "}\n\n", name, name, dispname, name, dispname, name, name, name, name, name);
  }

  /* public member functions */
  def = mputstr(def, "\npublic:\n");
  def = mputprintf(def, "  typedef %s of_type;\n", sdef->type);

  /* constructors */
  def = mputprintf(def, "%s();\n", name);
  src = mputprintf(src,
    "%s::%s()\n"
    "{\n"
    "val_ptr = NULL;\n"
    "}\n\n", name, name);

  def = mputprintf(def, "%s(null_type other_value);\n", name);
  src = mputprintf(src,
    "%s::%s(null_type)\n"
    "{\n"
    "val_ptr = new recordof_setof_struct;\n"
    "val_ptr->ref_count = 1;\n"
    "val_ptr->n_elements = 0;\n"
    "val_ptr->value_elements = NULL;\n"
    "}\n\n", name, name);

  /* copy constructor */
  def = mputprintf(def, "%s(const %s& other_value);\n", name, name);
  src = mputprintf(src,
     "%s::%s(const %s& other_value)\n"
     "{\n"
     "if (!other_value.is_bound()) "
     "TTCN_error(\"Copying an unbound value of type %s.\");\n"
     "val_ptr = other_value.val_ptr;\n"
     "val_ptr->ref_count++;\n"
Elemer Lelik's avatar
Elemer Lelik committed
     "}\n\n", name, name, name, dispname);

  /* destructor */
  def = mputprintf(def, "~%s();\n\n", name);
  src = mputprintf(src,
    "%s::~%s()\n"
    "{\n"
    "clean_up();\n"
    "if (val_ptr != NULL) val_ptr = NULL;\n"
    "}\n\n", name, name);

  /* clean_up function */
  def = mputstr(def, "void clean_up();\n");
  src = mputprintf
    (src,
     "void %s::clean_up()\n"
     "{\n"
     "if (val_ptr != NULL) {\n"
     "if (val_ptr->ref_count > 1) {\n"
     "val_ptr->ref_count--;\n"
     "val_ptr = NULL;\n"
     "}\n"
     "else if (val_ptr->ref_count == 1) {\n"
     "for (int elem_count = 0; elem_count < val_ptr->n_elements;\n"
     "elem_count++)\n"
     "if (val_ptr->value_elements[elem_count] != NULL)\n"
     "delete val_ptr->value_elements[elem_count];\n"
     "free_pointers((void**)val_ptr->value_elements);\n"
     "delete val_ptr;\n"
     "val_ptr = NULL;\n"
     "}\n"
     "else\n"
     "TTCN_error(\"Internal error: Invalid reference counter in a record "
     "of/set of value.\");\n"
     "}\n"
     "}\n\n", name);

  /* assignment operators */
  def = mputprintf(def, "%s& operator=(null_type other_value);\n", name);
  src = mputprintf(src,
    "%s& %s::operator=(null_type)\n"
    "{\n"
Elemer Lelik's avatar
Elemer Lelik committed
    "clean_up();\n"
    "val_ptr = new recordof_setof_struct;\n"
    "val_ptr->ref_count = 1;\n"
    "val_ptr->n_elements = 0;\n"
    "val_ptr->value_elements = NULL;\n"
    "return *this;\n"
    "}\n\n", name, name);

  def = mputprintf(def, "%s& operator=(const %s& other_value);\n\n",
                   name, name);
  src = mputprintf(src,
    "%s& %s::operator=(const %s& other_value)\n"
    "{\n"
Elemer Lelik's avatar
Elemer Lelik committed
    "if (other_value.val_ptr == NULL) "
    "TTCN_error(\"Assigning an unbound value of type %s.\");\n"
    "if (this != &other_value) {\n"
    "clean_up();\n"
    "val_ptr = other_value.val_ptr;\n"
    "val_ptr->ref_count++;\n"
    "}\n"
    "return *this;\n"
Elemer Lelik's avatar
Elemer Lelik committed
    "}\n\n", name, name, name, dispname);

  /* comparison operators */
  def = mputstr(def, "boolean operator==(null_type other_value) const;\n");
  src = mputprintf(src,
    "boolean %s::operator==(null_type) const\n"
    "{\n"
    "if (val_ptr == NULL)\n"
    "TTCN_error(\"The left operand of comparison is an unbound value of "
    "type %s.\");\n"
Elemer Lelik's avatar
Elemer Lelik committed
    "return val_ptr->n_elements == 0 ;\n"
    "}\n\n", name, dispname);

  def = mputprintf(def, "boolean operator==(const %s& other_value) const;\n",
                   name);
  src = mputprintf(src,
    "boolean %s::operator==(const %s& other_value) const\n"
    "{\n"
    "if (val_ptr == NULL) "
    "TTCN_error(\"The left operand of comparison is an unbound value of type "
    "%s.\");\n"
    "if (other_value.val_ptr == NULL) "
    "TTCN_error(\"The right operand of comparison is an unbound value of type "
    "%s.\");\n"
    "if (val_ptr == other_value.val_ptr) return TRUE;\n", name, name,
    dispname, dispname);
  if (sdef->kind == SET_OF) {
    src = mputstr(src,
Elemer Lelik's avatar
Elemer Lelik committed
       "return compare_set_of(this, val_ptr->n_elements, &other_value, "
       "(other_value.val_ptr)->n_elements, compare_function);\n");
  } else {
    src = mputstr
      (src,
Elemer Lelik's avatar
Elemer Lelik committed
       "if (val_ptr->n_elements != (other_value.val_ptr)->n_elements)\n"
       "return FALSE;\n"
Elemer Lelik's avatar
Elemer Lelik committed
       "for (int elem_count = 0; elem_count < val_ptr->n_elements; elem_count++){\n"
       "if (val_ptr->value_elements[elem_count] != NULL){\n"
       "if ((other_value.val_ptr)->value_elements[elem_count] != NULL){\n"
       "  if (*val_ptr->value_elements[elem_count] != "
          "*(other_value.val_ptr)->value_elements[elem_count]) "
          "return FALSE;\n"
       "} else return FALSE;\n"
       "} else {\n"
Elemer Lelik's avatar
Elemer Lelik committed
       "if ((other_value.val_ptr)->value_elements[elem_count] != NULL) "
         "return FALSE;\n"
       "}\n"
       "}\n"
       "return TRUE;\n");
  }
  src = mputstr(src, "}\n\n");

  def = mputstr(def, "inline boolean operator!=(null_type other_value) const "
                "{ return !(*this == other_value); }\n");
  def = mputprintf(def, "inline boolean operator!=(const %s& other_value) "
                   "const { return !(*this == other_value); }\n\n", name);

  /* indexing operators */
  /* Non-const operator[] is allowed to extend the record-of */
  def = mputprintf(def, "%s& operator[](int index_value);\n", type);
  src = mputprintf(src,
    "%s& %s::operator[](int index_value)\n"
    "{\n"
    "if (index_value < 0) TTCN_error(\"Accessing an element of type %s "
    "using a negative index: %%d.\", index_value);\n"
    "if (val_ptr == NULL) {\n"
    "val_ptr = new recordof_setof_struct;\n"
    "val_ptr->ref_count = 1;\n"
    "val_ptr->n_elements = 0;\n"
    "val_ptr->value_elements = NULL;\n"
    "} else if (val_ptr->ref_count > 1) {\n" /* copy-on-write */
    "struct recordof_setof_struct *new_val_ptr = new recordof_setof_struct;\n"
    "new_val_ptr->ref_count = 1;\n"
    "new_val_ptr->n_elements = (index_value >= val_ptr->n_elements) ? "
    "index_value + 1 : val_ptr->n_elements;\n"
    "new_val_ptr->value_elements = "
    "(%s**)allocate_pointers(new_val_ptr->n_elements);\n"
    "for (int elem_count = 0; elem_count < val_ptr->n_elements; "
    "elem_count++){\n"
    "if (val_ptr->value_elements[elem_count] != NULL){\n"
    "new_val_ptr->value_elements[elem_count] = "
    "new %s(*(val_ptr->value_elements[elem_count]));\n"
    "}\n"
    "}\n"
    "clean_up();\n"
    "val_ptr = new_val_ptr;\n"
    "}\n"
    "if (index_value >= val_ptr->n_elements) set_size(index_value + 1);\n"
    "if (val_ptr->value_elements[index_value] == NULL) {\n"
    "val_ptr->value_elements[index_value] = new %s;\n"
    "}\n"
    "return *val_ptr->value_elements[index_value];\n"
    "}\n\n", type, name, dispname, type, type, type);

  def = mputprintf(def, "%s& operator[](const INTEGER& index_value);\n",
                   type);
  src = mputprintf(src,
    "%s& %s::operator[](const INTEGER& index_value)\n"
    "{\n"
    "index_value.must_bound(\"Using an unbound integer value for indexing "
    "a value of type %s.\");\n"
    "return (*this)[(int)index_value];\n"
    "}\n\n", type, name, dispname);

  /* Const operator[] throws an error if over-indexing */
  def = mputprintf(def, "const %s& operator[](int index_value) const;\n",
                   type);
  src = mputprintf(src,
    "const %s& %s::operator[](int index_value) const\n"
    "{\n"
    "if (val_ptr == NULL)\n"
    "TTCN_error(\"Accessing an element in an unbound value of type %s.\");\n"
    "if (index_value < 0) TTCN_error(\"Accessing an element of type %s "
    "using a negative index: %%d.\", index_value);\n"
Elemer Lelik's avatar
Elemer Lelik committed
    "if (index_value >= val_ptr->n_elements) TTCN_error(\"Index overflow in "
    "a value of type %s: The index is %%d, but the value has only %%d "
Elemer Lelik's avatar
Elemer Lelik committed
    "elements.\", index_value, val_ptr->n_elements);\n"
Kristof Szabados's avatar
Kristof Szabados committed
    "return (val_ptr->value_elements[index_value] == NULL) ?\n"
    "UNBOUND_ELEM : *val_ptr->value_elements[index_value];\n"
    "}\n\n", type, name, dispname, dispname, dispname);

  def = mputprintf(def, "const %s& operator[](const INTEGER& index_value) "
                   "const;\n\n", type);
  src = mputprintf(src,
    "const %s& %s::operator[](const INTEGER& index_value) const\n"
    "{\n"
    "index_value.must_bound(\"Using an unbound integer value for indexing "
    "a value of type %s.\");\n"
    "return (*this)[(int)index_value];\n"
    "}\n\n", type, name, dispname);

  /* rotation operators */
  def = mputprintf(def,
    "%s operator<<=(int rotate_count) const;\n"
    "%s operator<<=(const INTEGER& rotate_count) const;\n"
    "%s operator>>=(int rotate_count) const;\n"
    "%s operator>>=(const INTEGER& rotate_count) const;\n\n",
    name, name, name, name);
  src = mputprintf(src,
    "%s %s::operator<<=(int rotate_count) const\n"
    "{\n"
    "return *this >>= (-rotate_count);\n"
    "}\n\n"
    "%s %s::operator<<=(const INTEGER& rotate_count) const\n"
    "{\n"
    "rotate_count.must_bound(\""
    "Unbound integer operand of rotate left operator.\");\n"
    "return *this >>= (int)(-rotate_count);\n"
    "}\n\n"
    "%s %s::operator>>=(const INTEGER& rotate_count) const\n"
    "{\n"
    "rotate_count.must_bound(\""
    "Unbound integer operand of rotate right operator.\");\n"
    "return *this >>= (int)rotate_count;\n"
    "}\n\n"
    "%s %s::operator>>=(int rotate_count) const\n"
    "{\n"
    "if (val_ptr == NULL) "
    "TTCN_error(\"Performing rotation operation on an unbound value of type "
    "%s.\");\n"
Elemer Lelik's avatar
Elemer Lelik committed
    "if (val_ptr->n_elements == 0) return *this;\n"
    "int rc;\n"
Elemer Lelik's avatar
Elemer Lelik committed
    "if (rotate_count>=0) rc = rotate_count %% val_ptr->n_elements;\n"
    "else rc = val_ptr->n_elements - ((-rotate_count) %% val_ptr->n_elements);\n"
    "if (rc == 0) return *this;\n"
    "%s ret_val;\n"
Elemer Lelik's avatar
Elemer Lelik committed
    "ret_val.set_size(val_ptr->n_elements);\n"
    "for (int i=0; i<val_ptr->n_elements; i++) {\n"
    "if (val_ptr->value_elements[i] != NULL) {\n"
    "ret_val.val_ptr->value_elements[(i+rc)%%val_ptr->n_elements] ="
      "new %s(*val_ptr->value_elements[i]);\n"
    "}\n"
    "}\n"
    "return ret_val;\n"
    "}\n\n",
    name, name, name, name, name, name, name, name, dispname, name, type);

  /* concatenation */
  def = mputprintf(def,
    "%s operator+(const %s& other_value) const;\n\n", name, name);
  src = mputprintf(src,
    "%s %s::operator+(const %s& other_value) const\n"
    "{\n"
    "if (val_ptr == NULL || other_value.val_ptr == NULL) "
      "TTCN_error(\"Unbound operand of %s concatenation.\");\n"
Elemer Lelik's avatar
Elemer Lelik committed
    "if (val_ptr->n_elements == 0) return other_value;\n"
    "if (other_value.val_ptr->n_elements == 0) return *this;\n"
    "%s ret_val;\n"
Elemer Lelik's avatar
Elemer Lelik committed
    "ret_val.set_size(val_ptr->n_elements+other_value.val_ptr->n_elements);\n"
    "for (int i=0; i<val_ptr->n_elements; i++) {\n"
    "if (val_ptr->value_elements[i] != NULL) {\n"
    "ret_val.val_ptr->value_elements[i] = new %s(*val_ptr->value_elements[i]);\n"
    "}\n"
    "}\n"
Elemer Lelik's avatar
Elemer Lelik committed
    "for (int i=0; i<other_value.val_ptr->n_elements; i++) {\n"
    "if (other_value.val_ptr->value_elements[i] != NULL) {\n"
    "ret_val.val_ptr->value_elements[i+val_ptr->n_elements] = "
    "new %s(*other_value.val_ptr->value_elements[i]);\n"
    "}\n"
    "}\n"
    "return ret_val;\n"
    "}\n\n", name, name, name, dispname, name, type, type);

  /* substr() */
  def = mputprintf(def,
    "%s substr(int index, int returncount) const;\n\n", name);
  src = mputprintf(src,
    "%s %s::substr(int index, int returncount) const\n"
    "{\n"
    "if (val_ptr == NULL) "
      "TTCN_error(\"The first argument of substr() is an unbound value of "
        "type %s.\");\n"
Elemer Lelik's avatar
Elemer Lelik committed
    "check_substr_arguments(val_ptr->n_elements, index, returncount, "
      "\"%s\",\"element\");\n"
    "%s ret_val;\n"
    "ret_val.set_size(returncount);\n"
    "for (int i=0; i<returncount; i++) {\n"
Elemer Lelik's avatar
Elemer Lelik committed
    "if (val_ptr->value_elements[i+index] != NULL) {\n"
    "ret_val.val_ptr->value_elements[i] = "
    "new %s(*val_ptr->value_elements[i+index]);\n"
    "}\n"
    "}\n"
    "return ret_val;\n"
    "}\n\n", name, name, dispname, dispname, name, type);

  /* replace() */
  def = mputprintf(def,
    "%s replace(int index, int len, const %s& repl) const;\n\n", name, name);
  src = mputprintf(src,
    "%s %s::replace(int index, int len, const %s& repl) const\n"
    "{\n"
    "if (val_ptr == NULL) "
      "TTCN_error(\"The first argument of replace() is an unbound value of "
        "type %s.\");\n"
    "if (repl.val_ptr == NULL) "
      "TTCN_error(\"The fourth argument of replace() is an unbound value of "
        "type %s.\");\n"
Elemer Lelik's avatar
Elemer Lelik committed
    "check_replace_arguments(val_ptr->n_elements, index, len, "
      "\"%s\",\"element\");\n"
    "%s ret_val;\n"
Elemer Lelik's avatar
Elemer Lelik committed
    "ret_val.set_size(val_ptr->n_elements + repl.val_ptr->n_elements - len);\n"
    "for (int i = 0; i < index; i++) {\n"
Elemer Lelik's avatar
Elemer Lelik committed
    "if (val_ptr->value_elements[i] != NULL) {\n"
    "ret_val.val_ptr->value_elements[i] = new %s(*val_ptr->value_elements[i]);\n"
    "}\n"
    "}\n"
Elemer Lelik's avatar
Elemer Lelik committed
    "for (int i = 0; i < repl.val_ptr->n_elements; i++) {\n"
    "if (repl.val_ptr->value_elements[i] != NULL) {\n"
    "ret_val.val_ptr->value_elements[i+index] = "
    "new %s(*repl.val_ptr->value_elements[i]);\n"
    "}\n"
    "}\n"
Elemer Lelik's avatar
Elemer Lelik committed
    "for (int i = 0; i < val_ptr->n_elements - index - len; i++) {\n"
    "if (val_ptr->value_elements[index+i+len] != NULL) {\n"
    "ret_val.val_ptr->value_elements[index+i+repl.val_ptr->n_elements] = "
    "new %s(*val_ptr->value_elements[index+i+len]);\n"
    "}\n"
    "}\n"
    "return ret_val;\n"
  "}\n\n", name, name, name, dispname, dispname, dispname, name, type, type, type);
  def = mputprintf(def,
    "%s replace(int index, int len, const %s_template& repl) const;\n\n",
    name, name);
  src = mputprintf(src,
    "%s %s::replace(int index, int len, const %s_template& repl) const\n"
    "{\n"
    "if (!repl.is_value()) TTCN_error(\"The fourth argument of function "
      "replace() is a template with non-specific value.\");\n"
    "return replace(index, len, repl.valueof());\n"
    "}\n\n", name, name, name);

  /* set_size function */
  def = mputstr(def, "void set_size(int new_size);\n");
  src = mputprintf(src, "void %s::set_size(int new_size)\n"
    "{\n"
    "if (new_size < 0) TTCN_error(\"Internal error: Setting a negative size "
      "for a value of type %s.\");\n"
    "if (val_ptr == NULL) {\n"
    "val_ptr = new recordof_setof_struct;\n"
    "val_ptr->ref_count = 1;\n"
    "val_ptr->n_elements = 0;\n"
    "val_ptr->value_elements = NULL;\n"
    "} else if (val_ptr->ref_count > 1) {\n" /* copy-on-write */
    "struct recordof_setof_struct *new_val_ptr = new recordof_setof_struct;\n"
    "new_val_ptr->ref_count = 1;\n"
    "new_val_ptr->n_elements = (new_size < val_ptr->n_elements) ? "
    "new_size : val_ptr->n_elements;\n"
    "new_val_ptr->value_elements = "
    "(%s**)allocate_pointers(new_val_ptr->n_elements);\n"
    "for (int elem_count = 0; elem_count < new_val_ptr->n_elements; "
    "elem_count++) {\n"
    "if (val_ptr->value_elements[elem_count] != NULL){\n"
    "new_val_ptr->value_elements[elem_count] = "
    "new %s(*(val_ptr->value_elements[elem_count]));\n"
    "}\n"
    "}\n"
    "clean_up();\n"
    "val_ptr = new_val_ptr;\n"
    "}\n"
    "if (new_size > val_ptr->n_elements) {\n"
    "val_ptr->value_elements = (%s**)"
    "reallocate_pointers((void**)val_ptr->value_elements, "
    "val_ptr->n_elements, new_size);\n"
    "#ifdef TITAN_MEMORY_DEBUG_SET_RECORD_OF\n"
    "if((val_ptr->n_elements/1000)!=(new_size/1000)) "
    "TTCN_warning(\"New size of type %s: %%d\",new_size);\n"
    "#endif\n"
    "val_ptr->n_elements = new_size;\n"
    "} else if (new_size < val_ptr->n_elements) {\n"
    "for (int elem_count = new_size; elem_count < val_ptr->n_elements; "
Elemer Lelik's avatar
Elemer Lelik committed
    "elem_count++)\n"
    "if (val_ptr->value_elements[elem_count] != NULL)"
    "delete val_ptr->value_elements[elem_count];\n"
    "val_ptr->value_elements = (%s**)"
    "reallocate_pointers((void**)val_ptr->value_elements, "
    "val_ptr->n_elements, new_size);\n"
    "val_ptr->n_elements = new_size;\n"
    "}\n"
    "}\n\n", name, dispname, type, type, type, dispname, type);

  /* is_bound function */
  def = mputstr(def,
Elemer Lelik's avatar
Elemer Lelik committed
    "inline boolean is_bound() const {return val_ptr != NULL; }\n");

  /* is_present function */
  def = mputstr(def,
    "inline boolean is_present() const { return is_bound(); }\n");

  /* is_value function */
  def = mputstr(def,
    "boolean is_value() const;\n");
  src = mputprintf(src,
    "boolean %s::is_value() const\n"
    "{\n"
    "if (val_ptr == NULL) return FALSE;\n"
Elemer Lelik's avatar
Elemer Lelik committed
    "for(int i = 0; i < val_ptr->n_elements; ++i) {\n"
    "if (val_ptr->value_elements[i] == NULL || "
    "!val_ptr->value_elements[i]->is_value()) return FALSE;\n"
    "}\n"
    "return TRUE;\n"
    "}\n\n", name);

  /* sizeof operation */
  def = mputstr(def,
    "int size_of() const;\n"
    "int n_elem() const { return size_of(); }\n");
  src = mputprintf(src,
    "int %s::size_of() const\n"
    "{\n"
    "if (val_ptr == NULL) "
    "TTCN_error(\"Performing sizeof operation on an unbound value of type "
    "%s.\");\n"
Elemer Lelik's avatar
Elemer Lelik committed
    "return val_ptr->n_elements;\n"
    "}\n\n", name, dispname);

  /* lengthof operation */
  def = mputstr(def, "int lengthof() const;\n");
  src = mputprintf(src,
    "int %s::lengthof() const\n"
    "{\n"
    "if (val_ptr == NULL) "
      "TTCN_error(\"Performing lengthof operation on an unbound value of type "
    "%s.\");\n"
Elemer Lelik's avatar
Elemer Lelik committed
    "for (int my_length=val_ptr->n_elements; my_length>0; my_length--) "
      "if (val_ptr->value_elements[my_length-1] != NULL) return my_length;\n"
    "return 0;\n"
    "}\n\n", name, dispname);

  /* log function */
  def = mputstr(def, "void log() const;\n");
  src = mputprintf
    (src,
     "void %s::log() const\n"
     "{\n"
     "if (val_ptr == NULL) {;\n"
     "TTCN_Logger::log_event_unbound();\n"
     "return;\n"
     "}\n"
Elemer Lelik's avatar
Elemer Lelik committed
     "switch (val_ptr->n_elements) {\n"
     "case 0:\n"
     "TTCN_Logger::log_event_str(\"{ }\");\n"
     "break;\n"
     "default:\n"
     "TTCN_Logger::log_event_str(\"{ \");\n"
Elemer Lelik's avatar
Elemer Lelik committed
     "for (int elem_count = 0; elem_count < val_ptr->n_elements; "
     "elem_count++) {\n"
     "if (elem_count > 0) TTCN_Logger::log_event_str(\", \");\n"
     "(*this)[elem_count].log();\n"
     "}\n"
     "TTCN_Logger::log_event_str(\" }\");\n"
     "}\n"
     "}\n\n", name);

  /* set_param function */
  def = mputstr(def, "void set_param(Module_Param& param);\n");
  src = mputprintf(src,
    "void %s::set_param(Module_Param& param)\n"
    "{\n"
    "  param.basic_check(Module_Param::BC_VALUE|Module_Param::BC_LIST, \"%s value\");\n"
    "  switch (param.get_operation_type()) {\n"
    "  case Module_Param::OT_ASSIGN:\n"
    "    if (param.get_type()==Module_Param::MP_Value_List && param.get_size()==0) {\n"
    "      *this = NULL_VALUE;\n"
    "      return;\n"
    "    }\n"
    "    switch (param.get_type()) {\n"
    "    case Module_Param::MP_Value_List:\n"
    "      set_size(param.get_size());\n"
    "      for (size_t i=0; i<param.get_size(); ++i) {\n"
    "        Module_Param* const curr = param.get_elem(i);\n"
    "        if (curr->get_type()!=Module_Param::MP_NotUsed) {\n"
    "          (*this)[i].set_param(*curr);\n"
    "          if (!(*this)[i].is_bound()) {\n"
    "            delete val_ptr->value_elements[i];\n"
    "            val_ptr->value_elements[i] = NULL;\n"
    "          }\n"
    "        }\n"
    "      }\n"
    "      break;\n"
    "    case Module_Param::MP_Indexed_List:\n"
    "      for (size_t i=0; i<param.get_size(); ++i) {\n"
    "        Module_Param* const curr = param.get_elem(i);\n"
    "        (*this)[curr->get_id()->get_index()].set_param(*curr);\n"
    "        if (!(*this)[curr->get_id()->get_index()].is_bound()) {\n"
    "          delete val_ptr->value_elements[curr->get_id()->get_index()];\n"
    "          val_ptr->value_elements[curr->get_id()->get_index()] = NULL;\n"
    "        }\n"
    "      }\n"
    "      break;\n"
    "    default:\n"
    "      param.type_error(\"%s value\", \"%s\");\n"
    "    }\n"
    "    break;\n"
    "  case Module_Param::OT_CONCAT:\n"
    "    switch (param.get_type()) {\n"
    "    case Module_Param::MP_Value_List: {\n"
    "      if (!is_bound()) *this = NULL_VALUE;\n"
    "      int start_idx = lengthof();\n"
    "      for (size_t i=0; i<param.get_size(); ++i) {\n"
    "        Module_Param* const curr = param.get_elem(i);\n"
    "        if ((curr->get_type()!=Module_Param::MP_NotUsed)) {\n"
    "          (*this)[start_idx+(int)i].set_param(*curr);\n"
    "        }\n"
    "      }\n"
    "    } break;\n"
    "    case Module_Param::MP_Indexed_List:\n"
    "      param.error(\"Cannot concatenate an indexed value list\");\n"
    "      break;\n"
    "    default:\n"
    "      param.type_error(\"%s value\", \"%s\");\n"
    "    }\n"
    "    break;\n"
    "  default:\n"
    "    TTCN_error(\"Internal error: Unknown operation type.\");\n"
    "  }\n"
Elemer Lelik's avatar
Elemer Lelik committed
    "}\n\n", name, sdef->kind == RECORD_OF ? "record of" : "set of",
    sdef->kind == RECORD_OF ? "record of" : "set of", dispname,
    sdef->kind == RECORD_OF ? "record of" : "set of", dispname);

  /* set implicit omit function, recursive */
  def = mputstr(def, "  void set_implicit_omit();\n");
  src = mputprintf(src,
    "void %s::set_implicit_omit()\n{\n"
    "if (val_ptr == NULL) return;\n"
Elemer Lelik's avatar
Elemer Lelik committed
    "for (int i = 0; i < val_ptr->n_elements; i++) {\n"
    "if (val_ptr->value_elements[i] != NULL) val_ptr->value_elements[i]->set_implicit_omit();\n"
    "}\n}\n\n", name);

  /* encoding / decoding functions */
  def = mputstr(def, "void encode_text(Text_Buf& text_buf) const;\n");
  src = mputprintf(src,
    "void %s::encode_text(Text_Buf& text_buf) const\n"
    "{\n"
    "if (val_ptr == NULL) "
    "TTCN_error(\"Text encoder: Encoding an unbound value of type %s.\");\n"
Elemer Lelik's avatar
Elemer Lelik committed
    "text_buf.push_int(val_ptr->n_elements);\n"
    "for (int elem_count = 0; elem_count < val_ptr->n_elements; "
    "elem_count++)\n"
    "(*this)[elem_count].encode_text(text_buf);\n"
    "}\n\n", name, dispname);

  def = mputstr(def, "void decode_text(Text_Buf& text_buf);\n");
  src = mputprintf(src,
    "void %s::decode_text(Text_Buf& text_buf)\n"
    "{\n"
Elemer Lelik's avatar
Elemer Lelik committed
    "clean_up();\n"
    "val_ptr = new recordof_setof_struct;\n"
    "val_ptr->ref_count = 1;\n"
    "val_ptr->n_elements = text_buf.pull_int().get_val();\n"
    "if (val_ptr->n_elements < 0) TTCN_error(\"Text decoder: Negative size "
    "was received for a value of type %s.\");\n"
Elemer Lelik's avatar
Elemer Lelik committed
    "val_ptr->value_elements = (%s**)allocate_pointers(val_ptr->n_elements);\n"
    "for (int elem_count = 0; elem_count < val_ptr->n_elements; "
    "elem_count++) {\n"
    "val_ptr->value_elements[elem_count] = new %s;\n"
    "val_ptr->value_elements[elem_count]->decode_text(text_buf);\n"
    "}\n"
Elemer Lelik's avatar
Elemer Lelik committed
    "}\n\n", name, dispname, type, type);
  if(ber_needed || raw_needed || text_needed || xer_needed || json_needed 
    || oer_needed) {
    def_encdec(name, &def, &src, ber_needed, raw_needed, text_needed,
               xer_needed, json_needed, oer_needed, FALSE);
  }

  if(text_needed){
   src=mputprintf(src,
      "int %s::TEXT_encode(const TTCN_Typedescriptor_t& p_td,"
      " TTCN_Buffer& p_buf) const{\n"
      "  int encoded_length=0;\n"
      "  if(p_td.text->begin_encode){\n"
      "    p_buf.put_cs(*p_td.text->begin_encode);\n"
      "    encoded_length+=p_td.text->begin_encode->lengthof();\n"
      "  }\n"
      "  if(val_ptr==NULL) {\n"
      "    TTCN_EncDec_ErrorContext::error\n"
      "      (TTCN_EncDec::ET_UNBOUND, \"Encoding an unbound value.\");\n"
      "    if(p_td.text->end_encode){\n"
      "      p_buf.put_cs(*p_td.text->end_encode);\n"
      "      encoded_length+=p_td.text->end_encode->lengthof();\n"
      "    }\n"
      "    return encoded_length;\n"
      "  }\n"
Elemer Lelik's avatar
Elemer Lelik committed
      "  for(int a=0;a<val_ptr->n_elements;a++){\n"
      "   if(a!=0 && p_td.text->separator_encode){\n"
      "    p_buf.put_cs(*p_td.text->separator_encode);\n"
      "    encoded_length+=p_td.text->separator_encode->lengthof();\n"
      "   }\n"
Elemer Lelik's avatar
Elemer Lelik committed
      "   encoded_length+=(*this)[a].TEXT_encode(*p_td.oftype_descr,p_buf);\n"
      "  }\n"
      "  if(p_td.text->end_encode){\n"
      "    p_buf.put_cs(*p_td.text->end_encode);\n"
      "    encoded_length+=p_td.text->end_encode->lengthof();\n"
      "  }\n"
      "  return encoded_length;\n"
      "}\n"
Elemer Lelik's avatar
Elemer Lelik committed
      ,name
      );
    src = mputprintf(src,
      "int %s::TEXT_decode(const TTCN_Typedescriptor_t& p_td,"
      " TTCN_Buffer& p_buf, Limit_Token_List& limit, boolean no_err"
      ", boolean first_call){\n"
      "  int decoded_length=0;\n"
      "  size_t pos=p_buf.get_pos();\n"
      "  boolean sep_found=FALSE;\n"
      "  int sep_length=0;\n"
      "  int ml=0;\n"
      "  if(p_td.text->begin_decode){\n"
      "    int tl;\n"
      "    if((tl=p_td.text->begin_decode->match_begin(p_buf))<0){\n"
      "          if(no_err)return -1;\n"
      "          TTCN_EncDec_ErrorContext::error\n"
      "              (TTCN_EncDec::ET_TOKEN_ERR, \"The specified token '%%s'"
      " not found for '%%s': \",(const char*)*(p_td.text->begin_decode)"
      ", p_td.name);\n"
      "          return 0;\n"
      "        }\n"
      "    decoded_length+=tl;\n"
      "    p_buf.increase_pos(tl);\n"
      "  }\n"
      "  if(p_td.text->end_decode){\n"
      "    limit.add_token(p_td.text->end_decode);\n"
      "    ml++;\n"
      "  }\n"
      "  if(p_td.text->separator_decode){\n"
      "    limit.add_token(p_td.text->separator_decode);\n"
      "    ml++;\n"
      "  }\n"
      "  if(first_call) {\n"
Elemer Lelik's avatar
Elemer Lelik committed
      "    clean_up();\n"
      "    val_ptr=new recordof_setof_struct;\n"
      "    val_ptr->ref_count=1;\n"
      "    val_ptr->n_elements=0;\n"
      "    val_ptr->value_elements=NULL;\n"
      "  }\n"
Elemer Lelik's avatar
Elemer Lelik committed
      "  int more=val_ptr->n_elements;\n"
      "  while(TRUE){\n"
      "    %s *val=new %s;\n"
      "    pos=p_buf.get_pos();\n"
Elemer Lelik's avatar
Elemer Lelik committed
      "    int len=val->TEXT_decode(*p_td.oftype_descr,p_buf,limit,TRUE);\n"
      "    if(len==-1 || (len==0 && !limit.has_token())){\n"
      "      p_buf.set_pos(pos);\n"
      "      delete val;\n"
      "      if(sep_found){\n"
      "        p_buf.set_pos(p_buf.get_pos()-sep_length);\n"
      "        decoded_length-=sep_length;\n"
      "      }\n"
      "      break;\n"
      "    }\n"
      "    sep_found=FALSE;\n"
Elemer Lelik's avatar
Elemer Lelik committed
      "    val_ptr->value_elements = (%s**)reallocate_pointers"
      "((void**)val_ptr->value_elements, val_ptr->n_elements, "
      "val_ptr->n_elements + 1);\n"
Elemer Lelik's avatar
Elemer Lelik committed
      "    val_ptr->value_elements[val_ptr->n_elements]=val;\n"
      "    val_ptr->n_elements++;\n"
      "    decoded_length+=len;\n"
      "    if(p_td.text->separator_decode){\n"
      "      int tl;\n"
      "      if((tl=p_td.text->separator_decode->match_begin(p_buf))<0){\n"
      "        break;\n"
      "      }\n"
      "      decoded_length+=tl;\n"
      "      p_buf.increase_pos(tl);\n"
      "      sep_length=tl;\n"
      "      sep_found=TRUE;\n"
      "    } else if(p_td.text->end_decode){\n"
      "      int tl;\n"
      "      if((tl=p_td.text->end_decode->match_begin(p_buf))!=-1){\n"
      "        decoded_length+=tl;\n"
      "        p_buf.increase_pos(tl);\n"
      "        limit.remove_tokens(ml);\n"
      "        return decoded_length;\n"
      "      }\n"
      "    } else if(limit.has_token(ml)){\n"
      "      if(limit.match(p_buf,ml)==0){\n"
      "        sep_found=FALSE;\n"
      "        break;\n"
      "      }\n"
      "    }\n"
      "  }\n"
Elemer Lelik's avatar
Elemer Lelik committed
      ,name,type,type,type
     );
    src = mputstr(src,
      "   limit.remove_tokens(ml);\n"
      "  if(p_td.text->end_decode){\n"
      "    int tl;\n"
      "    if((tl=p_td.text->end_decode->match_begin(p_buf))<0){\n"
      "          if(no_err){\n"
      "            if(!first_call){\n"
Elemer Lelik's avatar
Elemer Lelik committed
      "              for(int a=more; a<val_ptr->n_elements; a++) "
      "delete val_ptr->value_elements[a];\n"
      "              val_ptr->n_elements=more;\n"
      "            }\n"
      "            return -1;\n"
      "          }\n"
      "          TTCN_EncDec_ErrorContext::error"
      "(TTCN_EncDec::ET_TOKEN_ERR, \"The specified token '%s'"
      " not found for '%s': \",(const char*)*(p_td.text->end_decode)"
      ",p_td.name);\n"
      "          return decoded_length;\n"
      "        }\n"
      "    decoded_length+=tl;\n"
      "    p_buf.increase_pos(tl);\n"
      "  }\n"
Elemer Lelik's avatar
Elemer Lelik committed
      "  if(val_ptr->n_elements==0){\n"
      "    if(!(p_td.text->end_decode || p_td.text->begin_decode)) {\n"
      "      if(no_err)return -1;\n"
      "      TTCN_EncDec_ErrorContext::error"
      "(TTCN_EncDec::ET_TOKEN_ERR, \"No record/set of member found.\");\n"
      "      return decoded_length;\n"
      "    }\n"
      "  }\n"
Elemer Lelik's avatar
Elemer Lelik committed
      "  if(!first_call && more==val_ptr->n_elements && "
      "!(p_td.text->end_decode || p_td.text->begin_decode)) return -1;\n"
      "  return decoded_length;\n"
      "}\n"
     );
  }

  /* BER functions */
  if(ber_needed) {
    /* BER_encode_TLV() */
    src=mputprintf
      (src,
       "ASN_BER_TLV_t* %s::BER_encode_TLV(const TTCN_Typedescriptor_t&"
       " p_td, unsigned p_coding) const\n"
       "{\n"
       "  BER_chk_descr(p_td);\n"
       "  ASN_BER_TLV_t *new_tlv=BER_encode_chk_bound(is_bound());\n"
       "  if(!new_tlv) {\n"
       "    new_tlv=ASN_BER_TLV_t::construct(NULL);\n"
       "    TTCN_EncDec_ErrorContext ec;\n"
Elemer Lelik's avatar
Elemer Lelik committed
       "    for(int elem_i=0; elem_i<val_ptr->n_elements; elem_i++) {\n"
       "      ec.set_msg(\"Component #%%d: \", elem_i);\n"
       "      new_tlv->add_TLV((*this)[elem_i].BER_encode_TLV"
Elemer Lelik's avatar
Elemer Lelik committed
       "(*p_td.oftype_descr, p_coding));\n"
       "    }\n"
       "%s"
       "  }\n"
       "  new_tlv=ASN_BER_V2TLV(new_tlv, p_td, p_coding);\n"
       "  return new_tlv;\n"
       "}\n"
       "\n"
       /* BER_decode_TLV() */
       "boolean %s::BER_decode_TLV(const TTCN_Typedescriptor_t& p_td,"
       " const ASN_BER_TLV_t& p_tlv, unsigned L_form)\n"
       "{\n"
       "  BER_chk_descr(p_td);\n"
       "  ASN_BER_TLV_t stripped_tlv;\n"
       "  BER_decode_strip_tags(*p_td.ber, p_tlv, L_form, stripped_tlv);\n"
       "  TTCN_EncDec_ErrorContext ec_0(\"While decoding '%%s' type: \","
       " p_td.name);\n"
       "  stripped_tlv.chk_constructed_flag(TRUE);\n"
Elemer Lelik's avatar
Elemer Lelik committed
       "  clean_up();\n"
       "  val_ptr = new recordof_setof_struct;\n"
       "  val_ptr->ref_count = 1;\n"
       "  val_ptr->n_elements = 0;\n"
       "  val_ptr->value_elements = NULL;\n"
       "  size_t V_pos=0;\n"
       "  ASN_BER_TLV_t tmp_tlv;\n"
       "  TTCN_EncDec_ErrorContext ec_1(\"Component #\");\n"
       "  TTCN_EncDec_ErrorContext ec_2(\"0: \");\n"
       "  while(BER_decode_constdTLV_next(stripped_tlv, V_pos, L_form, "
       "tmp_tlv)) {\n"
Elemer Lelik's avatar
Elemer Lelik committed
       "    val_ptr->value_elements = (%s**)reallocate_pointers("
       "(void**)val_ptr->value_elements, val_ptr->n_elements, "
       "val_ptr->n_elements + 1);\n"
       "    val_ptr->n_elements++;\n"
       "    val_ptr->value_elements[val_ptr->n_elements - 1] = new %s;\n"
Elemer Lelik's avatar
Elemer Lelik committed
       "    val_ptr->value_elements[val_ptr->n_elements - 1]->BER_decode_TLV(*p_td.oftype_descr, tmp_tlv, "
       "L_form);\n"
Elemer Lelik's avatar
Elemer Lelik committed
       "    ec_2.set_msg(\"%%d: \", val_ptr->n_elements);\n"
       "  }\n"
       "  return TRUE;\n"
       "}\n"
       "\n"
Elemer Lelik's avatar
Elemer Lelik committed
       , name
       , sdef->kind==SET_OF?"    new_tlv->sort_tlvs();\n":""
Elemer Lelik's avatar
Elemer Lelik committed
       , name, type, type
       );

    if(sdef->has_opentypes) {
      /* BER_decode_opentypes() */
      def=mputstr
        (def,
         "void BER_decode_opentypes(TTCN_Type_list& p_typelist,"
         " unsigned L_form);\n");
      src=mputprintf
        (src,
         "void %s::BER_decode_opentypes(TTCN_Type_list& p_typelist,"
         " unsigned L_form)\n"
         "{\n"
         "  p_typelist.push(this);\n"
         "  TTCN_EncDec_ErrorContext ec_0(\"Component #\");\n"
         "  TTCN_EncDec_ErrorContext ec_1;\n"
Elemer Lelik's avatar
Elemer Lelik committed
         "  for(int elem_i=0; elem_i<val_ptr->n_elements; elem_i++) {\n"
         "    ec_1.set_msg(\"%%d: \", elem_i);\n"
Elemer Lelik's avatar
Elemer Lelik committed
         "    val_ptr->value_elements[elem_i]->BER_decode_opentypes(p_typelist,"
         " L_form);\n"
         "  }\n"
         "  p_typelist.pop();\n"
         "}\n"
         "\n"
         , name
         );
    }
  }

  if(raw_needed){
      src=mputprintf(src,
    "int %s::RAW_decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, "
    "int limit, raw_order_t top_bit_ord, boolean /*no_err*/, int sel_field"
    ", boolean first_call, const RAW_Force_Omit*){\n"
    "  int prepaddlength=p_buf.increase_pos_padd(p_td.raw->prepadding);\n"
    "  limit-=prepaddlength;\n"
    "  int decoded_length=0;\n"
    "  int decoded_field_length=0;\n"
    "  size_t start_of_field=0;\n"
    "  if(first_call) {\n"
Elemer Lelik's avatar
Elemer Lelik committed
    "    clean_up();\n"
    "    val_ptr=new recordof_setof_struct;\n"
    "    val_ptr->ref_count=1;\n"
    "    val_ptr->n_elements=0;\n"
    "    val_ptr->value_elements=NULL;\n"
    "  }\n"
Elemer Lelik's avatar
Elemer Lelik committed
    "  int start_field=val_ptr->n_elements;\n"
    "  if(p_td.raw->fieldlength || sel_field!=-1){\n"
    "    int a=0;\n"
    "    if(sel_field==-1) sel_field=p_td.raw->fieldlength;\n"
    "    start_of_field=p_buf.get_pos_bit();\n"
    "    for(a=0;a<sel_field;a++){\n"
Elemer Lelik's avatar
Elemer Lelik committed
    "      decoded_field_length=(*this)[a+start_field].RAW_decode(*p_td.oftype_descr,"
    "p_buf,limit,top_bit_ord,TRUE);\n"
    "      if(decoded_field_length < 0){\n"
    "        while(a>=0){\n"
    "          delete &(*this)[a+start_field];\n"
    "          a--;\n"
    "          val_ptr->n_elements--;\n"
    "        }\n"
    "        p_buf.set_pos_bit(start_of_field);\n"
    "        return decoded_field_length;\n"
    "      }\n"
    "      decoded_length+=decoded_field_length;\n"
    "      limit-=decoded_field_length;\n"
    "    }\n"
Elemer Lelik's avatar
Elemer Lelik committed
    "    if(a==0) val_ptr->n_elements=0;\n"
    "  } else {\n"
    "    if(limit==0){\n"
    "      if(!first_call) return -1;\n"
Elemer Lelik's avatar
Elemer Lelik committed
    "      val_ptr->n_elements=0;\n"
    "      return decoded_length+p_buf.increase_pos_padd(p_td.raw->padding)"