⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 templates.cpp

📁 UC Library Extensions UnderC comes with a pocket implementation of the standard C++ libraries, wh
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// These are represented by dummy types, except for (3), which just pass through.
// (See the end of parser.y)
Type Template::dummy(Type t, string name)
{ 
 if (t != t_null) {
	 if (name == "") { // e.g. just plain 'int' passes through  (3)
	   return t;  
     }  else { // *fix 1.2.9 force the const type
        t.make_const();  
        // 'int n' -> unbound variable dummy (2)
        return Type::make_dummy(name,t,NULL);  
     }
 } else 
  // 'class T' -> classic type dummy (1)
  return Type::make_dummy(name,t_null,NULL); 
}

Type Template::dummy(PEntry pe)
{
  return Type::make_dummy("",pe->type,pe); // constant entry dummy (4)
}

char *get_method_name(char *line);
const int MAX_LINE_SIZE = 256;

void Template::grab()
{
 char buff[MAX_LINE_SIZE];
// in general stuff will already be written into the buffer; may (or not) include the ':' or '{'
 int already_written = strlen(mIBuffer);
 int brace_count = already_written > 0 ? count(mIBuffer,'{') : 0;
 char *ptr = mIBuffer + already_written; // - 1;  *NOTE*
 strcpy(ptr,"\n"); // seems to make a difference...
 ptr ++;
 do {
   Input::grab_next_line(buff);
   brace_count += count(buff,'{') - count(buff,'}'); 

   if (*buff != '\0') strcpy(ptr,buff);
   ptr += strlen(buff);
   strcpy(ptr,"\n"); //*I suspect we need this because we cannot handle very long lines!
   ptr ++;
  //brace_count += count(buff,'{') - count(buff,'}'); 
 } while (brace_count > 0);      

if (Parser::debug.verbose) cout << "*buff: " << mIBuffer << endl;
 m_buffer = strdup(mIBuffer);
 *mIBuffer = '\0'; 
}

// *add 1.1.0 This is obviously very similar to the above; next time I want to combine
// the functionality, but for now I just want to know that (a) it works and (b) doesn't 
// interfere with stuff that already works.
// *fix 1.2.4 If this is a ctor with an init list, handle the special case by always
// grabbing everything up to '{'
void Template::grab_function_body(bool plain_method, char* body)
{
 int brace_count = plain_method ? 1 : 0;
 bool grabbing_init = ! plain_method;
 char* ptr;
 char buff[MAX_LINE_SIZE];
 int open_kount, close_kount;
 if (body) ptr = body + strlen(body);
 do { 
   Input::grab_next_line(buff);
   open_kount = count(buff,'{');
   close_kount = count(buff,'}');
   brace_count += open_kount - close_kount; 
   if (open_kount) grabbing_init = false;
   if (body) {
     if (*buff != '\0') strcpy(ptr,buff);
     ptr += strlen(buff);
     strcpy(ptr,"\n"); //*I suspect we need this because we cannot handle very long lines!
     ptr ++;
   }
 } while (brace_count > 0 || grabbing_init);  
}

Template *Template::as_template(Type t)
{
  if (t.is_template_class()) // peculiar expr gets the actual template,
                             // not just the particular instance! 
    return t.as_class()->get_template()->get_template();
  else return NULL; //*NOTE* until we can sort this out!
}

static string mErrStr;

int err(const string& s)
{ mErrStr = s; return 0; }

int Template::match(const TypeList& tl)
{
  TLCI tlif, tlia;
  if (tl == m_formal_args) return 999; // *fix 1.0.0 full specialization
  int effort = 0;
  for(tlif = m_formal_args.begin(), tlia = tl.begin(); tlia != tl.end(); ++tlif, ++tlia) {
    Type tf = *tlif, ta = *tlia;
	if (! tf.is_dummy()) { 
		// *fix 1.1.1 must be able to match all plain args of template functions
		if (::match(tf,ta)==NO_MATCH) return 0;
		continue;  // NB rest is not for plain arguments!!
    }
    if (tf.as_dummy() != NULL) tf.as_dummy()->unbind();

    if (tf.is_const()) { // Quite safe to remove const even if the actual arg isn't...
            ta.strip_const(); tf.strip_const(); effort++; 
    } 
    if (tf.is_reference()) {
           /*if (ta.is_reference())*/
		    { ta.strip_reference(); tf.strip_reference(); effort++; }
    } 
    while (tf.is_pointer()) {
		   if (ta.is_pointer()) { ta.decr_pointer();  tf.decr_pointer(); effort++; }
		   else break;
   }

   // at this point, the formal arg type is either 'bare'
   // or a template class.
   if (!tf.is_bare()) return err("cannot match");
   if (ta.is_const() && ta.is_ref_or_ptr()) return err("parameter is not const");
   effort++;  
   if (tf.is_template_class()) {
     if(ta.is_template_class()) {
        TemplateInstance * titf = tf.as_class()->get_template(); 
 		TemplateInstance * tita = ta.as_class()->get_template(); 
		// but do they belong to the same template?
		if (titf->get_template() == tita->get_template()) {
	      effort++;
          TypeList& tlf = titf->type_parms();
          TypeList& tla = tita->type_parms();
          TLI tlif,tlia;
          for(tlif=tlf.begin(),tlia=tla.begin(); tlif != tlf.end(); tlif++,tlia++) {
            if (!tlif->as_dummy()->bind_to(*tlia)) return err("already bound to a diff. type");
          }
        } else return 0;  // no way we can match different templates!
     } else return 0;  // cannot match template w/ a non-template class! 	  
   } else {
     if (! tf.as_dummy()->bind_to(ta)) return err("already bound");   
   }
  }
  return effort;
}

