26 #ifndef SHORE_MISC_STRINGOPS_HPP__
27 #define SHORE_MISC_STRINGOPS_HPP__
44 #include <boost/utility/enable_if.hpp>
45 #include <boost/type_traits.hpp>
58 bool operator()(
const std::string& s0,
const std::string& s1)
const;
62 template<
typename Iter>
78 template<
typename iter_type,
79 typename delim_type=
typename std::iterator_traits<iter_type>::value_type>
84 std::pair<iter_type,iter_type> m_range;
85 const iter_type m_end;
86 const delim_type m_delim;
94 typedef std::pair<iter_type,iter_type> current_type;
97 :m_range(beg,std::find(beg,end,d)),
98 m_end(end),m_delim(d),m_index(0),m_hasdata(
true)
101 const std::pair<iter_type,iter_type>& current()
const
106 bool has_data()
const
113 if(m_range.second==m_end)
120 m_range.first=m_range.second;
121 m_range.second=std::find(m_range.first,m_end,m_delim);
134 template<
typename iter_type,
typename delim_iter_type>
139 std::pair<iter_type,iter_type> m_range;
140 const iter_type m_end;
141 const delim_iter_type m_dbeg;
142 const delim_iter_type m_dend;
150 typedef std::pair<iter_type,iter_type> current_type;
153 const delim_iter_type& dbeg,
const delim_iter_type& dend)
154 :m_range(beg,std::find_first_of(beg,end,dbeg,dend)),
155 m_end(end),m_dbeg(dbeg),m_dend(dend),m_index(0),m_hasdata(
true)
158 const std::pair<iter_type,iter_type>& current()
const
163 bool has_data()
const
170 if(m_range.second==m_end)
177 m_range.first=m_range.second;
178 m_range.second=std::find_first_of(m_range.first,m_end,m_dbeg,m_dend);
191 template<
typename iter_type,
typename delim_type>
196 std::pair<iter_type,iter_type> m_range;
197 const iter_type m_end;
198 const delim_type m_delim;
205 typedef std::pair<iter_type,iter_type> current_type;
208 :m_range(beg,std::find(beg,end,d)),
209 m_end(end),m_delim(d),m_index(0),m_hasdata(
true)
212 const std::pair<iter_type,iter_type>& current()
const
217 bool has_data()
const
224 if(m_range.second==m_end)
234 while((m_range.second!=m_end)&&((*m_range.second)==m_delim))
237 m_range.first=m_range.second;
238 m_range.second=std::find(m_range.first,m_end,m_delim);
252 template<
typename iter_type,
typename delim_iter_type>
257 std::pair<iter_type,iter_type> m_range;
258 const iter_type m_end;
259 const delim_iter_type m_dbeg;
260 const delim_iter_type m_dend;
268 typedef std::pair<iter_type,iter_type> current_type;
271 const delim_iter_type& dbeg,
const delim_iter_type& dend)
272 :m_range(beg,std::find_first_of(beg,end,dbeg,dend)),
273 m_end(end),m_dbeg(dbeg),m_dend(dend),m_index(0),m_hasdata(
true)
276 const std::pair<iter_type,iter_type>& current()
const
281 bool has_data()
const
288 if(m_range.second==m_end)
298 while((m_range.second!=m_end)
299 &&(std::find(m_dbeg,m_dend,*m_range.second)!=m_dend))
302 m_range.first=m_range.second;
303 m_range.second=std::find_first_of(m_range.first,m_end,m_dbeg,m_dend);
316 template<
typename iter_type,
typename delim_iter_type>
321 std::pair<iter_type,iter_type> m_range;
322 const iter_type m_end;
323 const delim_iter_type m_dbeg;
324 const delim_iter_type m_dend;
332 typedef std::pair<iter_type,iter_type> current_type;
335 const delim_iter_type& dbeg,
const delim_iter_type& dend)
336 :m_range(beg,std::search(beg,end,dbeg,dend)),
337 m_end(end),m_dbeg(dbeg),m_dend(dend),m_index(0),m_hasdata(
true)
340 const std::pair<iter_type,iter_type>& current()
const
345 bool has_data()
const
352 if(m_range.second==m_end)
358 for(delim_iter_type di=m_dbeg;di!=m_dend;++di)
362 m_range.first=m_range.second;
363 m_range.second=std::search(m_range.first,m_end,m_dbeg,m_dend);
377 template<
typename iter_type,
typename delim_iter_type>
382 std::pair<iter_type,iter_type> m_range;
383 const iter_type m_end;
384 const delim_iter_type m_dbeg;
385 const delim_iter_type m_dend;
386 delim_iter_type m_aux;
394 typedef std::pair<iter_type,iter_type> current_type;
397 const delim_iter_type& dbeg,
const delim_iter_type& dend)
398 :m_range(beg,std::search(beg,end,dbeg,dend)),
399 m_end(end),m_dbeg(dbeg),m_dend(dend),m_aux(dbeg),
400 m_index(0),m_hasdata(
true)
403 const std::pair<iter_type,iter_type>& current()
const
408 bool has_data()
const
415 if(m_range.second==m_end)
429 m_range.first=m_range.second;
430 m_range.second=std::search(m_range.first,m_end,m_dbeg,m_dend);
432 while((m_range.first==m_range.second)&&(m_range.second!=m_end))
447 template<
typename T,T termval=T()>
449 :
public std::iterator<std::forward_iterator_tag,T>
459 if((c==0)||((*c)==termval))
476 return m_ptr==other.m_ptr;
481 return m_ptr!=other.m_ptr;
489 T* operator->()
const
497 if((*m_ptr)==termval)
506 if((*m_ptr)==termval)
513 std::vector<std::string>
split(
const std::string& s,
const char delim=
'\t');
517 std::vector<std::string>
split(
const std::string& s,
const char*
const delims);
521 std::vector<std::string>
tsplit(
const std::string& s,
const char delim=
'\t');
525 std::vector<std::string>
tsplit(
const std::string& s,
const char*
const delims);
529 std::vector<std::string>
lsplit(
const std::string& s,
const std::string& delim);
533 std::vector<std::string>
ltsplit(
const std::string& s,
const std::string& delim);
538 template<
class StringIterator>
539 size_t split(
const std::string& s,StringIterator destination,
540 const char delim=
'\t',
541 const size_t limit=std::numeric_limits<size_t>::max()-1)
543 typedef std::string::const_iterator iter_t;
544 typedef std::pair<iter_t,iter_t> range_t;
547 tok_t tok(s.begin(),s.end(),delim);
549 const range_t& r=tok.current();
550 destination->assign(r.first,r.second);
555 while(tok.has_data()&&(tok.index()<limit))
557 const range_t& r=tok.current();
559 destination->assign(r.first,r.second);
565 return tok.index()+1;
571 template<
class StringIterator>
572 size_t split(
const std::string& s,StringIterator destination,
573 const char*
const delims,
574 const size_t limit=std::numeric_limits<size_t>::max()-1)
576 typedef std::string::const_iterator iter_t;
577 typedef std::pair<iter_t,iter_t> range_t;
581 tok_t tok(s.begin(),s.end(),delim_iter_t(delims),delim_iter_t());
583 const range_t& r=tok.current();
584 destination->assign(r.first,r.second);
589 while(tok.has_data()&&(tok.index()<limit))
591 const range_t& r=tok.current();
593 destination->assign(r.first,r.second);
599 return tok.index()+1;
606 template<
class StringIterator>
607 size_t tsplit(
const std::string& s,StringIterator destination,
608 const char delim=
'\t',
609 const size_t limit=std::numeric_limits<size_t>::max()-1)
611 typedef std::string::const_iterator iter_t;
612 typedef std::pair<iter_t,iter_t> range_t;
615 tok_t tok(s.begin(),s.end(),delim);
617 const range_t& r=tok.current();
618 destination->assign(r.first,r.second);
623 while(tok.has_data()&&(tok.index()<limit))
625 const range_t& r=tok.current();
627 destination->assign(r.first,r.second);
633 return tok.index()+1;
640 template<
class StringIterator>
641 size_t tsplit(
const std::string& s,StringIterator destination,
642 const char*
const delims,
643 const size_t limit=std::numeric_limits<size_t>::max()-1)
645 typedef std::string::const_iterator iter_t;
646 typedef std::pair<iter_t,iter_t> range_t;
650 tok_t tok(s.begin(),s.end(),delim_iter_t(delims),delim_iter_t());
652 const range_t& r=tok.current();
653 destination->assign(r.first,r.second);
658 while(tok.has_data()&&(tok.index()<limit))
660 const range_t& r=tok.current();
662 destination->assign(r.first,r.second);
668 return tok.index()+1;
677 std::ostringstream os;
678 os<<std::setprecision(prec)<<value;
683 template<
typename T,
int precision>
686 std::ostringstream os;
687 os<<std::setprecision(precision)<<value;
695 return to_string<T,14>(value);
700 std::string to_string<bool>(
const bool& value)
702 return value?
"yes":
"no";
708 std::string to_string<std::ostringstream>(
const std::ostringstream& str)
716 std::string to_string<std::string>(
const std::string& s)
725 std::string
join(Iter begin,Iter
end,
const std::string& delim)
744 std::string
join(
const Iter begin,
const Iter
end)
746 return join(begin,end,
"\t");
751 std::string
join(
const std::vector<T>& sv,
const std::string& delim)
753 return join(sv.begin(),sv.end(),delim);
758 std::string
join(
const std::vector<T>& sv)
760 return join(sv.begin(),sv.end());
764 template<
class Iteriter>
765 std::string
ijoin(Iteriter begin,Iteriter
end,
const std::string& delim)
783 template<
typename Iter>
784 std::string
ijoin(
const std::vector<Iter>& sv,
const std::string &delim)
786 return ijoin(sv.begin(),sv.end(),delim);
791 std::vector<std::vector<std::string> >& pv,
const std::string& delim)
793 std::vector<std::string> ret;
794 for(
size_t i=0;i<pv.size();++i)
795 ret.push_back(
join(pv[i],delim));
810 std::string
to_string(
const std::vector<std::vector<T> >& v)
818 template<
typename conv_type,
void (*initfunc)(conv_type *const)>
822 template<
typename conv_type,
void (*initfunc)(conv_type *const)>
827 friend const conv_type *chartab<conv_type,initfunc>();
839 static ptrmgr m_instance;
841 conv_type m_table[256];
850 template<
typename conv_type,
void (*initfunc)(conv_type *const)>
860 template<
typename conv_type,
void (*initfunc)(conv_type *const)>
861 typename chartable<conv_type,initfunc>::ptrmgr chartable<conv_type,initfunc>::m_instance;
871 for(
int i=0;i<exp;++i)
873 for(
unsigned int i=0;i<256;++i)
882 else if((i>=uint8_t(
'1'))&&(i<=uint8_t(
'9')))
885 table[i]=signif*(i-uint8_t(
'0'));
889 else if(i==uint8_t(
'-'))
891 else if(i==uint8_t(
'+'))
893 else if(i==uint8_t(
'.'))
895 else if(i==uint8_t(
'e'))
897 else if(i==uint8_t(
'E'))
899 else if(i==uint8_t(
' '))
901 else if(i==uint8_t(
'\t'))
903 else if(i==uint8_t(
'\n'))
913 extern const int *
const ctab_digit;
914 extern const int64_t *
const ctab_expdigit[21];
917 template<
typename iter_type>
921 throw std::runtime_error(
"parse_uint64: empty range");
924 const int64_t *
const *digtab=ctab_expdigit;
930 const int64_t d=(*digtab)[uint8_t(*end)];
945 uint64_t((*(digtab-1))[uint8_t(
'1')])*10;
947 if((std::numeric_limits<uint64_t>::max()-d2)>=ret)
950 throw std::runtime_error(
"parse_uint64: out of range: "
951 +std::string(beg,++end));
954 throw std::runtime_error(
"parse_uint64: out of range: "
955 +std::string(beg,++end));
958 throw std::runtime_error(
"parse_uint64: sign error: "
959 +std::string(beg,++end));
960 throw std::runtime_error(
"parse_uint64: conversion error 2: "
961 +std::string(beg,++end));
964 throw std::runtime_error(
"parse_uint64: conversion error: "
965 +std::string(beg,++end));
978 template<
typename iter_type>
982 throw std::runtime_error(
"parse_uint64: empty range");
985 const int64_t *
const *digtab=ctab_expdigit;
991 const int64_t d=(*digtab)[uint8_t(*end)];
1000 if(ret>(1+uint64_t(std::numeric_limits<int64_t>::max())))
1001 throw std::runtime_error(
"parse_int64: out of range: "
1002 +std::string(beg,++end));
1004 return -(int64_t(ret));
1014 const uint64_t d2=uint64_t((*(digtab-1))[uint8_t(
'1')])*10;
1016 if((std::numeric_limits<uint64_t>::max()-d2)>=ret)
1019 throw std::runtime_error(
"parse_int64: out of range: "
1020 +std::string(beg,++end));
1023 throw std::runtime_error(
"parse_int64: out of range: "
1024 +std::string(beg,++end));
1026 throw std::runtime_error(
"parse_int64: conversion error 2: "
1027 +std::string(beg,++end));
1030 throw std::runtime_error(
"parse_int64: conversion error: "
1031 +std::string(beg,++end));
1040 if(ret>uint64_t(std::numeric_limits<int64_t>::max()))
1041 throw std::runtime_error(
"parse_int64: out of range: "
1042 +std::string(beg,end));
1052 template<
typename T>
1055 std::istringstream sstr(str);
1056 if(!(sstr>>std::noskipws>>(*dest)))
1057 throw std::runtime_error(
"stream conversion failed for \""+str+
"\"");
1058 if((sstr.peek()!=EOF))
1059 throw std::runtime_error(
1060 "stream conversion failed for \""+str+
"\": trailing characters");
1065 inline void parse_value<std::string>(std::string* dest,
const std::string& str)
1077 template<
typename T>
1081 parse_value<T>(&value,str);
1089 double value=std::atof(str.c_str());
1101 template<
typename iter_type>
1104 dest->assign(beg,end);
1108 template<
typename iter_type>
1115 template<
typename iter_type>
1122 template<
typename T,
typename iter_type>
1124 typename boost::enable_if<boost::is_integral<T> >::type *dummy_int=0,
1125 typename boost::enable_if<boost::is_signed<T> >::type *dummy_sign=0)
1128 if((v>int64_t(std::numeric_limits<T>::max()))
1129 ||(v<int64_t(std::numeric_limits<T>::min())))
1130 throw std::runtime_error(
"parse_value: out of range");
1135 template<
typename T,
typename iter_type>
1137 typename boost::enable_if<boost::is_integral<T> >::type *dummy_int=0,
1138 typename boost::disable_if<boost::is_signed<T> >::type *dummy_sign=0)
1141 if(v>uint64_t(std::numeric_limits<T>::max()))
1142 throw std::runtime_error(
"parse_value: out of range");
1148 template<
typename Dest,
typename Default>
1149 void parse_envvar(Dest *
const dest,
const std::string &envvar,
const Default &def)
1151 const char *
const env=std::getenv(envvar.c_str());
1160 template<
typename Dest,
typename Default>
1176 template<
typename Iterator>
1177 bool equal_ci(
const std::string &s,Iterator b,Iterator e)
1179 return (s.size()==size_t(e-b))&&std::equal(b,e,s.begin(),
charcmp_equal_ci);
1183 bool starts_with_cs(
const std::string& s,
const std::string& pref);
1185 bool ends_with_cs(
const std::string& s,
const std::string& suff);
1187 bool starts_with_ci(
const std::string& s,
const std::string& pref);
1189 bool ends_with_ci(
const std::string& s,
const std::string& suff);
1191 std::string
toggle_suffix_cs(
const std::string& s,
const std::string& suff);
1193 std::string
remove_suffix_cs(
const std::string& s,
const std::string& suff);
1195 std::string
toggle_suffix_ci(
const std::string& s,
const std::string& suff);
1197 std::string
remove_suffix_ci(
const std::string& s,
const std::string& suff);
1203 std::string
lprefix(
const T& what,
const std::string& prefix)
1205 const std::string whatstr=to_string<T>(what);
1209 return prefix+
join(
split(whatstr,
'\n'),
"\n"+prefix);
1213 std::vector<std::string>
wrap_line(
const std::string& line,
const size_t maxlw);
1216 void expand_tabs(std::istream& in,std::ostream& out,
1218 const std::vector<size_t>& maxwidths=std::vector<size_t>(),
1219 const bool headings=
true);
1224 const std::vector<size_t>& maxwidths=std::vector<size_t>(),
1225 const bool headings=
true);
1228 template<
class Iter>
1231 Iter b_maxwidths,Iter e_maxwidths,
1232 const bool headings=
true)
1234 const std::vector<size_t> maxwidths(b_maxwidths,e_maxwidths);
1235 return expand_tabs(str,colsep,maxwidths,headings);
1240 template<
typename Iter>
1243 while((beg!=end)&&std::isspace(*beg)) ++beg;
1244 while((beg!=end)&&std::isspace(*(end-1))) --
end;
1245 return std::make_pair(beg,end);
1254 typedef std::ios_base& (*manip_type)(std::ios_base&);
1256 const manip_type manip;
1261 manipd(manip_type m=0,
int f=0,
int w=0,
int p=0):
1262 manip(m),fill(f),width(w),precision(p)
1264 manipd(
const T& v,manip_type m=0,
int f=0,
int w=0,
int p=0)
1265 :value(v),manip(m),fill(f),width(w),precision(p)
1270 std::ostream& operator<<(std::ostream& os,const manipd<T>& mp)
1272 const std::ios_base::fmtflags fl=os.flags();
1273 const int fc=os.fill();
1274 const int fw=os.width();
1275 const int pr=os.precision();
1285 os.precision(mp.precision);
1301 std::istream&
operator>>(std::istream& is,manipd<T>& mp)
1303 const std::ios_base::fmtflags fl=is.flags();
1315 template<
typename exception_type>
1316 void throw_exception(
const std::string &msg)
1318 throw exception_type(msg);
1323 inline void throw_exception<void>(
const std::string &msg)
1334 template<
class exception_type,
class Iter>
1336 const std::string& arg,Iter beg,Iter
end,
1337 const std::string& exlabel=std::string(
"match_arg"))
1339 std::string arg_lc=arg;
1341 std::vector<std::string> matches;
1342 std::vector<Iter> positions;
1345 for(Iter i=beg;i!=
end;++i)
1352 throw_exception<exception_type>(exlabel
1353 +
" - tried to match an empty string");
1356 for(Iter i=beg;i!=
end;++i)
1358 std::string match_lc=*i;
1360 if(match_lc==arg_lc)
1362 matches.push_back(*i);
1363 positions.push_back(i);
1367 if(!positions.empty())
1369 if(positions.size()==1)
1370 return positions.front();
1371 throw_exception<exception_type>(exlabel+
" - ambiguous match for \""
1372 +arg+
"\": "+
join(matches,
", "));
1377 for(Iter i=beg;i!=
end;++i)
1379 if(i->substr(0,arg.size())==arg)
1381 matches.push_back(*i);
1382 positions.push_back(i);
1386 if(!positions.empty())
1388 if(positions.size()==1)
1389 return positions.front();
1390 throw_exception<exception_type>(
1391 exlabel+
" - ambiguous match for \""+arg+
"\": "+
join(matches,
", "));
1396 for(Iter i=beg;i!=
end;++i)
1398 std::string match_lc=*i;
1400 if(match_lc.substr(0,arg_lc.size())==arg_lc)
1402 matches.push_back(*i);
1403 positions.push_back(i);
1407 if(positions.size()==1)
1408 return positions.front();
1410 if(positions.empty())
1411 throw_exception<exception_type>(exlabel+
" - no match for \""+arg+
"\"");
1413 if(positions.size()>1)
1414 throw_exception<exception_type>(exlabel+
" - ambiguous match for \""
1415 +arg+
"\": "+
join(matches,
", "));
1421 template<
class Ex,
class Iter>
1423 const std::string& arg,Iter beg,Iter end,
1424 const std::string& exlabel=std::string(
"match_arg"))
1426 return match_arg<Ex,Iter>(arg,beg,
end,exlabel)-beg;
1430 template<
typename Enum,
typename Iter>
1431 std::istream &
parse_enum(std::istream &in,Enum &dest,Iter beg,Iter end)
1438 dest=
static_cast<Enum
>(
1439 match_arg_idx<std::runtime_error>(buf,beg,
end));
1441 catch(
const std::runtime_error &)
1443 in.setstate(std::ios_base::failbit);
1449 template<
typename Enum,
int SZ>
1450 std::istream &
parse_enum(std::istream &in,Enum &dest,
const std::string (&templ)[SZ])
1455 template<
typename Enum>
1459 #define MAKE_ENUM_TRAITS(T)\
1462 struct enum_traits<T>\
1464 typedef std::istream istream_type;\
1465 typedef std::ostream ostream_type;\
1466 static const std::string values;\
1467 static const std::string description;\
1472 #define S_MAKE_ENUM_TRAITS(T)\
1474 struct enum_traits<T>\
1476 typedef std::istream istream_type;\
1477 typedef std::ostream ostream_type;\
1478 static const std::string values;\
1479 static const std::string description;\
1483 template<
typename Enum>
1484 typename enum_traits<Enum>::istream_type &
operator>>(std::istream &in,Enum &en)
1486 const std::vector<std::string> values=
1492 template<
typename Enum>
1493 typename enum_traits<Enum>::ostream_type &
operator<<(std::ostream &out,
const Enum &en)
1495 const std::vector<std::string> labels=
1497 if((static_cast<int>(en)<0)
1498 ||(static_cast<size_t>(en)>labels.size())
1499 ||labels[en].empty())
1500 return out<<
"UNNAMED_ENUM_VALUE"<<static_cast<int>(en);
1501 return out<<labels[en];
1506 #endif // SHORE_MISC_STRINGOPS_HPP__