Turn psring iterator into a real forward iterator that works with standard algorithms.

There are a few changes to achieve this:
* Rename to const_iterator since it's immutable
* Typedef iterator to const_iterator for now as there's no mutable iterator
* Add default constrcutor and operator-> required by concept, const-qualify operators
* Remove operator+ and operator+= since it's not a random-access iterator (use std::next and std::advance instead)
* Return reference/pointer to a proxy rather than a code_t value from opertator*/operator->

The final change is required to meet the requirement that operator* for
two equivalent forward iterators return an equivalent reference.  The
pstring doesn't actually contain a sequence of code_t, so there's no way
to return a reference to code_t directly.  Instead, a reference to a
proxy object aliased on the string storage is returned.  The proxy is
implicitly convertible to code_t.  The most noticeable side effect is
that auto c = *s.begin() or for (auto c : s) won't work.  You need to do
for (auto &c : s) or for (code_t c : s) instead.
This commit is contained in:
Vas Crabb 2017-03-30 15:23:23 +11:00
parent 35b673ea45
commit 5e8fefbb12
8 changed files with 85 additions and 53 deletions

View File

@ -100,7 +100,7 @@ void setup_t::register_model(const pstring &model_in)
if (pos == model_in.end())
log().fatal(MF_1_UNABLE_TO_PARSE_MODEL_1, model_in);
pstring model = model_in.left(pos).trim().ucase();
pstring def = model_in.substr(pos + 1).trim();
pstring def = model_in.substr(std::next(pos, 1)).trim();
if (!m_models.insert({model, def}).second)
log().fatal(MF_1_MODEL_ALREADY_EXISTS_1, model_in);
}
@ -818,11 +818,11 @@ void setup_t::model_parse(const pstring &model_in, detail::model_map_t &map)
log().fatal(MF_1_MODEL_NOT_FOUND, model_in);
}
pstring remainder=model.substr(pos+1).trim();
pstring remainder=model.substr(std::next(pos, 1)).trim();
if (!remainder.endsWith(")"))
log().fatal(MF_1_MODEL_ERROR_1, model);
// FIMXE: Not optimal
remainder = remainder.left(remainder.begin() + (remainder.len() - 1));
remainder = remainder.left(std::next(remainder.begin(), (remainder.len() - 1)));
std::vector<pstring> pairs(plib::psplit(remainder," ", true));
for (pstring &pe : pairs)
@ -830,7 +830,7 @@ void setup_t::model_parse(const pstring &model_in, detail::model_map_t &map)
auto pose = pe.find("=");
if (pose == pe.end())
log().fatal(MF_1_MODEL_ERROR_ON_PAIR_1, model);
map[pe.left(pose).ucase()] = pe.substr(pose+1);
map[pe.left(pose).ucase()] = pe.substr(std::next(pose, 1));
}
}
@ -854,7 +854,7 @@ nl_double setup_t::model_value(detail::model_map_t &map, const pstring &entity)
pstring tmp = model_value_str(map, entity);
nl_double factor = NL_FCONST(1.0);
auto p = tmp.begin() + (tmp.len() - 1);
auto p = std::next(tmp.begin(), (tmp.len() - 1));
switch (*p)
{
case 'M': factor = 1e6; break;
@ -870,7 +870,7 @@ nl_double setup_t::model_value(detail::model_map_t &map, const pstring &entity)
log().fatal(MF_1_UNKNOWN_NUMBER_FACTOR_IN_1, entity);
}
if (factor != NL_FCONST(1.0))
tmp = tmp.left(tmp.begin() + (tmp.len() - 1));
tmp = tmp.left(std::next(tmp.begin(), (tmp.len() - 1)));
return tmp.as_double() * factor;
}
@ -976,7 +976,7 @@ void setup_t::register_define(pstring defstr)
{
auto p = defstr.find("=");
if (p != defstr.end())
register_define(defstr.left(p), defstr.substr(p+1));
register_define(defstr.left(p), defstr.substr(std::next(p, 1)));
else
register_define(defstr, "1");
}

View File

@ -86,7 +86,7 @@ static int get_prio(pstring v)
{
if (v == "(" || v == ")")
return 1;
else if (v.left(v.begin()+1) >= "a" && v.left(v.begin()+1) <= "z")
else if (v.left(std::next(v.begin(),1)) >= "a" && v.left(std::next(v.begin(),1)) <= "z")
return 0;
else if (v == "*" || v == "/")
return 20;

View File

@ -133,8 +133,8 @@ namespace plib {
}
else if (arg.startsWith("-"))
{
auto p = arg.begin() + 1;
opt = getopt_short(arg.substr(p,p + 1));
auto p = std::next(arg.begin(), 1);
opt = getopt_short(arg.substr(p, std::next(p, 1)));
++p;
if (p != arg.end())
{
@ -226,7 +226,7 @@ namespace plib {
{
line += v + "|";
}
line = line.left(line.begin() + (line.len() - 1));
line = line.left(std::next(line.begin(), (line.len() - 1)));
}
else
line += "Value";

View File

@ -104,7 +104,7 @@ void pstring_t<F>::pcopy(const mem_t *from, std::size_t size)
}
template<typename F>
const pstring_t<F> pstring_t<F>::substr(const iterator &start, const iterator &end) const
const pstring_t<F> pstring_t<F>::substr(const const_iterator &start, const const_iterator &end) const
{
pstring_t ret;
//FIXME: throw ?
@ -116,7 +116,7 @@ template<typename F>
const pstring_t<F> pstring_t<F>::ucase() const
{
pstring_t ret = "";
for (auto c : *this)
for (code_t c : *this)
if (c >= 'a' && c <= 'z')
ret += (c - 'a' + 'A');
else
@ -125,12 +125,12 @@ const pstring_t<F> pstring_t<F>::ucase() const
}
template<typename F>
typename pstring_t<F>::iterator pstring_t<F>::find_first_not_of(const pstring_t &no) const
typename pstring_t<F>::const_iterator pstring_t<F>::find_first_not_of(const pstring_t &no) const
{
for (auto it = begin(); it != end(); ++it)
{
bool f = true;
for (auto const jt : no)
for (code_t const jt : no)
{
if (*it == jt)
{
@ -145,14 +145,14 @@ typename pstring_t<F>::iterator pstring_t<F>::find_first_not_of(const pstring_t
}
template<typename F>
typename pstring_t<F>::iterator pstring_t<F>::find_last_not_of(const pstring_t &no) const
typename pstring_t<F>::const_iterator pstring_t<F>::find_last_not_of(const pstring_t &no) const
{
/* FIXME: reverse iterator */
iterator last_found = end();
/* FIXME: reverse const_iterator */
const_iterator last_found = end();
for (auto it = begin(); it != end(); ++it)
{
bool f = true;
for (auto const jt : no)
for (code_t const jt : no)
{
if (*it == jt)
{
@ -167,11 +167,11 @@ typename pstring_t<F>::iterator pstring_t<F>::find_last_not_of(const pstring_t &
}
template<typename F>
typename pstring_t<F>::iterator pstring_t<F>::find(const pstring_t &search, iterator start) const
typename pstring_t<F>::const_iterator pstring_t<F>::find(const pstring_t &search, const_iterator start) const
{
for (; start != end(); ++start)
{
iterator itc(start);
const_iterator itc(start);
auto cmp = search.begin();
while (itc != end() && cmp != search.end() && *itc == *cmp)
{
@ -185,7 +185,7 @@ typename pstring_t<F>::iterator pstring_t<F>::find(const pstring_t &search, iter
}
template<typename F>
typename pstring_t<F>::iterator pstring_t<F>::find(const code_t search, iterator start) const
typename pstring_t<F>::const_iterator pstring_t<F>::find(const code_t search, const_iterator start) const
{
mem_t buf[traits::MAXCODELEN+1] = { 0 };
traits::encode(search, buf);
@ -205,7 +205,7 @@ pstring_t<F> pstring_t<F>::replace(const pstring_t &search, const pstring_t &rep
{
ret += substr(last_s, s);
ret += replace;
last_s = s + slen;
last_s = std::next(s, slen);
s = find(search, last_s);
}
ret += substr(last_s, end());
@ -225,7 +225,7 @@ const pstring_t<F> pstring_t<F>::rtrim(const pstring_t &ws) const
if (f==end())
return pstring_t("");
else
return substr(begin(), f + 1);
return substr(begin(), std::next(f, 1));
}
template<typename F>

View File

@ -82,25 +82,57 @@ public:
// assignment operators
pstring_t &operator=(const pstring_t &string) { pcopy(string); return *this; }
struct iterator final : public std::iterator<std::forward_iterator_tag, mem_t>
class const_iterator final
{
const mem_t * p;
public:
explicit constexpr iterator(const mem_t *x) noexcept : p(x) {}
iterator(const iterator &rhs) noexcept = default;
iterator(iterator &&rhs) noexcept { p = rhs.p; }
iterator &operator=(const iterator &it) { p = it.p; return *this; }
iterator& operator++() noexcept { p += traits::codelen(p); return *this; }
iterator operator++(int) noexcept { iterator tmp(*this); operator++(); return tmp; }
bool operator==(const iterator& rhs) noexcept { return p==rhs.p; }
bool operator!=(const iterator& rhs) noexcept { return p!=rhs.p; }
const code_t operator*() noexcept { return traits::code(p); }
iterator& operator+=(size_type count) { while (count>0) { --count; ++(*this); } return *this; }
friend iterator operator+(iterator lhs, const size_type &rhs) { return (lhs += rhs); }
class value_type final
{
public:
value_type() = delete;
value_type(const value_type &) = delete;
value_type(value_type &&) = delete;
value_type &operator=(const value_type &) = delete;
value_type &operator=(value_type &&) = delete;
operator code_t() const noexcept { return traits::code(&m); }
private:
const mem_t m;
};
typedef value_type const *pointer;
typedef value_type const &reference;
typedef std::ptrdiff_t difference_type;
typedef std::forward_iterator_tag iterator_category;
const_iterator() noexcept : p(nullptr) { }
explicit constexpr const_iterator(const mem_t *x) noexcept : p(x) { }
const_iterator(const const_iterator &rhs) noexcept = default;
const_iterator(const_iterator &&rhs) noexcept = default;
const_iterator &operator=(const const_iterator &rhs) noexcept = default;
const_iterator &operator=(const_iterator &&rhs) noexcept = default;
const_iterator& operator++() noexcept { p += traits::codelen(p); return *this; }
const_iterator operator++(int) noexcept { const_iterator tmp(*this); operator++(); return tmp; }
bool operator==(const const_iterator& rhs) const noexcept { return p == rhs.p; }
bool operator!=(const const_iterator& rhs) const noexcept { return p != rhs.p; }
reference operator*() const noexcept { return *reinterpret_cast<pointer>(p); }
pointer operator->() const noexcept { return reinterpret_cast<pointer>(p); }
private:
template <typename G> friend struct pstring_t;
const mem_t * p;
};
iterator begin() const { return iterator(m_ptr->str()); }
iterator end() const { return iterator(m_ptr->str() + blen()); }
// no non-const const_iterator for now
typedef const_iterator iterator;
iterator begin() { return iterator(m_ptr->str()); }
iterator end() { return iterator(m_ptr->str() + blen()); }
const_iterator begin() const { return const_iterator(m_ptr->str()); }
const_iterator end() const { return const_iterator(m_ptr->str() + blen()); }
const_iterator cbegin() const { return const_iterator(m_ptr->str()); }
const_iterator cend() const { return const_iterator(m_ptr->str() + blen()); }
// C string conversion helpers
const mem_t *c_str() const { return m_ptr->str(); }
@ -141,20 +173,20 @@ public:
pstring_t& operator+=(const code_t c) { mem_t buf[traits::MAXCODELEN+1] = { 0 }; traits::encode(c, buf); pcat(buf); return *this; }
friend pstring_t operator+(const pstring_t &lhs, const code_t rhs) { return pstring_t(lhs) += rhs; }
iterator find(const pstring_t &search, iterator start) const;
iterator find(const pstring_t &search) const { return find(search, begin()); }
iterator find(const code_t search, iterator start) const;
iterator find(const code_t search) const { return find(search, begin()); }
const_iterator find(const pstring_t &search, const_iterator start) const;
const_iterator find(const pstring_t &search) const { return find(search, begin()); }
const_iterator find(const code_t search, const_iterator start) const;
const_iterator find(const code_t search) const { return find(search, begin()); }
const pstring_t substr(const iterator &start, const iterator &end) const ;
const pstring_t substr(const iterator &start) const { return substr(start, end()); }
const pstring_t substr(size_type start) const { return (start >= len()) ? pstring_t("") : substr(begin() + start, end()); }
const pstring_t substr(const const_iterator &start, const const_iterator &end) const;
const pstring_t substr(const const_iterator &start) const { return substr(start, end()); }
const pstring_t substr(size_type start) const { return (start >= len()) ? pstring_t("") : substr(std::next(begin(), start), end()); }
const pstring_t left(iterator leftof) const { return substr(begin(), leftof); }
const pstring_t right(iterator pos) const { return substr(pos, end()); }
const pstring_t left(const_iterator leftof) const { return substr(begin(), leftof); }
const pstring_t right(const_iterator pos) const { return substr(pos, end()); }
iterator find_first_not_of(const pstring_t &no) const;
iterator find_last_not_of(const pstring_t &no) const;
const_iterator find_first_not_of(const pstring_t &no) const;
const_iterator find_last_not_of(const pstring_t &no) const;
const pstring_t ltrim(const pstring_t &ws = pstring_t(" \t\n\r")) const;
const pstring_t rtrim(const pstring_t &ws = pstring_t(" \t\n\r")) const;

View File

@ -52,7 +52,7 @@ namespace plib
pstring t = str.substr(p, pn);
if (!ignore_empty || t.len() != 0)
ret.push_back(t);
p = pn + onstr.len();
p = std::next(pn, onstr.len());
pn = str.find(onstr, p);
}
if (p != str.end())

View File

@ -421,7 +421,7 @@ void tool_app_t::mac_out(const pstring &s, const bool cont)
if (cont)
{
unsigned adj = 0;
for (auto x : s)
for (auto &x : s)
adj += (x == '\t' ? 3 : 0);
pout("{1}\\\n", s.rpad(" ", RIGHT-1-adj));
}

View File

@ -318,7 +318,7 @@ void nl_convert_spice_t::process_line(const pstring &line)
{
if (m[1].len() != 4)
fprintf(stderr, "error with model desc %s\n", model.c_str());
pins = m[1].left(m[1].begin() + 3);
pins = m[1].left(std::next(m[1].begin(), 3));
}
add_device("QBJT_EB", tt[0], m[0]);
add_term(tt[1], tt[0] + "." + pins.code_at(0));