Proton  1.1.1
Make porting easy from Python to C++11
string.hpp
1 #ifndef PROTON_STRING_HEADER
2 #define PROTON_STRING_HEADER
3 
4 #include <iostream>
5 #include <fstream>
6 #include <sstream>
7 #include <string>
8 #include <boost/algorithm/string/predicate.hpp>
9 #include <boost/algorithm/string/case_conv.hpp>
10 #include <stdexcept>
11 #include <cstring>
12 #include <cwchar>
13 #include <type_traits>
14 #include <proton/base.hpp>
15 #include <proton/pool.hpp>
16 #include <proton/deque.hpp>
17 #include <proton/tuple.hpp>
18 
19 namespace proton{
20 
21 /** @addtogroup str
22  * @{
23  */
24 
25 template<typename string>string strip(const string& x)
26 {
27  string spc = " \t\n\r";
28 
29  long i=x.find_first_not_of(spc);
30  long j=x.find_last_not_of(spc);
31 
32  if(i<0 || j<0 || j < i )
33  return "";
34 
35  return x.substr(i,j-i+1);
36 }
37 
38 /** split a string.
39  * @param r the output string list, supporting clear() and push_back()
40  * @param s the input string
41  * @param spc the delimiters
42  * @param null_unite -1: a.c.t. python depent on token, 0: false, 1: true
43  */
44 template<typename string_list, typename string> void split(string_list& r, const string& s, string spc="", int null_unite=-1)
45 {
46  long pos = 0, begin, end;
47 
48  r.clear();
49 
50  if(spc.size()==0){
51  if(null_unite<0)
52  null_unite=1;
53  spc=" \t\n\r";
54  }
55  else{
56  if(null_unite<0)
57  null_unite=0;
58  }
59 
60  if(null_unite){
61  do{
62  begin = s.find_first_not_of(spc,pos);
63  if(begin<0)
64  break;
65  end = s.find_first_of(spc,begin);
66  if(end<0)
67  end=s.length();
68  r.push_back(s.substr(begin, end-begin).c_str());
69  pos = end;
70  }
71  while(pos < (long)s.length());
72  }
73  else{
74  while(1){
75  begin = s.find_first_of(spc,pos);
76  if(begin<0){
77  r.push_back(s.substr(pos).c_str());
78  break;
79  }
80  r.push_back(s.substr(pos, begin-pos).c_str());
81  pos = begin + 1;
82  if(pos>=(long)s.length()){
83  r.push_back("");
84  break;
85  }
86  }//while
87  }//else
88 }
89 
90 template<typename string_list, typename string>
91  void split(string_list& r, const string& s, const char* spc, int null_unite=-1)
92 {
93  return split(r, s, string(spc), null_unite);
94 }
95 
96 /** join a list of strings to one string.
97  * @param token the delimiter
98  * @param r the input string list
99  * @return the output string
100  */
101 template<typename string_list>
102  typename string_list::value_type join(const char* token, const string_list& r)
103 {
104  if(r.empty()){
105  return "";
106  }
107  else{
108  typename string_list::const_iterator it=r.begin();
109  typename string_list::value_type res=*it;
110  ++it;
111  for(;it!=r.end();++it){
112  res+=token+*it;
113  }
114  return res;
115  }
116 }
117 
118 template<typename str1, typename str2> bool startswith(const str1& s,const str2& sub)
119 {
120  return boost::algorithm::starts_with(s, sub);
121 }
122 
123 template<typename str1, typename str2> bool istartswith(const str1& s,const str2& sub)
124 {
125  return boost::algorithm::istarts_with(s, sub);
126 }
127 
128 template<typename str1, typename str2> bool endswith(const str1& s,const str2& sub)
129 {
130  return boost::algorithm::ends_with(s, sub);
131 }
132 
133 template<typename str1, typename str2> bool iendswith(const str1& s,const str2& sub)
134 {
135  return boost::algorithm::iends_with(s, sub);
136 }
137 
138 template<typename ostream> void set_base(ostream& s, int base, bool is_num=false)
139 {
140  switch(base){
141  case 8:
142  s << std::oct;
143  if(is_num)
144  s<< "0";
145  break;
146  case 10:
147  s << std::dec;
148  break;
149  case 16:
150  s << std::hex;
151  if(is_num)
152  s<< "0x";
153  break;
154  default:
155  PROTON_LOG(0, "unsupported base : " << base );
156  }
157 }
158 
159 /** convert a number/object to a string.
160  * @param n the input value
161  * @param base 10:dec, 16:hex
162  * @return the output string
163  */
164 template<typename string, typename T> string to_(T&& n, int base=10)
165 {
166  std::basic_ostringstream<char, std::char_traits<char>, typename string::allocator_type > s;
167  set_base(s, base, true);
168  s << n;
169  return s.str();
170 }
171 
172 /** get integer (including int/long/unsigned and so on) from string.
173  * @param r the output value
174  * @param s the input string
175  * @param base 10:dec, 16:hex
176  * @return true: success, false: failure
177  */
178 template<typename int_t, typename string> bool get_int(int_t& r, const string& s, int base=10)
179 {
180  bool is_hex= (base==16);
181  string v1;
182  if( iendswith(s,"h") ){
183  v1=s.substr(0,s.length()-1);
184  is_hex=true;
185  }
186  else if( istartswith(s,"0x") ){
187  v1=s;
188  is_hex=true;
189  }
190  else{
191  v1=s;
192  }
193  std::basic_istringstream<char, std::char_traits<char>, typename string::allocator_type >
194  i(v1);
195  int_t x;
196  if(is_hex)
197  i >> std::hex;
198  if ( (!(i >> x)) || (i.get()>0) ){
199  return false;
200  }
201  r=x;
202  return true;
203 }
204 
205 template<typename string> string to_lower(const string& s)
206 {
207  long length = s.size();
208  static typename string::allocator_type alloc;
209  char* p = alloc.allocate(length);
210  if(p){
211  char* q = p;
212  const char* p0 = s.c_str();
213  string r;
214 
215  for(long i=0;i<length;++i){
216  *p=tolower(*p0);
217  p++;
218  p0++;
219  }
220  r = string(q,length);
221  alloc.deallocate(q,length) ;
222  return r;
223  }
224  else{
225  PROTON_ERR("bad alloc:" << length);
226  }
227 }
228 
229 template<typename string>string to_upper(const string& s)
230 {
231  long length = s.size();
232  static typename string::allocator_type alloc;
233  char* p = alloc.allocate(length);
234  if(p){
235  char* q = p;
236  const char* p0 = s.c_str();
237  string r;
238 
239  for(long i=0;i<length;++i){
240  *p=toupper(*p0);
241  p++;
242  p0++;
243  }
244  r = string(q,length);
245  alloc.deallocate(q,length) ;
246 
247  return r;
248  }
249  else{
250  PROTON_ERR("bad alloc:" << length);
251  }
252 }
253 
254 template<typename string>string readline(std::istream& f, char delim='\n')
255 {
256  string r;
257  std::ios::pos_type start=f.tellg(), end;
258  std::getline(f, r, delim);
259  end=f.tellg();
260  if(end-start>(long)r.length()){
261  char a[2]={delim,0};
262  r.append(a);
263  return r;
264  }
265  else
266  return r;
267 }
268 
269 template <typename C, typename T, typename A>
270 C get(const std::basic_string<C,T,A>& x, long i)
271 {
272  unsigned long s=x.size();
273  if(i<0)
274  i=s+i;
275  if(i<0 || (unsigned long)i >= s )
276  PROTON_ERR("out of range: look up "<<i<<" in vector whose size is " << s);
277  return x[i];
278 }
279 
280 template <typename C, typename T, typename A>
281 std::basic_string<C,T,A> sub(const std::basic_string<C,T,A>& x, long first)
282 {
283  unsigned long s=x.size();
284  if(first<0)
285  first=first+s;
286  if(first<0)
287  first=0;
288  if((unsigned long)first >= s )
289  return "";
290 
291  return x.substr(first);
292 }
293 
294 template <typename C, typename T, typename A>
295 std::basic_string<C,T,A> sub(const std::basic_string<C,T,A>& x, long first, long last)
296 {
297  unsigned long s=x.size();
298  if(first<0)
299  first=first+s;
300  if(first<0)
301  first=0;
302  if((unsigned long)first >= s )
303  return "";
304 
305  if(last<0)
306  last=last+s;
307  if(last<=0)
308  return "";
309 
310  if((unsigned long)last>s)
311  last=s;
312  return x.substr(first,last-first);
313 }
314 
315 namespace detail{
316  template<typename cT> struct vals;
317 
318  template<> struct vals<char>{
319  static constexpr const char* nil="";
320  static constexpr const char* spc=" ";
321  static constexpr const char* ws=" \t\r\n";
322  static constexpr const char* per="%";
323  static constexpr const char* d="d";
324  static constexpr const char* f="f";
325  static constexpr const char* u="u";
326  static constexpr const char* o="o";
327  static constexpr const char* x="x";
328  static constexpr const char* X="X";
329  static constexpr const char* s="s";
330 
331  static const char* find(const char* s, char x)
332  {
333  return std::strchr(s, x);
334  }
335  };
336 
337  template<> struct vals<wchar_t>{
338  static constexpr const wchar_t* nil=L"";
339  static constexpr const wchar_t* spc=L" ";
340  static constexpr const wchar_t* ws=L" \t\r\n";
341  static constexpr const wchar_t* per=L"%";
342  static constexpr const wchar_t* d=L"d";
343  static constexpr const wchar_t* f=L"f";
344  static constexpr const wchar_t* u=L"u";
345  static constexpr const wchar_t* o=L"o";
346  static constexpr const wchar_t* x=L"x";
347  static constexpr const wchar_t* X=L"X";
348  static constexpr const wchar_t* s=L"s";
349 
350  static const wchar_t* find(const wchar_t* s, wchar_t x)
351  {
352  return std::wcschr(s,x);
353  }
354  };
355 }
356 
357 template<
358  class CharT,
359  class Traits = std::char_traits<CharT>,
360  class Allocator = smart_allocator<CharT>
361 > class basic_string_;
362 
363 namespace detail{
364 
365 template<typename C, typename T>
366 void output_prefix(std::basic_ostream<C,T>& o, const C*& f)
367 {
368  if(f==NULL)
369  return;
370  while(1){
371  const C* p=vals<C>::find(f, *vals<C>::per);
372  if(p){
373  switch(*(p+1)){
374  case 0:
375  throw std::invalid_argument("incomplete format");
376  case *vals<C>::per:
377  o.write(f, p-f+1);
378  f=p+2;
379  continue;
380  default:
381  o.write(f,p-f);
382  f=p+1;
383  return;
384  }//switch
385  }
386  else{
387  o << f;
388  f=NULL;
389  return;
390  }
391  }
392 }
393 
394 template<typename C, typename T, typename V, typename X>
395 struct format_t;
396 
397 template<typename C, typename T, typename V>
398 struct format_t<C,T,V,typename std::enable_if<std::is_integral<V>::value, void>::type>
399 {
400  static void output(std::basic_ostream<C,T>& o, const C* & f, V a)
401  {
402  bool printed=false;
403  output_prefix(o,f);
404  if(f==NULL)
405  throw std::invalid_argument("not all arguments converted during formatting");
406  switch(*(f)){
407  case *vals<C>::s:
408  case *vals<C>::f:
409  case *vals<C>::d:
410  case *vals<C>::u:
411  o << std::dec << a;
412  break;
413  case *vals<C>::o:
414  o << std::oct << a;
415  break;
416  case *vals<C>::x:
417  o << std::hex << std::nouppercase << a;
418  break;
419  case *vals<C>::X:
420  o << std::hex << std::uppercase << a;
421  break;
422  default:
423  throw std::invalid_argument("unsupported format character");
424  }//inner switch
425  f++;
426  }
427 };
428 
429 template<typename C, typename T, typename V>
430 struct format_t<C,T,V,typename std::enable_if<std::is_floating_point<V>::value, void>::type>
431 {
432  static void output(std::basic_ostream<C,T>& o, const C* & f, V a)
433  {
434  bool printed=false;
435  output_prefix(o,f);
436  if(f==NULL)
437  throw std::invalid_argument("not all arguments converted during formatting");
438  switch(*(f)){
439  case *vals<C>::s:
440  case *vals<C>::f:
441  o << std::dec << a;
442  break;
443  case *vals<C>::d:
444  case *vals<C>::u:
445  o << std::dec << (long long)(a);
446  break;
447  case *vals<C>::o:
448  o << std::oct << (long long)(a);
449  break;
450  case *vals<C>::x:
451  o << std::hex << std::nouppercase << (long long)(a);
452  break;
453  case *vals<C>::X:
454  o << std::hex << std::uppercase << (long long)(a);
455  break;
456  default:
457  throw std::invalid_argument("unsupported format character");
458  }//inner switch
459  f++;
460  }
461 };
462 
463 
464 template<typename C, typename T, typename V>
465 struct format_t<C,T,V,typename std::enable_if<!(std::is_floating_point<V>::value ||
466  std::is_integral<V>::value), void>::type>{
467  static void output(std::basic_ostream<C,T>& o, const C* & f, const V& a)
468  {
469  bool printed=false;
470  output_prefix(o,f);
471  if(f==NULL)
472  throw std::invalid_argument("not all arguments converted during formatting");
473  switch(*(f)){
474  case *vals<C>::s:
475  o << a;
476  break;
477  case *vals<C>::d:
478  case *vals<C>::u:
479  case *vals<C>::o:
480  case *vals<C>::x:
481  case *vals<C>::X:
482  throw std::invalid_argument("a number is required");
483  default:
484  throw std::invalid_argument("unsupported format character");
485  }//inner switch
486  f++;
487  }
488 };
489 
490 template<typename C, typename T, typename V>
491 struct format_output_t{
492  static void output(std::basic_ostream<C,T>& s, const C* f, const V& v)
493  {
494  format_t<C,T,V,void>::output(s, f, v);
495  output_prefix(s, f);
496  if(f)
497  throw std::invalid_argument("not enough arguments for format");
498  }
499 };
500 
501 template<typename C, typename T, typename A, typename V>
502  basic_string_<C,T,A> str_format(const C* f, const V& v)
503 {
504  std::basic_ostringstream<C,T,A> o;
505  format_output_t<C,T,V>::output(o, f, v);
506  return o.str();
507 }
508 
509 // helper function to format a tuple of any size
510 template<typename C, typename T, typename V, std::size_t I>
511 struct format_tuple {
512  static void output(std::basic_ostream<C,T>& s, const C* & f, const V& t)
513  {
514  format_tuple<C, T, V, I-1>::output(s, f, t);
515  typedef decltype(std::get<I-1>(t)) N;
516  typedef typename std::remove_reference<N>::type N1;
517  format_t<C,T,N1,void>::output(s, f, std::get<I-1>(t));
518  }
519 };
520 
521 template<typename C, typename T, typename V>
522 struct format_tuple<C, T, V, 1> {
523  static void output(std::basic_ostream<C,T>& s, const C* & f, const V& t)
524  {
525  typedef decltype(std::get<0>(t)) N;
526  typedef typename std::remove_reference<N>::type N1;
527  format_t<C,T,N1,void>::output(s, f, std::get<0>(t));
528  }
529 };
530 
531 template<typename C, typename T, typename V>
532 struct format_tuple<C, T, V, 0> {
533  static void output(std::basic_ostream<C,T>& s, const C* & f, const V& t)
534  {
535  }
536 };
537 
538 template<typename C, typename T, typename ...V>
539 struct format_output_t<C,T,std::tuple<V...> >{
540  static void output(std::basic_ostream<C,T>& s, const C* f, const std::tuple<V...> & t)
541  {
542  format_tuple<C, T, const std::tuple<V...> &, sizeof...(V) >::output(s,f,t);
543  detail::output_prefix(s, f);
544  if(f)
545  throw std::invalid_argument("not enough arguments for format");
546  }
547 };
548 
549 } //ns detail
550 
551 /** main string template
552  */
553 template<
554  class CharT,
555  class Traits,
556  class Allocator
557 >
558 class basic_string_ : public std::basic_string<CharT,Traits,Allocator> {
559 public:
560  typedef std::basic_string<CharT,Traits,Allocator> baseT;
561  typedef typename baseT::difference_type offset_t;
562 protected:
563  offset_t __offset(offset_t i)const
564  {
565  if(i<0)
566  i+=this->size();
567  return i;
568  }
569 
570  offset_t offset(offset_t i)const
571  {
572  i=__offset(i);
573  PROTON_THROW_IF(i<0 || (size_t)i>=this->size(), "out of range, offset is " << i
574  << " while size is " << this->size() );
575  return i;
576  }
577 
578  int fix_offset(offset_t begin)const
579  {
580  offset_t size=(offset_t)this->size();
581  begin=__offset(begin);
582  if(begin>=size){
583  return size;
584  }
585  if(begin<0)
586  return 0;
587  return begin;
588  }
589 
590  void fix_range(offset_t& begin, offset_t& end)const
591  {
592  offset_t size=(offset_t)this->size(); //[FIXME] size>2G in 32bit?
593  begin=__offset(begin);
594  end=__offset(end);
595  if(begin>=size || end<=0 || end<=begin){
596  begin=0;
597  end=0;
598  return;
599  }
600  if(begin<0)
601  begin=0;
602  if(end>=size)
603  end=size;
604  }
605 
606 public:
607  /** forwarding ctor.
608  */
609  template<typename ...argT> basic_string_(argT&& ...a):baseT(a...)
610  {}
611 
612  /** initializer_list forwarding ctor.
613  */
614  basic_string_(std::initializer_list<CharT> a):baseT(a)
615  {}
616 
617  /** copy ctor.
618  */
619  basic_string_(const basic_string_& x):baseT(x)
620  {}
621 
622  /** move ctor.
623  */
624  basic_string_(basic_string_&& x)noexcept:baseT(x)
625  {}
626 
627  explicit basic_string_(const baseT& x):baseT(x)
628  {}
629 
630  basic_string_(baseT&& x)noexcept:baseT(x)
631  {}
632 
633  /** assign.
634  */
635  basic_string_& operator=(const basic_string_& x)
636  {
637  baseT::operator=(x);
638  return *this;
639  }
640 
641  basic_string_& operator=(basic_string_&& x)noexcept
642  {
643  baseT::operator=(x);
644  return *this;
645  }
646 
647  basic_string_& operator=(const baseT& x)
648  {
649  baseT::operator=(x);
650  return *this;
651  }
652 
653  basic_string_& operator=(baseT&& x)noexcept
654  {
655  baseT::operator=(x);
656  return *this;
657  }
658 
659  template<typename argT> basic_string_& operator=(argT&& a)
660  {
661  baseT::operator=(a);
662  return *this;
663  }
664 
665  basic_string_& operator=(std::initializer_list<CharT> a)
666  {
667  baseT::operator=(a);
668  return *this;
669  }
670 
671  /** +=
672  */
673  template<typename argT>
674  basic_string_& operator+=(argT&& a)
675  {
676  this->append(a);
677  return *this;
678  }
679 
680  /** string + string
681  */
682  template<typename argT>
684  {
685  basic_string_ r(*this);
686  r.append(a);
687  return r;
688  }
689 
690  /** string % V
691  */
692  template<typename V>
694  {
695  return detail::str_format<CharT, Traits, Allocator>(this->c_str(), a);
696  }
697 
698  /** cast to std::basic_string<>&.
699  */
700  operator baseT&()
701  {
702  return reinterpret_cast<baseT&>(*this);
703  }
704 
705  /** cast to std::basic_string<>&.
706  */
707  template<typename A1>
708  operator std::basic_string<CharT,Traits,A1> ()const
709  {
710  return this->c_str();
711  }
712 
713  /** [i] in python
714  */
715  CharT& operator[](offset_t i)
716  {
717  return *(this->begin()+offset(i));
718  }
719 
720  /** [i] in python
721  */
722  const CharT& operator[](offset_t i)const
723  {
724  return *(this->begin()+offset(i));
725  }
726 
727  /** slice of [i:]
728  */
729  basic_string_ operator()(offset_t i)const
730  {
731  auto begin=this->begin();
732  return basic_string_(begin+fix_offset(i),this->end());
733  }
734 
735  /** slice of [i:j]
736  */
737  basic_string_ operator()(offset_t i, offset_t j)const
738  {
739  auto begin=this->begin();
740  fix_range(i,j);
741  return basic_string_(begin+i,begin+j);
742  }
743 
744  /** slice of [i:j:k]
745  */
746  basic_string_ operator()(offset_t i, offset_t j, size_t k)const
747  {
748  fix_range(i,j);
749  basic_string_ r;
750  r.reserve((j-i)/k+2);
751  auto it=this->begin()+i;
752  for(offset_t n=i; n<j; n+=k,it+=k)
753  r.push_back(*it);
754  return r;
755  }
756 
757  /** total number of occurences of a char.
758  */
759  size_t count(const CharT& x)const
760  {
761  return std::count(this->begin(), this->end(), x);
762  }
763 
764  /** index of the first occurence of a char.
765  * @param val the char.
766  * @throw std::invalid_argument if there is no such a char.
767  */
768  offset_t index(const CharT& val)const
769  {
770  auto begin=this->begin(), end=this->end();
771  auto it=std::find(begin, end, val);
772  if(it==end)
773  throw std::invalid_argument("The given char doesn't exist in this sequence.");
774  return it-begin;
775  }
776 
777  /** Return a copy of the string with leading and trailing characters removed.
778  * @param spc white space chars
779  * @return the stripped string
780  */
781  basic_string_ strip(const baseT& spc=detail::vals<CharT>::ws)const
782  {
783  offset_t i=this->find_first_not_of(spc);
784  offset_t j=this->find_last_not_of(spc);
785 
786  if(i<0 || j<0 || j < i )
787  return detail::vals<CharT>::nil;
788 
789  return basic_string_(this->begin()+i,this->begin()+j+1);
790  }
791 
792  /** split a string.
793  * @param delim the delimiters
794  * @param null_unite -1: a.c.t. python depent on token, 0: false, 1: true
795  * @return the output string list, in deque_<basic_string_>
796  */
798  split(const baseT& delim=baseT(), int null_unite=-1)const
799  {
800  long pos = 0, begin, end;
801 
803 
804  basic_string_ spc(delim);
805  if(spc.size()==0){
806  if(null_unite<0)
807  null_unite=1;
808  spc=detail::vals<CharT>::ws;
809  }
810  else{
811  if(null_unite<0)
812  null_unite=0;
813  }
814 
815  if(null_unite){
816  do{
817  begin = this->find_first_not_of(spc,pos);
818  if(begin<0)
819  break;
820  end = this->find_first_of(spc,begin);
821  if(end<0)
822  end=this->length();
823  r.push_back(this->substr(begin, end-begin));
824  pos = end;
825  }
826  while(pos < (long)this->length());
827  }
828  else{
829  while(1){
830  begin = this->find_first_of(spc,pos);
831  if(begin<0){
832  r.push_back(this->substr(pos));
833  break;
834  }
835  r.push_back(this->substr(pos, begin-pos));
836  pos = begin + 1;
837  if(pos>=(long)this->length()){
838  r.push_back(detail::vals<CharT>::nil);
839  break;
840  }
841  }//while
842  }//else
843  return r;
844  }
845 
846  /** join a list of strings to one string.
847  * @param r the input string list
848  * @return the output string
849  */
850  template<typename string_list>
851  basic_string_ join(const string_list& r)const
852  {
853  if(r.empty()){
854  return basic_string_();
855  }
856  else{
857  typename string_list::const_iterator it=r.begin();
858  basic_string_ res=*it;
859  ++it;
860  for(;it!=r.end();++it){
861  res+=*this;
862  res+=*it;
863  }
864  return res;
865  }
866  }
867 
868  /** startswith.
869  */
870  template<typename str2> bool startswith(str2&& sub)const
871  {
872  return boost::algorithm::starts_with(*this, sub);
873  }
874 
875  /** case-insensitive startswith.
876  */
877  template<typename str2> bool istartswith(str2&& sub)const
878  {
879  return boost::algorithm::istarts_with(*this, sub);
880  }
881 
882  /** endswith.
883  */
884  template<typename str2> bool endswith(str2&& sub)const
885  {
886  return boost::algorithm::ends_with(*this, sub);
887  }
888 
889  /** case-insensitive endswith.
890  */
891  template<typename str2> bool iendswith(str2&& sub)const
892  {
893  return boost::algorithm::iends_with(*this, sub);
894  }
895 
896  /** return a copy with upper case letters converted to lower case.
897  */
898  basic_string_ lower()const
899  {
900  return boost::algorithm::to_lower_copy(*this);
901  }
902 
903  /** return a copy with lower case letters converted to upper case.
904  */
905  basic_string_ upper()const
906  {
907  return boost::algorithm::to_upper_copy(*this);
908  }
909 
910 };
911 
912 /**
913  * @example string.cpp
914  */
915 
916 /** the main string type in proton.
917  */
919 
920 /** the main wstring type in proton.
921  */
923 
924 
925 /** const CharT* + str
926  */
927 template<typename T, typename C, typename A>
929 {
931  r.append(t);
932  return r;
933 }
934 
935 /** const CharT* % V
936  */
937 template<typename C, typename V>
939 {
940  return detail::str_format<C, std::char_traits<C>, smart_allocator<C> >(f, a);
941 }
942 
943 /** string * n
944  */
945 template<typename T, typename C, typename A>
947 {
949  r.reserve(s.size()*n+1);
950  for(size_t i=0; i<n; i++)
951  r.append(s);
952  return r;
953 }
954 
955 /** n * string
956  */
957 template<typename T, typename C, typename A>
959 {
960  return s*n;
961 }
962 
963 /** cast to proton::basic_string_<>& from std::basic_string<>&.
964  */
965 template<typename T, typename C, typename A>
966 basic_string_<T,C,A>& cast_(std::basic_string<T,C,A>& x)
967 {
968  return reinterpret_cast<basic_string_<T,C,A>&>(x);
969 }
970 
971 template<typename T, typename C, typename A>
972 const basic_string_<T,C,A>& cast_(const std::basic_string<T,C,A>& x)
973 {
974  return reinterpret_cast<const basic_string_<T,C,A>&>(x);
975 }
976 
977 template<typename T, typename C, typename A>
978 basic_string_<T,C,A>&& cast_(std::basic_string<T,C,A>&& x)
979 {
980  return reinterpret_cast<basic_string_<T,C,A>&&>(x);
981 }
982 
983 template<typename T, typename C, typename A>
984 const basic_string_<T,C,A>&& cast_(const std::basic_string<T,C,A>&& x)
985 {
986  return reinterpret_cast<const basic_string_<T,C,A>&&>(x);
987 }
988 
989 /**
990  * @}
991  */
992 
993 }
994 
995 namespace std{
996 
997 template<typename T, typename C, typename A>
998 struct hash<proton::basic_string_<T,C,A> >{
999 public:
1000  typedef size_t result_type;
1001  typedef proton::basic_string_<T,C,A> argument_type;
1002  size_t operator()(const proton::basic_string_<T,C,A> &s) const noexcept
1003  {
1004  return std::hash<std::basic_string<T> >()(reinterpret_cast<const std::basic_string<T>&>(s));
1005  }
1006 };
1007 
1008 } // ns std
1009 #endif // PROTON_STRING_HEADER