void t_c_glib_generator::generate_const_initializer()

in compiler/cpp/src/thrift/generate/t_c_glib_generator.cc [997:1215]


void t_c_glib_generator::generate_const_initializer(string name,
                                                    t_type* type,
                                                    t_const_value* value,
                                                    bool top_level) {
  string name_u = initial_caps_to_underscores(name);
  string name_lc = to_lower_case(name_u);
  string type_u = initial_caps_to_underscores(type->get_name());
  string type_uc = to_upper_case(type_u);
  string maybe_static = top_level ? "" : "static ";

  if (type->is_struct() || type->is_xception()) {
    const vector<t_field*>& fields = ((t_struct*)type)->get_members();
    vector<t_field*>::const_iterator f_iter;
    const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
    ostringstream initializers;

    // initialize any constants that may be referenced by this initializer
    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
      t_type* field_type = nullptr;
      string field_name = "";

      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
        if ((*f_iter)->get_name() == v_iter->first->get_string()) {
          field_type = (*f_iter)->get_type();
          field_name = (*f_iter)->get_name();
          break;
        }
      }
      if (field_type == nullptr) {
        throw "type error: " + type->get_name() + " has no field "
          + v_iter->first->get_string();
      }
      field_name = tmp(field_name);

      generate_const_initializer(name + "_constant_" + field_name,
                                 field_type,
                                 v_iter->second);
      initializers << "    constant->" << v_iter->first->get_string() << " = "
                   << constant_value(name + "_constant_" + field_name,
                                     field_type,
                                     v_iter->second) << ";" << '\n'
                   << "    constant->__isset_" << v_iter->first->get_string()
                   << " = TRUE;" << '\n';
    }

    // implement the initializer
    f_types_impl_ << maybe_static << this->nspace << type->get_name() << " *"
                  << '\n'
                  << this->nspace_lc << name_lc << "_constant (void)" << '\n';
    scope_up(f_types_impl_);
    f_types_impl_ << indent() << "static " << this->nspace << type->get_name()
                  << " *constant = NULL;" << '\n'
                  << indent() << "if (constant == NULL)" << '\n';
    scope_up(f_types_impl_);
    f_types_impl_ << indent() << "constant = g_object_new (" << this->nspace_uc
                  << "TYPE_" << type_uc << ", NULL);" << '\n'
                  << initializers.str();
    scope_down(f_types_impl_);

    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
      t_type* field_type = nullptr;
      string field_name = "";

      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
        if ((*f_iter)->get_name() == v_iter->first->get_string()) {
          field_type = (*f_iter)->get_type();
          field_name = (*f_iter)->get_name();
          break;
        }
      }
      if (field_type == nullptr) {
        throw "type error: " + type->get_name() + " has no field "
          + v_iter->first->get_string();
      }
      field_name = tmp(field_name);
    }

    f_types_impl_ << indent() << "return constant;" << '\n';
    scope_down(f_types_impl_);
    f_types_impl_ << '\n';
  } else if (type->is_list()) {
    string list_type = "GPtrArray *";
    string free_func
        = generate_free_func_from_type(reinterpret_cast<t_list*>(type)->get_elem_type());
    string list_initializer = "g_ptr_array_new_with_free_func (" + free_func + ");";
    string list_appender = "g_ptr_array_add";
    bool list_variable = false;

    t_type* etype = ((t_list*)type)->get_elem_type();
    const vector<t_const_value*>& val = value->get_list();
    vector<t_const_value*>::const_iterator v_iter;
    ostringstream initializers;
    ostringstream appenders;

    list_initializer = generate_new_array_from_type(etype);
    if (etype->is_base_type()) {
      t_base_type::t_base tbase = ((t_base_type*)etype)->get_base();
      switch (tbase) {
      case t_base_type::TYPE_VOID:
        throw "compiler error: cannot determine array type";
      case t_base_type::TYPE_BOOL:
      case t_base_type::TYPE_I8:
      case t_base_type::TYPE_I16:
      case t_base_type::TYPE_I32:
      case t_base_type::TYPE_I64:
      case t_base_type::TYPE_DOUBLE:
        list_type = "GArray *";
        list_appender = "g_array_append_val";
        list_variable = true;
        break;
      case t_base_type::TYPE_STRING:
        break;
      default:
        throw "compiler error: no array info for type";
      }
    } else if (etype->is_enum()) {
      list_type = "GArray *";
      list_appender = "g_array_append_val";
      list_variable = true;
    }

    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
      string fname = tmp(name);

      generate_const_initializer(fname, etype, (*v_iter));
      if (list_variable) {
        initializers << "    " << type_name(etype) << " " << fname << " = "
                     << constant_value(fname, (t_type*)etype, (*v_iter)) << ";"
                     << '\n';
        appenders << "    " << list_appender << "(constant, " << fname << ");"
                  << '\n';
      } else {
        appenders << "    " << list_appender << "(constant, "
                  << constant_value(fname, (t_type*)etype, (*v_iter)) << ");"
                  << '\n';
      }
    }

    f_types_impl_ << maybe_static << list_type << '\n'
                  << this->nspace_lc << name_lc << "_constant (void)" << '\n';
    scope_up(f_types_impl_);
    f_types_impl_ << indent() << "static " << list_type << " constant = NULL;"
                  << '\n'
                  << indent() << "if (constant == NULL)" << '\n';
    scope_up(f_types_impl_);
    if (!initializers.str().empty()) {
      f_types_impl_ << initializers.str()
                    << '\n';
    }
    f_types_impl_ << indent() << "constant = " << list_initializer << '\n'
                  << appenders.str();
    scope_down(f_types_impl_);
    f_types_impl_ << indent() << "return constant;" << '\n';
    scope_down(f_types_impl_);
    f_types_impl_ << '\n';
  } else if (type->is_set()) {
    t_type* etype = ((t_set*)type)->get_elem_type();
    const vector<t_const_value*>& val = value->get_list();
    vector<t_const_value*>::const_iterator v_iter;
    ostringstream initializers;
    ostringstream appenders;

    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
      string fname = tmp(name);
      string ptr = is_numeric(etype) ? "*" : "";
      generate_const_initializer(fname, etype, (*v_iter));
      initializers << constant_value_with_storage(fname, (t_type*)etype, *v_iter);
      appenders << "    g_hash_table_insert (constant, " << fname << ", 0);" << '\n';
    }

    f_types_impl_ << maybe_static << "GHashTable *" << '\n'
                  << this->nspace_lc << name_lc << "_constant (void)" << '\n';
    scope_up(f_types_impl_);
    f_types_impl_ << indent() << "static GHashTable *constant = NULL;" << '\n'
                  << indent() << "if (constant == NULL)" << '\n';
    scope_up(f_types_impl_);
    f_types_impl_ << initializers.str() << '\n'
                  << indent() << "constant = " << generate_new_hash_from_type(etype, nullptr) << '\n'
                  << appenders.str();
    scope_down(f_types_impl_);
    f_types_impl_ << indent() << "return constant;" << '\n';
    scope_down(f_types_impl_);
    f_types_impl_ << '\n';
  } else if (type->is_map()) {
    t_type* ktype = ((t_map*)type)->get_key_type();
    t_type* vtype = ((t_map*)type)->get_val_type();
    const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
    ostringstream initializers;
    ostringstream appenders;

    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
      string fname = tmp(name);
      string kname = fname + "key";
      string vname = fname + "val";
      generate_const_initializer(kname, ktype, v_iter->first);
      generate_const_initializer(vname, vtype, v_iter->second);

      initializers << constant_value_with_storage(kname, (t_type*)ktype, v_iter->first);
      initializers << constant_value_with_storage(vname, (t_type*)vtype, v_iter->second);
      appenders << "    g_hash_table_insert (constant, " << kname << ", " << vname << ");" << '\n';
    }

    f_types_impl_ << maybe_static << "GHashTable *" << '\n'
                  << this->nspace_lc << name_lc << "_constant (void)" << '\n';
    scope_up(f_types_impl_);
    f_types_impl_ << indent() << "static GHashTable *constant = NULL;" << '\n'
                  << indent() << "if (constant == NULL)" << '\n';
    scope_up(f_types_impl_);
    f_types_impl_ << initializers.str() << '\n'
                  << indent() << "constant = " << generate_new_hash_from_type(ktype, vtype) << '\n'
                  << appenders.str();
    scope_down(f_types_impl_);
    f_types_impl_ << indent() << "return constant;" << '\n';
    scope_down(f_types_impl_);
    f_types_impl_ << '\n';
  }
}