Make netlist more typesafe. Added a pformat class to reduce sprintf

usage. The approach is also suitable for translated strings with
arbitrary positioning of parameters. (nw)
This commit is contained in:
couriersud 2015-08-10 21:50:08 +02:00
parent 7b15a99c4b
commit 6cc506594d
16 changed files with 142 additions and 59 deletions

View File

@ -175,11 +175,11 @@ void netlist_mame_stream_input_t::custom_netlist_additions(netlist::setup_t &set
if (snd_in == NULL)
snd_in = dynamic_cast<NETLIB_NAME(sound_in) *>(setup.register_dev("NETDEV_SOUND_IN", "STREAM_INPUT"));
pstring sparam = pstring::sprintf("STREAM_INPUT.CHAN%d", m_channel);
pstring sparam = pformat("STREAM_INPUT.CHAN%1")(m_channel);
setup.register_param(sparam, m_param_name);
sparam = pstring::sprintf("STREAM_INPUT.MULT%d", m_channel);
sparam = pformat("STREAM_INPUT.MULT%1")(m_channel);
setup.register_param(sparam, m_mult);
sparam = pstring::sprintf("STREAM_INPUT.OFFSET%d", m_channel);
sparam = pformat("STREAM_INPUT.OFFSET%1")(m_channel);
setup.register_param(sparam, m_offset);
}
@ -210,7 +210,7 @@ void netlist_mame_stream_output_t::device_start()
void netlist_mame_stream_output_t::custom_netlist_additions(netlist::setup_t &setup)
{
//NETLIB_NAME(sound_out) *snd_out;
pstring sname = pstring::sprintf("STREAM_OUT_%d", m_channel);
pstring sname = pformat("STREAM_OUT_%1")(m_channel);
//snd_out = dynamic_cast<NETLIB_NAME(sound_out) *>(setup.register_dev("nld_sound_out", sname));
setup.register_dev("NETDEV_SOUND_OUT", sname);

View File

@ -648,9 +648,9 @@ public:
for (int i = 0; i < MAX_INPUT_CHANNELS; i++)
{
register_param(pstring::sprintf("CHAN%d", i), m_param_name[i], "");
register_param(pstring::sprintf("MULT%d", i), m_param_mult[i], 1.0);
register_param(pstring::sprintf("OFFSET%d", i), m_param_offset[i], 0.0);
register_param(pformat("CHAN%1")(i), m_param_name[i], "");
register_param(pformat("MULT%1")(i), m_param_mult[i], 1.0);
register_param(pformat("OFFSET%1")(i), m_param_offset[i], 0.0);
}
m_num_channel = 0;
}

View File

@ -16,7 +16,7 @@ NETLIB_START(log)
{
register_input("I", m_I);
pstring filename = pstring::sprintf("%s.log", name().cstr());
pstring filename = pformat("%1.log")(name());
m_strm = palloc(pofilestream(filename));
}
@ -26,7 +26,9 @@ NETLIB_RESET(log)
NETLIB_UPDATE(log)
{
m_strm->writeline(pstring::sprintf("%20.9e %e", netlist().time().as_double(), (nl_double) INPANALOG(m_I)).cstr());
/* use pstring::sprintf, it is a LOT faster */
// m_strm->writeline(pstring::sprintf("%20.9e %e", netlist().time().as_double(), (nl_double) INPANALOG(m_I)).cstr());
m_strm->writeline(pformat("%1 %2").e(netlist().time().as_double(),".9").e((nl_double) INPANALOG(m_I)).cstr());
}
NETLIB_NAME(log)::~NETLIB_NAME(log)()

View File

@ -299,7 +299,7 @@ NETLIB_START(function)
register_output("Q", m_Q);
for (int i=0; i < m_N; i++)
register_input(pstring::sprintf("A%d", i), m_I[i]);
register_input(pformat("A%1")(i), m_I[i]);
pstring_list_t cmds(m_func.Value(), " ");
m_precompiled.clear();

View File