Type TemplateInstance::type()
{
  if (m_template->is_class()) return Type((Class *)data());
                      else return Type(((Function *)data())->signature());

}

string TemplateInstance::name()
{ return m_template->name(); }

TemplateInstance::TemplateInstance(Template *templ, const TypeList& tl)
 : m_template(templ), m_type_parms(templ->formal_parms()), m_type_args(tl),m_instantiated(false),
   m_data(NULL)
 { }


bool TemplateEntry::instantiate_method(Function *fn)
{
  if (fn->get_template()) return true; // fine - already instantiated!
// This function doesn't have a TemplateInstance initially
// *hack 1.1.0 The hack here is to find the template corresponding to this function
// in the overloaded set. The assumption of course is that they have been 
// defined in the same order as they were declared!
  FunctionEntry *pfe = fn->fun_entry();
  FunctionEntry::iterator fei;
  TemplateList::iterator tli;
  Template *templ;
  for(fei = pfe->begin(), tli = m_templates.begin(); fei != pfe->end(); ++fei,++tli)
     if (*fei == fn) templ = *tli;

  PClass pc = fn->class_context();
  TemplateInstance *c_inst = pc->get_template();

  TemplateInstance *tinst = new TemplateInstance(templ,c_inst->type_list()); 

  try {
     copy_type_list(tinst->type_parms(),c_inst->type_parms());
	 TLCI tlif = tinst->get_template()->formal_parms().begin(), tlia = c_inst->type_parms().begin();
	 for(; tlia != c_inst->type_parms().end();  ++tlif, ++tlia)
	    (*tlif).as_dummy()->bind_to(*tlia);
     templ->instantiate(tinst);
     tinst->instantiated(true);
	 // and mark as instantiated...
     fn->set_template(tinst);
     tinst->data(fn);
     return true;
   } catch(string s) {
     error(s);
	 return false;
   } catch(...) {
     error("unknown error");
	 return false;
   }
 }


int TemplateEntry::simple_match(const TypeList& tl, bool use_args)
{	
 TemplateInstanceList::iterator tili;
  int i = 0;
  FORALL(tili,m_instances) {
    TemplateInstance *ti = *tili;
    const TypeList& tlinst = use_args ? ti->type_list() : ti->type_parms();
	if (Parser::debug.verbose) cout << "*cmp " << tl << ' ' << tlinst << endl;
    if (tl == tlinst) return i;
	i++;
  }
 return -1;
}

int TemplateEntry::no_instances()
// returns the number of _instantiated_ instances
{
  TemplateInstanceList::iterator tili;
  int i = 0;
  FORALL(tili,m_instances) if ((*tili)->instantiated()) i++;
  return i;
}

TemplateInstance *TemplateEntry::match_instance()
{
  if (m_match_idx == -1) return NULL;
  return utils::list_item(m_instances,m_match_idx);
}

string TemplateEntry::last_error()
{
 string ret = mErrStr;
 mErrStr = "";
 return ret;
}

string TemplateEntry::name()
{
 return m_entry->name;
}

void TemplateEntry::add_template(Template *templ)
{
 utils::add_unique(m_templates,templ);
}

Template*  TemplateEntry::templates(int i)
{
  return utils::list_item(m_templates,i);
}

void TemplateEntry::add_method_entry(PEntry pe)
{
  if (m_method_entries == NULL) m_method_entries = new EntryList();
  m_method_entries->push_back(pe);
}

