/*$Id: u_parameter.h,v 26.14 2007/02/07 09:06:48 al Exp $ -*- C++ -*- * Copyright (C) 2005 Albert Davis * Author: Albert Davis * * This file is part of "Gnucap", the Gnu Circuit Analysis Package * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. *------------------------------------------------------------------ * A class for parameterized values * Used for spice compatible .param statements * and passing arguments to models and subcircuits */ //testing=script 2006.07.14 #ifndef U_PARAMETER_H #define U_PARAMETER_H #include "u_opt.h" #include "e_cardlist.h" #include "constant.h" #include "ap.h" /*--------------------------------------------------------------------------*/ template class PARAMETER { private: mutable T _v; std::string _s; public: explicit PARAMETER() :_v(NOT_INPUT), _s() {} PARAMETER(const PARAMETER& p) :_v(p._v), _s(p._s) {} explicit PARAMETER(T v) :_v(v), _s() {} //explicit PARAMETER(T v, const std::string& s) :_v(v), _s(s) {untested();} ~PARAMETER() {} bool has_hard_value()const {return (_s != "");} bool has_value()const {return has_hard_value();} bool has_good_value()const {return (_v != NOT_INPUT);} bool has_soft_value()const {untested(); return (has_good_value() && !has_hard_value());} operator T()const {return _v;} T e_val(const T& def, const CARD_LIST* scope)const; void parse(CS& cmd); void print(OMSTREAM& o)const { if (_s == "#") { o << _v; }else if (_s == "") { o << "NA(" << _v << ")"; }else{ o << _s; } } void set_default(const T& v) {_v = v; _s = "";} void operator=(const PARAMETER& p) {_v = p._v; _s = p._s;} void operator=(const T& v) {_v = v; _s = "#";} void operator=(const std::string& s) {_s = s;} bool operator==(const PARAMETER& p)const { return (_v == p._v && _s == p._s); } bool operator==(const T& v)const { if (v != NOT_INPUT) { return _v == v; }else{ return (_v == NOT_INPUT || !has_value()); } } //bool operator!=(const PARAMETER& p)const { // return !(*this == p); //} //bool operator!=(const T& v)const { // return !(*this == v); //} T* pointer_hack() {return &_v;} }; /*--------------------------------------------------------------------------*/ /* non-class interface, so non-paramaters can have same syntax */ /* It is needed by the model compiler */ inline bool operator==(const PARAMETER& p, double v) {untested(); if (v != NOT_INPUT) {untested(); return p.operator==(static_cast(v)); }else{untested(); return (!(p.has_value())); } } template bool has_hard_value(const PARAMETER& p) { return p.has_hard_value(); } inline bool has_hard_value(double x) { return (x != NOT_INPUT); } inline bool has_good_value(double x) { return (x != NOT_INPUT); } template bool has_good_value(const PARAMETER& p) { return p.has_good_value(); } template bool has_soft_value(const PARAMETER& p) {untested(); return p.has_soft_value(); } template bool has_nz_value(const T& p) { return (has_good_value(p) && p != 0); } template void set_default(PARAMETER* p, const T& v) { assert(p); p->set_default(v); } template void set_default(T* p, const T& v) { assert(p); *p = v; } template void e_val(PARAMETER* p, const PARAMETER& def, const CARD_LIST* scope) { assert(p); p->e_val(def, scope); } template void e_val(PARAMETER* p, const T& def, const CARD_LIST* scope) { assert(p); p->e_val(def, scope); } template void e_val(T* p, const T& def, const CARD_LIST*) { assert(p); if (*p == NOT_INPUT) { *p = def; }else{ } } /*--------------------------------------------------------------------------*/ class PARAM_LIST { private: std::map > _pl; PARAM_LIST* try_again; public: typedef std::map >::const_iterator const_iterator; typedef std::map >::iterator iterator; explicit PARAM_LIST() :try_again(NULL) {} explicit PARAM_LIST(const PARAM_LIST& p) :_pl(p._pl), try_again(p.try_again) {} //explicit PARAM_LIST(PARAM_LIST* ta) :try_again(ta) {untested();} ~PARAM_LIST() {} void parse(CS& cmd); void print(OMSTREAM&, LANGUAGE)const; void eval_copy(PARAM_LIST&, const CARD_LIST*); bool operator==(const PARAM_LIST& p)const {return _pl == p._pl;} PARAMETER operator[](const std::string& i); }; /*--------------------------------------------------------------------------*/ template T PARAMETER::e_val(const T& def, const CARD_LIST* scope)const { assert(scope); static int recursion=0; static const std::string* first_name = NULL; if (recursion == 0) { first_name = &_s; } assert(first_name); ++recursion; if (_s == "") { // blank string means to use default value _v = def; if (recursion > 1) {itested(); error(bWARNING, "parameter " + *first_name + " has no value\n"); } }else if (_s != "#") { // anything else means look up the value if (recursion <= OPT::recursion) { PARAM_LIST* pl = const_cast(scope->params()); _v = T((*pl)[_s].e_val(def, scope)); }else{untested(); _v = def; error(bDANGER, "parameter " + *first_name + " recursion too deep\n"); } }else{ // start with # means we have a final value } --recursion; return _v; } /*--------------------------------------------------------------------------*/ template <> inline void PARAMETER::parse(CS& cmd) { bool new_val; cmd >> new_val; if (cmd) { _v = new_val; _s = "#"; }else{untested(); std::string name; //cmd >> name; name = cmd.ctos(",=();", "'{\"'", "'}\"'"); if (cmd) {untested(); if (name == "NA") {untested(); _s = ""; }else{untested(); _s = name; } }else{untested(); } } if (!cmd) {untested(); _v = true; _s = "#"; } } /*--------------------------------------------------------------------------*/ template inline void PARAMETER::parse(CS& cmd) { T new_val; cmd >> new_val; if (cmd) { _v = new_val; _s = "#"; }else{ std::string name; //cmd >> name; name = cmd.ctos(",=();", "'{\"'", "'}\"'"); if (cmd) { if (name == "NA") {untested(); _s = ""; }else{ _s = name; } } } } /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ bool get(CS& cmd, const std::string& key, PARAMETER* val); bool get(CS& cmd, const std::string& key, PARAMETER* val); /*--------------------------------------------------------------------------*/ template inline OMSTREAM& operator<<(OMSTREAM& o, const PARAMETER p) { p.print(o); return o; } /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ #endif