@ -135,8 +135,8 @@ void truthtable_desc_t::help(unsigned cur, pstring_list_t list,
{
// cutoff previous inputs and outputs for ignore
if (m_outs[nstate] != ~0U && m_outs[nstate] != val)
fatalerror_e(pstring::sprintf("Error in truthtable: State %04x already set, %d != %d\n",
(UINT32) nstate, m_outs[nstate], val));
fatalerror_e(pformat("Error in truthtable: State %1 already set, %2 != %3\n")
.x(nstate,"04")(m_outs[nstate])(val) );
m_outs[nstate] = val;
for (unsigned j=0; j<m_NO; j++)
m_timing[nstate * m_NO + j] = timing_index[j];
@ -231,7 +231,7 @@ void truthtable_desc_t::setup(const pstring_list_t &truthtable, UINT32 disabled_
for (UINT32 i=0; i<m_size; i++)
{
if (m_outs[i] == ~0U)
throw fatalerror_e(pstring::sprintf("truthtable: found element not set %04x\n", i));
throw fatalerror_e(pformat("truthtable: found element not set %1\n").x(i) );
m_outs[i] |= ((ign[i] & ~disabled_ignore) << m_NO);
}
*m_initialized = true;
@ -264,7 +264,7 @@ netlist_base_factory_truthtable_t *nl_tt_factory_create(const unsigned ni, const
ENTRY(9);
ENTRY(10);
default:
pstring msg = pstring::sprintf("unable to create truthtable<%d,%d,%d>", ni, no, has_state);
pstring msg = pformat("unable to create truthtable<%1,%2,%3>")(ni)(no)(has_state);
nl_assert_always(false, msg.cstr());
}
return NULL;

View File

@ -252,11 +252,11 @@ virtual logic_family_desc_t *default_logic_family()
//============================================================
#if defined(MAME_DEBUG)
#define nl_assert(x) do { if (!(x)) throw fatalerror_e("assert: %s:%d: %s", __FILE__, __LINE__, #x); } while (0)
#define nl_assert(x) do { if (1) if (!(x)) throw fatalerror_e(pformat("assert: %1:%2: %3")(__FILE__)(__LINE__)(#x) ); } while (0)
#else
#define nl_assert(x) do { if (0) if (!(x)) throw fatalerror_e(pstring::sprintf("assert: %s:%d: %s", __FILE__, __LINE__, #x)); } while (0)
#define nl_assert(x) do { if (0) if (!(x)) throw fatalerror_e(pformat("assert: %1:%2: %3")(__FILE__)(__LINE__)(#x) ); } while (0)
#endif
#define nl_assert_always(x, msg) do { if (!(x)) throw fatalerror_e(pstring::sprintf("Fatal error: %s\nCaused by assert: %s:%d: %s", msg, __FILE__, __LINE__, #x)); } while (0)
#define nl_assert_always(x, msg) do { if (!(x)) throw fatalerror_e(pformat("Fatal error: %1\nCaused by assert: %2:%3: %4")(msg)(__FILE__)(__LINE__)(#x)); } while (0)
// -----------------------------------------------------------------------------

View File

@ -73,13 +73,13 @@ namespace netlist
const pstring &def_param)
{
if (!add(name, palloc(factory_t< _C >(name, classname, def_param))))
error(pstring::sprintf("factory already contains %s", name.cstr()));
error("factory already contains " + name);
}
ATTR_COLD void register_device(base_factory_t *factory)
{
if (!add(factory->name(), factory))
error(pstring::sprintf("factory already contains %s", factory->name().cstr()));
error("factory already contains " + factory->name());
}
//ATTR_COLD device_t *new_device_by_classname(const pstring &classname) const;

View File

@ -324,8 +324,8 @@ void parser_t::dippins()
unsigned n = pins.size();
for (unsigned i = 0; i < n / 2; i++)
{
m_setup.register_alias(pstring::sprintf("%d", i+1), pins[i*2]);
m_setup.register_alias(pstring::sprintf("%d", n-i), pins[i*2 + 1]);
m_setup.register_alias(pformat("%1")(i+1), pins[i*2]);
m_setup.register_alias(pformat("%1")(n-i), pins[i*2 + 1]);
}
}

View File

@ -170,8 +170,8 @@ void setup_t::register_dippins_arr(const pstring &terms)
unsigned n = list.size();
for (unsigned i = 0; i < n / 2; i++)
{
register_alias(pstring::sprintf("%d", i+1), list[i * 2]);
register_alias(pstring::sprintf("%d", n-i), list[i * 2 + 1]);
register_alias(pformat("%1")(i+1), list[i * 2]);
register_alias(pformat("%1")(n-i), list[i * 2 + 1]);
}
}
@ -332,7 +332,7 @@ void setup_t::remove_connections(const pstring pin)
void setup_t::register_frontier(const pstring attach, const double r_IN, const double r_OUT)
{
static int frontier_cnt = 0;
pstring frontier_name = pstring::sprintf("frontier_%d", frontier_cnt);
pstring frontier_name = pformat("frontier_%1")(frontier_cnt);
frontier_cnt++;
device_t *front = register_dev("FRONTIER_DEV", frontier_name);
register_param(frontier_name + ".RIN", r_IN);
@ -362,7 +362,7 @@ void setup_t::register_frontier(const pstring attach, const double r_IN, const d
void setup_t::register_param(const pstring &param, const double value)
{
// FIXME: there should be a better way
register_param(param, pstring::sprintf("%.9e", value));
register_param(param, pformat("%1").e(value,".9"));
}
void setup_t::register_param(const pstring &param, const pstring &value)
@ -478,7 +478,7 @@ devices::nld_base_proxy *setup_t::get_d_a_proxy(core_terminal_t &out)
{
// create a new one ...
devices::nld_base_d_to_a_proxy *new_proxy = out_cast.logic_family()->create_d_a_proxy(&out_cast);
pstring x = pstring::sprintf("proxy_da_%s_%d", out.name().cstr(), m_proxy_cnt);
pstring x = pformat("proxy_da_%1_%2")(out.name())(m_proxy_cnt);
m_proxy_cnt++;
register_dev(new_proxy, x);
@ -510,7 +510,7 @@ void setup_t::connect_input_output(core_terminal_t &in, core_terminal_t &out)
logic_input_t &incast = dynamic_cast<logic_input_t &>(in);
devices::nld_a_to_d_proxy *proxy = palloc(devices::nld_a_to_d_proxy(&incast));
incast.set_proxy(proxy);
pstring x = pstring::sprintf("proxy_ad_%s_%d", in.name().cstr(), m_proxy_cnt);
pstring x = pformat("proxy_ad_%1_%2")(in.name())( m_proxy_cnt);
m_proxy_cnt++;
register_dev(proxy, x);
@ -549,7 +549,7 @@ void setup_t::connect_terminal_input(terminal_t &term, core_terminal_t &inp)
NL_VERBOSE_OUT(("connect_terminal_input: connecting proxy\n"));
devices::nld_a_to_d_proxy *proxy = palloc(devices::nld_a_to_d_proxy(&incast));
incast.set_proxy(proxy);
pstring x = pstring::sprintf("proxy_ad_%s_%d", inp.name().cstr(), m_proxy_cnt);
pstring x = pformat("proxy_ad_%1_%2")(inp.name())(m_proxy_cnt);
m_proxy_cnt++;
register_dev(proxy, x);
@ -799,8 +799,7 @@ void setup_t::resolve_inputs()
{
core_terminal_t *term = m_terminals.value_at(i);
if (!term->has_net())
errstr += pstring::sprintf("Found terminal %s without a net\n",
term->name().cstr());
errstr += pformat("Found terminal %1 without a net\n")(term->name());
else if (term->net().num_cons() == 0)
netlist().warning("Found terminal %s without connections",
term->name().cstr());
@ -985,8 +984,8 @@ nl_double setup_t::model_value(model_map_t &map, const pstring &entity)
pstring tmp = model_value_str(map, entity);
nl_double factor = NL_FCONST(1.0);
char numfac = *(tmp.right(1).cstr());
switch (numfac)
pstring numfac = tmp.right(1);
switch (numfac.code_at(0))
{
case 'M': factor = 1e6; break;
case 'k': factor = 1e3; break;
@ -997,8 +996,8 @@ nl_double setup_t::model_value(model_map_t &map, const pstring &entity)
case 'f': factor = 1e-15; break;
case 'a': factor = 1e-18; break;
default:
if (numfac < '0' || numfac > '9')
fatalerror_e(pstring::sprintf("Unknown number factor <%c> in: %s", numfac, entity.cstr()));
if (numfac < "0" || numfac > "9")
fatalerror_e(pformat("Unknown number factor <%1> in: %2")(numfac)(entity));
}
if (factor != NL_FCONST(1.0))
tmp = tmp.left(tmp.len() - 1);

View File

@ -455,12 +455,12 @@ pstring ppreprocessor::process_line(const pstring &line)
if (m_ifflag == 0)
{
if (lti.size() != 3)
error(pstring::sprintf("PREPRO: only simple defines allowed: %s", line.cstr()));
error("PREPRO: only simple defines allowed: %s" + line);
m_defines.add(lti[1], define_t(lti[1], lti[2]));
}
}
else
error(pstring::sprintf("unknown directive on line %d: %s\n", m_lineno, line.cstr()));
error(pformat("unknown directive on line %1: %2\n")(m_lineno)(line));
}
else
{

View File

@ -226,6 +226,7 @@ pstring_t<F> pstring_t<F>::replace(const pstring_t &search, const pstring_t &rep
i++;
}
}
ret = ret.cat(cstr() + i);
return ret;
}
@ -512,6 +513,43 @@ void pstringbuffer::pcat(const pstring &s)
m_ptr[m_len] = 0;
}
pformat::pformat(const pstring &fmt)
: m_arg(0)
{
memcpy(m_str, fmt.cstr(), fmt.blen() + 1);
}
pformat::pformat(const char *fmt)
: m_arg(0)
{
strncpy(m_str, fmt, sizeof(m_str));
m_str[sizeof(m_str)] = 0;
}
pformat &pformat::update(const char *f, const char *l, ...)
{
va_list ap;
va_start(ap, l);
char fmt[30] = "%";
char search[10] = "";
char buf[1024];
strcat(fmt, f);
strcat(fmt, l);
int nl = vsprintf(buf, fmt, ap);
m_arg++;
int sl = sprintf(search, "%%%d", m_arg);
char *p = strstr(m_str, search);
if (p != NULL)
{
// Make room
memmove(p+nl, p+sl, strlen(p) + 1 - sl);
memcpy(p, buf, nl);
}
va_end(ap);
return *this;
}
template struct pstring_t<pu8_traits>;
template struct pstring_t<putf8_traits>;