const EntryList *TemplateEntry::method_entries()
{
  return m_method_entries;
}

void copy_type_list(TypeList& tlp, const TypeList& tlt)
{
  TLCI ti;
  TLI tip; 
  for(tip=tlp.begin(),ti=tlt.begin();  ti != tlt.end();  ++ti, ++tip) {
    if (ti->is_dummy()) {
	   DummyType *dt = ti->as_dummy();
       *tip = dt->type();
    } else *tip = *ti;
  }
}

bool TemplateEntry::match(const TypeList& actual_parms)
{
  if (is_method()) return false;

  // ensure that variables lose their implicit referenceness, etc.
  TypeList tl = actual_parms;
  massage_type_list(tl);
  set_index(-1);

  using Parser::state;
// Do we have an existing instance which will match exactly?
  int idx = simple_match(tl);
  if (idx != -1) {
    set_index(idx);
	return true;
  }
     
// Build up a candidate list of templates which could theoretically match this list
  TemplateList tel;
  int no_args = tl.size();
  TemplateList::iterator teli;	
  FORALL(teli, m_templates)
    if ((*teli)->formal_args().size() == no_args) tel.push_back(*teli);
  if (tel.size()==0) return err("Wrong number of type arguments"); 

  // now find the template that scores the highest! Even if there is only one
  // candidate, we go through this to see if we can actually do the match and
  // (most importantly) to do the type binding
  Template *templ;
  int score,max_score = 0;
  FORALL(teli,tel) {
    score = (*teli)->match(tl);
	if (score > max_score) { templ = *teli; max_score = score; }
  }
  if (max_score == 0) { 
	  string error = last_error();
	  return err(error != "" ? error : "Cannot match any template");
  }

  // at this point the template parameters should be successfully bound
  // and a new instance of this template can officially exist (although not yet 
  // instantiated, of course.)
  TemplateInstance *instance = new TemplateInstance(templ,tl);

  // Meanwhile, we fill in the instance's type parameters
  copy_type_list(instance->type_parms(),templ->formal_parms());

  if (m_is_class) {
     TemplateInstance *old_inst = state.in_template;
  // Generate an 'empty' class for the template instance (like one declared forwardly)
     string qualified_name = build_qualified_name(name(),tl);
	 state.push_context(templ->context());
	 state.in_template = instance;
     state.add_class(CLASS,qualified_name,ForwardClass,t_void);
	 state.in_template = old_inst;   // *fix 0.9.7 restore this for nested instantiations
	 state.pop_context();
  //*fix 1.2.9 this is the actual parent context of this template
     NamedTable* tbl = static_cast<NamedTable*>(templ->context()->parent_context());
	 PEntry pe = tbl->lookup(qualified_name);   // wuz state.context().
	 Class *pc = pe->type.as_class();
     instance->data(pc);
	 instance->entry(pe);
	 pc->set_template(instance);
   } else { // strictly speaking, this is not correct in _all cases_ but this will do for now.
    try {
     templ->instantiate(instance); 
    } catch(string msg) {
      return err(msg);
	}
  }
  add_instance(instance);
  return true;
}

void TemplateEntry::add_instance(TemplateInstance* ti)
{
  int ni = m_instances.size();
  m_instances.push_back(ti);
  set_index(ni);
}

int count(char *p, char ch)
{
 int k = 0;
 while (*p != '\0') if (*p++ == ch) k++;
 return k;
}

char *get_method_name(char *line)
{
  char buff[MAX_LINE_SIZE];
  strcpy(buff,line);
  char *p = strstr(buff,"(");
  if (p==NULL) return NULL;  
  p--;
  while(isspace(*p)) p--;
  *(p+1) = '\0';
  while(!isspace(*p)) p--;
  p++;
  if (strncmp(p,"operator",8)==0) p+=8;
  return p;
}


ostream& operator<< (ostream& outs, const TypeList& tl)
{
  outs << '<';
  TLCI tli, tl_last = tl.end();
  --tl_last;
  FORALL(tli,tl) {
	outs << *tli; 
	if (tli != tl_last) outs << ',';
  }
  outs << '>';
  return outs;
}

string build_qualified_name(const string& name, const TypeList& tl)
{
  char buff[512];
  ostrstream outs(buff,512);
  outs << name << tl;
  outs << ends;
  return buff;
}

char *sh_tlistc(const TypeList& tl)  /*DEBUG*/
{
 static char buff[128];
 ostrstream outs(buff,128);
 outs << tl << ends;
 return buff;
}

char *sh_tlist(TypeList& tl)
{ 
 return sh_tlistc((const TypeList&)tl); 
}


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -