SHORE API
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
stringops.hpp
Go to the documentation of this file.
1 
2 /*
3  * Copyright 2008,2009,2010,2011,2012 Stephan Ossowski, Korbinian Schneeberger,
4  * Felix Ott, Joerg Hagmann, Alf Scotland, Sebastian Bender
5  *
6  * This file is part of SHORE.
7  *
8  * SHORE is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * SHORE is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with SHORE. If not, see <http://www.gnu.org/licenses/>.
20  */
21 
25 
26 #ifndef SHORE_MISC_STRINGOPS_HPP__
27 #define SHORE_MISC_STRINGOPS_HPP__
28 
29 #include <algorithm>
30 #include <cstdio>
31 #include <iomanip>
32 #include <ios>
33 #include <iostream>
34 #include <iterator>
35 #include <limits>
36 #include <stdexcept>
37 #include <sstream>
38 #include <string>
39 #include <vector>
40 
41 #include <stdint.h>
42 #include <fstream>
43 
44 #include <boost/utility/enable_if.hpp>
45 #include <boost/type_traits.hpp>
46 
47 namespace shore {
48 
50 void tolower(std::string& str);
51 
53 void toupper(std::string& str);
54 
56 struct iless
57 {
58  bool operator()(const std::string& s0,const std::string& s1) const;
59 };
60 
62 template<typename Iter>
63 bool is_numeric(Iter b,Iter e)
64 {
65  bool ret=(b!=e);
66  while(ret&&(b!=e))
67  {
68  ret=std::isdigit(*b);
69  ++b;
70  }
71  return ret;
72 }
73 
75 
78 template<typename iter_type,
79  typename delim_type=typename std::iterator_traits<iter_type>::value_type>
81 {
82  private:
83 
84  std::pair<iter_type,iter_type> m_range;
85  const iter_type m_end;
86  const delim_type m_delim;
87 
88  size_t m_index;
89  bool m_hasdata;
90 
91 
92  public:
93 
94  typedef std::pair<iter_type,iter_type> current_type;
95 
96  tok_occurrence(const iter_type& beg,const iter_type& end,const delim_type d)
97  :m_range(beg,std::find(beg,end,d)),
98  m_end(end),m_delim(d),m_index(0),m_hasdata(true)
99  {}
100 
101  const std::pair<iter_type,iter_type>& current() const
102  {
103  return m_range;
104  }
105 
106  bool has_data() const
107  {
108  return m_hasdata;
109  }
110 
111  void next()
112  {
113  if(m_range.second==m_end)
114  {
115  m_hasdata=false;
116  }
117  else
118  {
119  ++m_range.second;
120  m_range.first=m_range.second;
121  m_range.second=std::find(m_range.first,m_end,m_delim);
122  ++m_index;
123  }
124  }
125 
126  size_t index() const
127  {
128  return m_index;
129  }
130 };
131 
134 template<typename iter_type,typename delim_iter_type>
136 {
137  private:
138 
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;
143 
144  size_t m_index;
145  bool m_hasdata;
146 
147 
148  public:
149 
150  typedef std::pair<iter_type,iter_type> current_type;
151 
152  tok_occurrences(const iter_type& beg,const iter_type& end,
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)
156  {}
157 
158  const std::pair<iter_type,iter_type>& current() const
159  {
160  return m_range;
161  }
162 
163  bool has_data() const
164  {
165  return m_hasdata;
166  }
167 
168  void next()
169  {
170  if(m_range.second==m_end)
171  {
172  m_hasdata=false;
173  }
174  else
175  {
176  ++m_range.second;
177  m_range.first=m_range.second;
178  m_range.second=std::find_first_of(m_range.first,m_end,m_dbeg,m_dend);
179  ++m_index;
180  }
181  }
182 
183  size_t index() const
184  {
185  return m_index;
186  }
187 };
188 
191 template<typename iter_type,typename delim_type>
193 {
194  private:
195 
196  std::pair<iter_type,iter_type> m_range;
197  const iter_type m_end;
198  const delim_type m_delim;
199 
200  size_t m_index;
201  bool m_hasdata;
202 
203  public:
204 
205  typedef std::pair<iter_type,iter_type> current_type;
206 
207  tok_transition(const iter_type& beg,const iter_type& end,const delim_type d)
208  :m_range(beg,std::find(beg,end,d)),
209  m_end(end),m_delim(d),m_index(0),m_hasdata(true)
210  {}
211 
212  const std::pair<iter_type,iter_type>& current() const
213  {
214  return m_range;
215  }
216 
217  bool has_data() const
218  {
219  return m_hasdata;
220  }
221 
222  void next()
223  {
224  if(m_range.second==m_end)
225  {
226  m_hasdata=false;
227  }
228  else
229  {
230  do
231  {
232  ++m_range.second;
233  }
234  while((m_range.second!=m_end)&&((*m_range.second)==m_delim))
235  ;
236 
237  m_range.first=m_range.second;
238  m_range.second=std::find(m_range.first,m_end,m_delim);
239  ++m_index;
240  }
241  }
242 
243  size_t index() const
244  {
245  return m_index;
246  }
247 };
248 
252 template<typename iter_type,typename delim_iter_type>
254 {
255  private:
256 
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;
261 
262  size_t m_index;
263  bool m_hasdata;
264 
265 
266  public:
267 
268  typedef std::pair<iter_type,iter_type> current_type;
269 
270  tok_transitions(const iter_type& beg,const iter_type& end,
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)
274  {}
275 
276  const std::pair<iter_type,iter_type>& current() const
277  {
278  return m_range;
279  }
280 
281  bool has_data() const
282  {
283  return m_hasdata;
284  }
285 
286  void next()
287  {
288  if(m_range.second==m_end)
289  {
290  m_hasdata=false;
291  }
292  else
293  {
294  do
295  {
296  ++m_range.second;
297  }
298  while((m_range.second!=m_end)
299  &&(std::find(m_dbeg,m_dend,*m_range.second)!=m_dend))
300  ;
301 
302  m_range.first=m_range.second;
303  m_range.second=std::find_first_of(m_range.first,m_end,m_dbeg,m_dend);
304  ++m_index;
305  }
306  }
307 
308  size_t index() const
309  {
310  return m_index;
311  }
312 };
313 
316 template<typename iter_type,typename delim_iter_type>
318 {
319  private:
320 
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;
325 
326  size_t m_index;
327  bool m_hasdata;
328 
329 
330  public:
331 
332  typedef std::pair<iter_type,iter_type> current_type;
333 
334  ltok_occurrence(const iter_type& beg,const iter_type& end,
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)
338  {}
339 
340  const std::pair<iter_type,iter_type>& current() const
341  {
342  return m_range;
343  }
344 
345  bool has_data() const
346  {
347  return m_hasdata;
348  }
349 
350  void next()
351  {
352  if(m_range.second==m_end)
353  {
354  m_hasdata=false;
355  }
356  else
357  {
358  for(delim_iter_type di=m_dbeg;di!=m_dend;++di)
359  {
360  ++m_range.second;
361  }
362  m_range.first=m_range.second;
363  m_range.second=std::search(m_range.first,m_end,m_dbeg,m_dend);
364  ++m_index;
365  }
366  }
367 
368  size_t index() const
369  {
370  return m_index;
371  }
372 };
373 
377 template<typename iter_type,typename delim_iter_type>
379 {
380  private:
381 
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;
387 
388  size_t m_index;
389  bool m_hasdata;
390 
391 
392  public:
393 
394  typedef std::pair<iter_type,iter_type> current_type;
395 
396  ltok_transition(const iter_type& beg,const iter_type& end,
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)
401  {}
402 
403  const std::pair<iter_type,iter_type>& current() const
404  {
405  return m_range;
406  }
407 
408  bool has_data() const
409  {
410  return m_hasdata;
411  }
412 
413  void next()
414  {
415  if(m_range.second==m_end)
416  {
417  m_hasdata=false;
418  }
419  else
420  {
421  do
422  {
423  while(m_aux!=m_dend)
424  {
425  ++m_range.second;
426  ++m_aux;
427  }
428  m_aux=m_dbeg;
429  m_range.first=m_range.second;
430  m_range.second=std::search(m_range.first,m_end,m_dbeg,m_dend);
431  }
432  while((m_range.first==m_range.second)&&(m_range.second!=m_end))
433  ;
434 
435  ++m_index;
436  }
437  }
438 
439  size_t index() const
440  {
441  return m_index;
442  }
443 };
444 
447 template<typename T,T termval=T()>
449 :public std::iterator<std::forward_iterator_tag,T>
450 {
451  private:
452 
453  T* m_ptr;
454 
455  public:
456 
457  valterm_iterator(T*const c=0)
458  {
459  if((c==0)||((*c)==termval))
460  m_ptr=0;
461  else
462  m_ptr=c;
463  }
464 
465  valterm_iterator(const valterm_iterator& other)
466  :m_ptr(other.m_ptr)
467  {}
468 
469  valterm_iterator& operator=(const valterm_iterator& other)
470  {
471  m_ptr=other.m_ptr;
472  }
473 
474  bool operator==(const valterm_iterator& other)
475  {
476  return m_ptr==other.m_ptr;
477  }
478 
479  bool operator!=(const valterm_iterator& other)
480  {
481  return m_ptr!=other.m_ptr;
482  }
483 
484  T& operator*() const
485  {
486  return *m_ptr;
487  }
488 
489  T* operator->() const
490  {
491  return m_ptr;
492  }
493 
494  valterm_iterator& operator++()
495  {
496  ++m_ptr;
497  if((*m_ptr)==termval)
498  m_ptr=0;
499  return *this;
500  }
501 
502  valterm_iterator operator++(int)
503  {
504  valterm_iterator ret=*this;
505  ++m_ptr;
506  if((*m_ptr)==termval)
507  m_ptr=0;
508  return ret;
509  }
510 };
511 
513 std::vector<std::string> split(const std::string& s,const char delim='\t');
514 
517 std::vector<std::string> split(const std::string& s,const char*const delims);
518 
521 std::vector<std::string> tsplit(const std::string& s,const char delim='\t');
522 
525 std::vector<std::string> tsplit(const std::string& s,const char*const delims);
526 
529 std::vector<std::string> lsplit(const std::string& s,const std::string& delim);
530 
533 std::vector<std::string> ltsplit(const std::string& s,const std::string& delim);
534 
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)
542 {
543  typedef std::string::const_iterator iter_t;
544  typedef std::pair<iter_t,iter_t> range_t;
545  typedef tok_occurrence<iter_t,char> tok_t;
546 
547  tok_t tok(s.begin(),s.end(),delim);
548 
549  const range_t& r=tok.current();
550  destination->assign(r.first,r.second);
551  ++destination;
552 
553  tok.next();
554 
555  while(tok.has_data()&&(tok.index()<limit))
556  {
557  const range_t& r=tok.current();
558 
559  destination->assign(r.first,r.second);
560  ++destination;
561 
562  tok.next();
563  }
564 
565  return tok.index()+1;
566 }
567 
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)
575 {
576  typedef std::string::const_iterator iter_t;
577  typedef std::pair<iter_t,iter_t> range_t;
578  typedef valterm_iterator<const char> delim_iter_t;
580 
581  tok_t tok(s.begin(),s.end(),delim_iter_t(delims),delim_iter_t());
582 
583  const range_t& r=tok.current();
584  destination->assign(r.first,r.second);
585  ++destination;
586 
587  tok.next();
588 
589  while(tok.has_data()&&(tok.index()<limit))
590  {
591  const range_t& r=tok.current();
592 
593  destination->assign(r.first,r.second);
594  ++destination;
595 
596  tok.next();
597  }
598 
599  return tok.index()+1;
600 }
601 
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)
610 {
611  typedef std::string::const_iterator iter_t;
612  typedef std::pair<iter_t,iter_t> range_t;
613  typedef tok_transition<iter_t,char> tok_t;
614 
615  tok_t tok(s.begin(),s.end(),delim);
616 
617  const range_t& r=tok.current();
618  destination->assign(r.first,r.second);
619  ++destination;
620 
621  tok.next();
622 
623  while(tok.has_data()&&(tok.index()<limit))
624  {
625  const range_t& r=tok.current();
626 
627  destination->assign(r.first,r.second);
628  ++destination;
629 
630  tok.next();
631  }
632 
633  return tok.index()+1;
634 }
635 
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)
644 {
645  typedef std::string::const_iterator iter_t;
646  typedef std::pair<iter_t,iter_t> range_t;
647  typedef valterm_iterator<const char> delim_iter_t;
649 
650  tok_t tok(s.begin(),s.end(),delim_iter_t(delims),delim_iter_t());
651 
652  const range_t& r=tok.current();
653  destination->assign(r.first,r.second);
654  ++destination;
655 
656  tok.next();
657 
658  while(tok.has_data()&&(tok.index()<limit))
659  {
660  const range_t& r=tok.current();
661 
662  destination->assign(r.first,r.second);
663  ++destination;
664 
665  tok.next();
666  }
667 
668  return tok.index()+1;
669 }
670 
672 
674 template<typename T>
675 std::string to_string(const T& value,const int prec)
676 {
677  std::ostringstream os;
678  os<<std::setprecision(prec)<<value;
679  return os.str();
680 }
681 
683 template<typename T,int precision>
684 std::string to_string(const T& value)
685 {
686  std::ostringstream os;
687  os<<std::setprecision(precision)<<value;
688  return os.str();
689 }
690 
692 template<typename T>
693 std::string to_string(const T& value)
694 {
695  return to_string<T,14>(value);
696 }
697 
698 template<>
699 inline
700 std::string to_string<bool>(const bool& value)
701 {
702  return value?"yes":"no";
703 }
704 
706 template<>
707 inline
708 std::string to_string<std::ostringstream>(const std::ostringstream& str)
709 {
710  return str.str();
711 }
712 
714 template<>
715 inline
716 std::string to_string<std::string>(const std::string& s)
717 {
718  return s;
719 }
720 
722 
724 template<class Iter>
725 std::string join(Iter begin,Iter end,const std::string& delim)
726 {
727  if(begin==end)
728  return "";
729 
730  --end;
731 
732  std::string ret;
733 
734  while(begin!=end)
735  {
736  ret+=to_string(*begin)+delim;
737  ++begin;
738  }
739  return ret+to_string(*end);
740 }
741 
743 template<class Iter>
744 std::string join(const Iter begin,const Iter end)
745 {
746  return join(begin,end,"\t");
747 }
748 
750 template<typename T>
751 std::string join(const std::vector<T>& sv,const std::string& delim)
752 {
753  return join(sv.begin(),sv.end(),delim);
754 }
755 
757 template<typename T>
758 std::string join(const std::vector<T>& sv)
759 {
760  return join(sv.begin(),sv.end());
761 }
762 
764 template<class Iteriter>
765 std::string ijoin(Iteriter begin,Iteriter end,const std::string& delim)
766 {
767  if(begin==end)
768  return "";
769 
770  --end;
771 
772  std::string ret;
773 
774  while(begin!=end)
775  {
776  ret+=to_string(**begin)+delim;
777  ++begin;
778  }
779  return ret+to_string(**end);
780 }
781 
783 template<typename Iter>
784 std::string ijoin(const std::vector<Iter>& sv,const std::string &delim)
785 {
786  return ijoin(sv.begin(),sv.end(),delim);
787 }
788 
790 inline std::vector<std::string> join2d(
791  std::vector<std::vector<std::string> >& pv,const std::string& delim)
792 {
793  std::vector<std::string> ret;
794  for(size_t i=0;i<pv.size();++i)
795  ret.push_back(join(pv[i],delim));
796  return ret;
797 }
798 
800 
802 template<typename T>
803 std::string to_string(const std::vector<T>& v)
804 {
805  return join(v,",");
806 }
807 
809 template<typename T>
810 std::string to_string(const std::vector<std::vector<T> >& v)
811 {
812  return join(join2d(v,":"),",");
813 }
814 
816 
818 template<typename conv_type,void (*initfunc)(conv_type *const)>
819 const conv_type *chartab();
820 
822 template<typename conv_type,void (*initfunc)(conv_type *const)>
824 {
825  private:
826 
827  friend const conv_type *chartab<conv_type,initfunc>();
828 
829  struct ptrmgr
830  {
831  chartable *ptr;
832 
833  ~ptrmgr()
834  {
835  delete ptr;
836  }
837  };
838 
839  static ptrmgr m_instance;
840 
841  conv_type m_table[256];
842 
843  chartable()
844  {
845  initfunc(m_table);
846  }
847 };
848 
850 template<typename conv_type,void (*initfunc)(conv_type *const)>
851 const conv_type *chartab()
852 {
854  {
856  }
857  return chartable<conv_type,initfunc>::m_instance.ptr->m_table;
858 }
859 
860 template<typename conv_type,void (*initfunc)(conv_type *const)>
861 typename chartable<conv_type,initfunc>::ptrmgr chartable<conv_type,initfunc>::m_instance;
862 
864 void ctabinit_digit(int *const table);
865 
867 template<int exp>
868 void ctabinit_expdigit(int64_t *const table)
869 {
870  uint64_t signif=1;
871  for(int i=0;i<exp;++i)
872  signif*=10;
873  for(unsigned int i=0;i<256;++i)
874  {
875  if(i==uint8_t('0'))
876  {
877  if(exp>=19)
878  table[i]=-8; // leading zero
879  else
880  table[i]=0;
881  }
882  else if((i>=uint8_t('1'))&&(i<=uint8_t('9')))
883  {
884  if(exp<19)
885  table[i]=signif*(i-uint8_t('0'));
886  else
887  table[i]=-7; // out of range
888  }
889  else if(i==uint8_t('-'))
890  table[i]=-2;
891  else if(i==uint8_t('+'))
892  table[i]=-3;
893  else if(i==uint8_t('.'))
894  table[i]=-4;
895  else if(i==uint8_t('e'))
896  table[i]=-5;
897  else if(i==uint8_t('E'))
898  table[i]=-5;
899  else if(i==uint8_t(' '))
900  table[i]=-6;
901  else if(i==uint8_t('\t'))
902  table[i]=-6;
903  else if(i==uint8_t('\n'))
904  table[i]=-6;
905  else
906  table[i]=-1;
907  }
908 }
909 
911 void ctabinit_base32hex(int *const table);
912 
913 extern const int *const ctab_digit;
914 extern const int64_t *const ctab_expdigit[21];
915 
917 template<typename iter_type>
918 uint64_t parse_uint64(iter_type beg,iter_type end)
919 {
920  if(beg==end)
921  throw std::runtime_error("parse_uint64: empty range");
922 
923  uint64_t ret=0;
924  const int64_t *const *digtab=ctab_expdigit;
925 
926  do
927  {
928  --end;
929 
930  const int64_t d=(*digtab)[uint8_t(*end)];
931 
932  if(d<0)
933  {
934  if(end==beg)
935  {
936  // leading '+'
937  if(d==-3)
938  return ret;
939  // out of range
940  if(d==-7)
941  {
942  if((*end)=='1')
943  {
944  const uint64_t d2=
945  uint64_t((*(digtab-1))[uint8_t('1')])*10;
946 
947  if((std::numeric_limits<uint64_t>::max()-d2)>=ret)
948  return ret+d2;
949 
950  throw std::runtime_error("parse_uint64: out of range: "
951  +std::string(beg,++end));
952  }
953  else
954  throw std::runtime_error("parse_uint64: out of range: "
955  +std::string(beg,++end));
956  }
957  if(d==-2)
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));
962  }
963  else
964  throw std::runtime_error("parse_uint64: conversion error: "
965  +std::string(beg,++end));
966  }
967 
968  ret+=d;
969  ++digtab;
970  }
971  while(end!=beg)
972  ;
973 
974  return ret;
975 }
976 
978 template<typename iter_type>
979 int64_t parse_int64(iter_type beg,iter_type end)
980 {
981  if(beg==end)
982  throw std::runtime_error("parse_uint64: empty range");
983 
984  uint64_t ret=0;
985  const int64_t *const *digtab=ctab_expdigit;
986 
987  do
988  {
989  --end;
990 
991  const int64_t d=(*digtab)[uint8_t(*end)];
992 
993  if(d<0)
994  {
995  if(end==beg)
996  {
997  // leading '-'
998  if(d==-2)
999  {
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));
1003 
1004  return -(int64_t(ret));
1005  }
1006  // leading '+'
1007  if(d==-3)
1008  return ret;
1009  // out of range
1010  if(d==-7)
1011  {
1012  if((*end)=='1')
1013  {
1014  const uint64_t d2=uint64_t((*(digtab-1))[uint8_t('1')])*10;
1015 
1016  if((std::numeric_limits<uint64_t>::max()-d2)>=ret)
1017  return ret+d2;
1018 
1019  throw std::runtime_error("parse_int64: out of range: "
1020  +std::string(beg,++end));
1021  }
1022  else
1023  throw std::runtime_error("parse_int64: out of range: "
1024  +std::string(beg,++end));
1025  }
1026  throw std::runtime_error("parse_int64: conversion error 2: "
1027  +std::string(beg,++end));
1028  }
1029  else
1030  throw std::runtime_error("parse_int64: conversion error: "
1031  +std::string(beg,++end));
1032  }
1033 
1034  ret+=d;
1035  ++digtab;
1036  }
1037  while(end!=beg)
1038  ;
1039 
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));
1043 
1044  return ret;
1045 }
1046 
1048 
1052 template<typename T>
1053 void parse_value(T* dest,const std::string& str)
1054 {
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");
1061 }
1062 
1064 template<>
1065 inline void parse_value<std::string>(std::string* dest,const std::string& str)
1066 {
1067  (*dest)=str;
1068 }
1069 
1073 template<>
1074 void parse_value<bool>(bool *dest,const std::string& str);
1075 
1077 template<typename T>
1078 T parse_value(const std::string& str)
1079 {
1080  T value;
1081  parse_value<T>(&value,str);
1082  return value;
1083 }
1084 
1086 template<>
1087 inline double parse_value<double>(const std::string& str)
1088 {
1089  double value=std::atof(str.c_str());
1090  // if unsure if conversion was successful
1091  if(value==0.0)
1092  {
1093  parse_value<double>(&value,str);
1094  }
1095  return value;
1096 }
1097 
1099 
1101 template<typename iter_type>
1102 void parse_value(std::string *const dest,iter_type beg,iter_type end)
1103 {
1104  dest->assign(beg,end);
1105 }
1106 
1108 template<typename iter_type>
1109 void parse_value(uint64_t *const dest,iter_type beg,iter_type end)
1110 {
1111  (*dest)=parse_uint64(beg,end);
1112 }
1113 
1115 template<typename iter_type>
1116 void parse_value(int64_t *const dest,iter_type beg,iter_type end)
1117 {
1118  (*dest)=parse_int64(beg,end);
1119 }
1120 
1122 template<typename T,typename iter_type>
1123 void parse_value(T *const dest,iter_type beg,iter_type end,
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)
1126 {
1127  const int64_t v=parse_int64(beg,end);
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");
1131  (*dest)=v;
1132 }
1133 
1135 template<typename T,typename iter_type>
1136 void parse_value(T *const dest,iter_type beg,iter_type end,
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)
1139 {
1140  const uint64_t v=parse_uint64(beg,end);
1141  if(v>uint64_t(std::numeric_limits<T>::max()))
1142  throw std::runtime_error("parse_value: out of range");
1143  (*dest)=v;
1144 }
1145 
1148 template<typename Dest,typename Default>
1149 void parse_envvar(Dest *const dest,const std::string &envvar,const Default &def)
1150 {
1151  const char *const env=std::getenv(envvar.c_str());
1152  if(env!=0)
1153  parse_value(dest,env);
1154  else
1155  (*dest)=def;
1156 }
1157 
1160 template<typename Dest,typename Default>
1161 Dest parse_envvar(const std::string &envvar,const Default &def)
1162 {
1163  Dest ret;
1164  parse_envvar(&ret,envvar,def);
1165  return ret;
1166 }
1167 
1169 
1171 bool charcmp_ci(const char a,const char b);
1173 bool charcmp_equal_ci(const char a,const char b);
1174 
1176 template<typename Iterator>
1177 bool equal_ci(const std::string &s,Iterator b,Iterator e)
1178 {
1179  return (s.size()==size_t(e-b))&&std::equal(b,e,s.begin(),charcmp_equal_ci);
1180 }
1181 
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);
1198 
1200 
1202 template<class T>
1203 std::string lprefix(const T& what,const std::string& prefix)
1204 {
1205  const std::string whatstr=to_string<T>(what);
1206  if(whatstr.empty())
1207  return whatstr;
1208 
1209  return prefix+join(split(whatstr,'\n'),"\n"+prefix);
1210 }
1211 
1213 std::vector<std::string> wrap_line(const std::string& line,const size_t maxlw);
1214 
1216 void expand_tabs(std::istream& in,std::ostream& out,
1217  const int colsep=4,
1218  const std::vector<size_t>& maxwidths=std::vector<size_t>(),
1219  const bool headings=true);
1220 
1222 std::string expand_tabs(const std::string& str,
1223  const int colsep=4,
1224  const std::vector<size_t>& maxwidths=std::vector<size_t>(),
1225  const bool headings=true);
1226 
1228 template<class Iter>
1229 std::string expand_tabs(const std::string& str,
1230  const int colsep,
1231  Iter b_maxwidths,Iter e_maxwidths,
1232  const bool headings=true)
1233 {
1234  const std::vector<size_t> maxwidths(b_maxwidths,e_maxwidths);
1235  return expand_tabs(str,colsep,maxwidths,headings);
1236 }
1237 
1240 template<typename Iter>
1241 std::pair<Iter,Iter> trim(Iter beg,Iter end)
1242 {
1243  while((beg!=end)&&std::isspace(*beg)) ++beg;
1244  while((beg!=end)&&std::isspace(*(end-1))) --end;
1245  return std::make_pair(beg,end);
1246 }
1247 
1249 
1251 template<class T>
1252 struct manipd
1253 {
1254  typedef std::ios_base& (*manip_type)(std::ios_base&);
1255  T value;
1256  const manip_type manip;
1257  char fill;
1258  int width;
1259  int precision;
1260 
1261  manipd(manip_type m=0,int f=0,int w=0,int p=0):
1262  manip(m),fill(f),width(w),precision(p)
1263  {}
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)
1266  {}
1267 };
1268 
1269 template<class T>
1270 std::ostream& operator<<(std::ostream& os,const manipd<T>& mp)
1271 {
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();
1276 
1277  if(mp.manip!=0)
1278  mp.manip(os);
1279 
1280  if(mp.fill>0)
1281  os.fill(mp.fill);
1282  if(mp.width>0)
1283  os.width(mp.width);
1284  if(mp.precision>0)
1285  os.precision(mp.precision);
1286 
1287  os<<mp.value;
1288 
1289  if(mp.precision>0)
1290  os.precision(pr);
1291  if(mp.width>0)
1292  os.width(fw);
1293  if(mp.fill>0)
1294  os.fill(fc);
1295  if(mp.manip!=0)
1296  os.flags(fl);
1297  return os;
1298 }
1299 
1300 template<class T>
1301 std::istream& operator>>(std::istream& is,manipd<T>& mp)
1302 {
1303  const std::ios_base::fmtflags fl=is.flags();
1304  if(mp.manip!=0)
1305  mp.manip(is);
1306  is>>mp.value;
1307  if(mp.manip!=0)
1308  is.flags(fl);
1309  return is;
1310 }
1311 
1313 
1314 // Helper for match_arg().
1315 template<typename exception_type>
1316 void throw_exception(const std::string &msg)
1317 {
1318  throw exception_type(msg);
1319 }
1320 
1321 // Helper for match_arg().
1322 template<>
1323 inline void throw_exception<void>(const std::string &msg)
1324 {}
1325 
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"))
1338 {
1339  std::string arg_lc=arg;
1340  tolower(arg_lc);
1341  std::vector<std::string> matches;
1342  std::vector<Iter> positions;
1343 
1344  // perfect match, case sensitive
1345  for(Iter i=beg;i!=end;++i)
1346  {
1347  if((*i)==arg)
1348  return i;
1349  }
1350 
1351  if(arg.empty())
1352  throw_exception<exception_type>(exlabel
1353  +" - tried to match an empty string");
1354 
1355  // perfect match, case insensitive
1356  for(Iter i=beg;i!=end;++i)
1357  {
1358  std::string match_lc=*i;
1359  tolower(match_lc);
1360  if(match_lc==arg_lc)
1361  {
1362  matches.push_back(*i);
1363  positions.push_back(i);
1364  }
1365  }
1366 
1367  if(!positions.empty())
1368  {
1369  if(positions.size()==1)
1370  return positions.front();
1371  throw_exception<exception_type>(exlabel+" - ambiguous match for \""
1372  +arg+"\": "+join(matches,", "));
1373  return end;
1374  }
1375 
1376  // prefix match, case sensitive
1377  for(Iter i=beg;i!=end;++i)
1378  {
1379  if(i->substr(0,arg.size())==arg)
1380  {
1381  matches.push_back(*i);
1382  positions.push_back(i);
1383  }
1384  }
1385 
1386  if(!positions.empty())
1387  {
1388  if(positions.size()==1)
1389  return positions.front();
1390  throw_exception<exception_type>(
1391  exlabel+" - ambiguous match for \""+arg+"\": "+join(matches,", "));
1392  return end;
1393  }
1394 
1395  // prefix match, case insensitive
1396  for(Iter i=beg;i!=end;++i)
1397  {
1398  std::string match_lc=*i;
1399  tolower(match_lc);
1400  if(match_lc.substr(0,arg_lc.size())==arg_lc)
1401  {
1402  matches.push_back(*i);
1403  positions.push_back(i);
1404  }
1405  }
1406 
1407  if(positions.size()==1)
1408  return positions.front();
1409 
1410  if(positions.empty())
1411  throw_exception<exception_type>(exlabel+" - no match for \""+arg+"\"");
1412 
1413  if(positions.size()>1)
1414  throw_exception<exception_type>(exlabel+" - ambiguous match for \""
1415  +arg+"\": "+join(matches,", "));
1416 
1417  return end;
1418 }
1419 
1421 template<class Ex,class Iter>
1423  const std::string& arg,Iter beg,Iter end,
1424  const std::string& exlabel=std::string("match_arg"))
1425 {
1426  return match_arg<Ex,Iter>(arg,beg,end,exlabel)-beg;
1427 }
1428 
1430 template<typename Enum,typename Iter>
1431 std::istream &parse_enum(std::istream &in,Enum &dest,Iter beg,Iter end)
1432 {
1433  std::string buf;
1434  in>>buf;
1435 
1436  try
1437  {
1438  dest=static_cast<Enum>(
1439  match_arg_idx<std::runtime_error>(buf,beg,end));
1440  }
1441  catch(const std::runtime_error &)
1442  {
1443  in.setstate(std::ios_base::failbit);
1444  }
1445  return in;
1446 }
1447 
1449 template<typename Enum,int SZ>
1450 std::istream &parse_enum(std::istream &in,Enum &dest,const std::string (&templ)[SZ])
1451 {
1452  return parse_enum(in,dest,templ,end(templ));
1453 }
1454 
1455 template<typename Enum>
1456 struct enum_traits;
1457 
1459 #define MAKE_ENUM_TRAITS(T)\
1460  namespace shore {\
1461  template<>\
1462  struct enum_traits<T>\
1463  {\
1464  typedef std::istream istream_type;\
1465  typedef std::ostream ostream_type;\
1466  static const std::string values;\
1467  static const std::string description;\
1468  };\
1469  }
1470 
1471 // Version of the MAKE_ENUM_TRAITS macro for use inside the shore namespace.
1472 #define S_MAKE_ENUM_TRAITS(T)\
1473  template<>\
1474  struct enum_traits<T>\
1475  {\
1476  typedef std::istream istream_type;\
1477  typedef std::ostream ostream_type;\
1478  static const std::string values;\
1479  static const std::string description;\
1480  };
1481 
1483 template<typename Enum>
1484 typename enum_traits<Enum>::istream_type &operator>>(std::istream &in,Enum &en)
1485 {
1486  const std::vector<std::string> values=
1487  shore::split(enum_traits<Enum>::values,'|');
1488  return shore::parse_enum(in,en,values.begin(),values.end());
1489 }
1490 
1492 template<typename Enum>
1493 typename enum_traits<Enum>::ostream_type &operator<<(std::ostream &out,const Enum &en)
1494 {
1495  const std::vector<std::string> labels=
1496  shore::split(enum_traits<Enum>::values,'|');
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];
1502 }
1503 
1504 } // namespace shore
1505 
1506 #endif // SHORE_MISC_STRINGOPS_HPP__
1507