View File

@ -381,5 +381,50 @@ private:
};
class pformat
{
public:
pformat(const pstring &fmt);
pformat(const char *fmt);
operator pstring() const { return m_str; }
const char *cstr() { return m_str; }
pformat &operator ()(const INT64 x, const char *f = "") { return update(f, I64FMT "d", x); }
pformat &operator ()(const UINT64 x, const char *f = "") { return update(f, I64FMT "u", x); }
pformat &x (const INT64 x, const char *f = "") { return update(f, I64FMT "x", x); }
pformat &x (const UINT64 x, const char *f = "") { return update(f, I64FMT "x", x); }
pformat &operator ()(const INT32 x, const char *f = "") { return update(f, "d", x); }
pformat &operator ()(const UINT32 x, const char *f = "") { return update(f, "u", x); }
pformat &x (const INT32 x, const char *f = "") { return update(f, "x", x); }
pformat &x (const UINT32 x, const char *f = "") { return update(f, "x", x); }
pformat &operator ()(const INT16 x, const char *f = "") { return update(f, "hd", x); }
pformat &operator ()(const UINT16 x, const char *f = "") { return update(f, "hu", x); }
pformat &operator ()(const std::size_t x, const char *f = "") { return update(f, SIZETFMT, x); }
pformat &operator ()(const double x, const char *f = "") { return update(f, "f", x); }
pformat & e(const double x, const char *f = "") { return update(f, "e", x); }
pformat & g(const double x, const char *f = "") { return update(f, "g", x); }
pformat &operator ()(const char *x, const char *f = "") { return update(f, "s", x); }
pformat &operator ()(const void *x, const char *f = "") { return update(f, "p", x); }
pformat &operator ()(const pstring &x, const char *f = "") { return update(f, "s", x.cstr() ); }
private:
pformat &update(const char *f, const char *l, ...);
char m_str[2048];
unsigned m_arg;
};
//const type_t vprintf(va_list args) const;
//static const type_t sprintf(const char *format, ...) ATTR_PRINTF(1,2);
#endif /* _PSTRING_H_ */

View File

@ -277,7 +277,7 @@ ATTR_COLD void matrix_solver_direct_t<m_N, _storage_N>::vsetup(analog_net_t::lis
for (unsigned k = 0; k < N(); k++)
{
pstring num = pstring::sprintf("%d", k);
pstring num = pformat("%1")(k);
save(m_terms[k]->go(),"GO" + num, m_terms[k]->count());
save(m_terms[k]->gt(),"GT" + num, m_terms[k]->count());

View File

@ -170,7 +170,7 @@ ATTR_COLD void matrix_solver_t::setup(analog_net_t::list_t &nets)
if (net_proxy_output == NULL)
{
net_proxy_output = palloc(analog_output_t);
net_proxy_output->init_object(*this, this->name() + "." + pstring::sprintf("m%" SIZETFMT, SIZET_PRINTF(m_inps.size())));
net_proxy_output->init_object(*this, this->name() + "." + pformat("m%1")(m_inps.size()));
m_inps.add(net_proxy_output);
net_proxy_output->m_proxied_net = &p->net().as_analog();
}
@ -584,7 +584,7 @@ ATTR_COLD void NETLIB_NAME(solver)::post_start()
break;
}
register_sub(pstring::sprintf("Solver_%" SIZETFMT,SIZET_PRINTF(m_mat_solvers.size())), *ms);
register_sub(pformat("Solver_%1")(m_mat_solvers.size()), *ms);
ms->vsetup(groups[i]);

View File

@ -149,7 +149,7 @@ const pstring nl_convert_base_t::get_nl_val(const double val)
break;
i++;
}
return pstring::sprintf(m_units[i].m_func.cstr(), val / m_units[i].m_mult);
return pformat(m_units[i].m_func.cstr()).g(val / m_units[i].m_mult);
}
}
double nl_convert_base_t::get_sp_unit(const pstring &unit)
@ -181,21 +181,21 @@ double nl_convert_base_t::get_sp_val(const pstring &sin)
nl_convert_base_t::unit_t nl_convert_base_t::m_units[] = {
{"T", "", 1.0e12 },
{"G", "", 1.0e9 },
{"MEG", "RES_M(%g)", 1.0e6 },
{"k", "RES_K(%g)", 1.0e3 }, /* eagle */
{"K", "RES_K(%g)", 1.0e3 },
{"", "%g", 1.0e0 },
{"M", "CAP_M(%g)", 1.0e-3 },
{"u", "CAP_U(%g)", 1.0e-6 }, /* eagle */
{"U", "CAP_U(%g)", 1.0e-6 },
{"??", "CAP_U(%g)", 1.0e-6 },
{"N", "CAP_N(%g)", 1.0e-9 },
{"P", "CAP_P(%g)", 1.0e-12},
{"F", "%ge-15", 1.0e-15},
{"MEG", "RES_M(%1)", 1.0e6 },
{"k", "RES_K(%1)", 1.0e3 }, /* eagle */
{"K", "RES_K(%1)", 1.0e3 },
{"", "%1", 1.0e0 },
{"M", "CAP_M(%1)", 1.0e-3 },
{"u", "CAP_U(%1)", 1.0e-6 }, /* eagle */
{"U", "CAP_U(%1)", 1.0e-6 },
{"??", "CAP_U(%1)", 1.0e-6 },
{"N", "CAP_N(%1)", 1.0e-9 },
{"P", "CAP_P(%1)", 1.0e-12},
{"F", "%1e-15", 1.0e-15},
{"MIL", "%e", 25.4e-6},
{"MIL", "%1", 25.4e-6},
{"-", "%g", 1.0 }
{"-", "%1", 1.0 }
};
@ -345,7 +345,7 @@ void nl_convert_spice_t::process_line(const pstring &line)
add_device(tname, xname);
for (std::size_t i=1; i < tt.size() - 1; i++)
{
pstring term = pstring::sprintf("%s.%" SIZETFMT, xname.cstr(), SIZET_PRINTF(i));
pstring term = pformat("%1.%2")(xname)(i);
add_term(tt[i], term);
}
break;

View File

@ -277,7 +277,7 @@ struct input_t
double t;
int e = line.scanf("%lf,%[^,],%lf", &t, buf, &m_value);
if ( e!= 3)
throw netlist::fatalerror_e(pstring::sprintf("error %d scanning line %s\n", e, line.cstr()));
throw netlist::fatalerror_e(pformat("error %1 scanning line %2\n")(e)(line));
m_time = netlist::netlist_time::from_double(t);
m_param = netlist->setup().find_param(buf, true);
}
@ -288,7 +288,7 @@ struct input_t
{
case netlist::param_t::MODEL:
case netlist::param_t::STRING:
throw netlist::fatalerror_e(pstring::sprintf("param %s is not numeric\n", m_param->name().cstr()));
throw netlist::fatalerror_e(pformat("param %1 is not numeric\n")(m_param->name()));
case netlist::param_t::DOUBLE:
static_cast<netlist::param_double_t*>(m_param)->setTo(m_value);
break;
@ -380,12 +380,11 @@ static void listdevices()
for (int i=0; i < list.size(); i++)
{
netlist::base_factory_t *f = list.value_at(i);
pstring out = pstring::sprintf("%-20s %s(<id>", f->classname().cstr(),
f->name().cstr() );
pstring out = pformat("%1 %2(<id>")(f->classname(),"-20")(f->name());
pstring terms("");
netlist::device_t *d = f->Create();
d->init(nt, pstring::sprintf("dummy%d", i));
d->init(nt, pformat("dummy%1")(i));
d->start_dev();
// get the list of terminals ...