1// -*- Mode: C++; tab-width: 2; -*-
2// vi: set ts=2:
3//
4
5BALL_INLINE
6String::String()
7	: string()
8{
9}
10
11BALL_INLINE String::String(const String& s)
12	: string(s)
13{
14}
15
16#ifdef BALL_STD_STRING_HAS_RVALUE_REFERENCES
17BALL_INLINE
18String::String(String&& s)
19	: string(std::move(s))
20{
21}
22
23BALL_INLINE
24String::String(string&& s)
25	: string(std::move(s))
26{
27}
28
29BALL_INLINE
30String& String::operator=(String&& s)
31{
32	if (this != &s)
33	{
34		string::operator=(std::move(s));
35	}
36
37	return *this;
38}
39
40BALL_INLINE
41String& String::operator=(string&& s)
42{
43	if (this != &s)
44	{
45		string::operator=(std::move(s));
46	}
47
48	return *this;
49}
50#endif
51
52BALL_INLINE
53String::String(const unsigned char c)
54	: string(1, (char)c)
55{
56}
57
58BALL_INLINE
59String::String(const char c, Size len)
60	: string(len, c)
61{
62}
63
64BALL_INLINE
65String::String(const string& s)
66	: string(s)
67{
68}
69
70BALL_INLINE
71String::String(const String& s, Index from, Size len)
72	: string("")
73{
74	s.validateRange_(from, len);
75	if (len > 0)
76	{
77		assign(s.c_str() + from, len);
78	}
79}
80
81BALL_INLINE
82#ifdef BALL_HAS_SSTREAM
83void String::set(std::stringstream& s)
84#else
85void String::set(std::strstream& s)
86#endif
87{
88	s >> (*this);
89}
90
91BALL_INLINE
92void String::set(char c, Size len)
93{
94	assign(len, c);
95}
96
97BALL_INLINE
98void String::set(unsigned char c)
99{
100	assign(1, (char)c);
101}
102
103BALL_INLINE
104bool String::operator == (const char* char_ptr) const
105{
106  return (compare(char_ptr) == 0);
107}
108
109BALL_INLINE
110bool String::operator != (const char* char_ptr) const
111{
112  return (compare(char_ptr) != 0);
113}
114
115BALL_INLINE
116bool Substring::operator == (const String& s) const
117{
118	if (bound_ == 0)
119	{
120		throw UnboundSubstring(__FILE__, __LINE__);
121	}
122
123  return (s.compare(bound_->c_str() + from_, 0, to_ - from_ + 1) == 0);
124}
125
126BALL_INLINE
127bool Substring::operator != (const String& s) const
128{
129  if (bound_ == 0)
130  {
131    throw UnboundSubstring(__FILE__, __LINE__);
132	}
133
134  return (s.compare(bound_->c_str() + from_, 0, to_ - from_ + 1) != 0);
135}
136
137BALL_INLINE
138Size Substring::size() const
139{
140	if (bound_ == 0)
141	{
142		return 0;
143	}
144
145	return (to_ - from_ + 1);
146}
147
148BALL_INLINE
149Substring::operator String() const
150{
151	if (bound_ == 0)
152	{
153		throw UnboundSubstring(__FILE__, __LINE__);
154	}
155
156  return String(bound_->c_str(), from_, to_ - from_ + 1);
157}
158
159BALL_INLINE
160void Substring::unbind()
161{
162  bound_ = 0;
163  from_ = to_ = (Index)String::EndPos;
164}
165
166BALL_INLINE
167void Substring::destroy()
168{
169	if (bound_ != 0)
170	{
171	  bound_->erase(from_, to_ - from_ + 1);
172	}
173
174  unbind();
175}
176
177BALL_INLINE
178void Substring::clear()
179{
180	destroy();
181}
182
183BALL_INLINE
184String Substring::toString() const
185{
186	if (bound_ == 0)
187	{
188		throw UnboundSubstring(__FILE__, __LINE__);
189	}
190
191  return String(bound_->c_str(), from_, to_ - from_ + 1);
192}
193
194BALL_INLINE
195Substring& Substring::bind(const String& s, Index from, Size len)
196{
197	s.validateRange_(from, len);
198
199  bound_ = (String *)&s;
200  from_ = from;
201  to_ = from + (Index)len - 1;
202
203  return *this;
204}
205
206BALL_INLINE
207void Substring::set(const String& s)
208{
209	if (bound_ == 0)
210	{
211		throw Substring::UnboundSubstring(__FILE__, __LINE__);
212	}
213
214  bound_->replace(from_, to_ - from_ + 1, s);
215}
216
217BALL_INLINE
218void Substring::set(const Substring& s)
219{
220	if (bound_ == 0 || s.bound_ == 0)
221	{
222		throw Substring::UnboundSubstring(__FILE__, __LINE__);
223	}
224
225  bound_->replace(from_, to_ - from_ + 1, s.bound_->c_str() + s.from_, s.size());
226}
227
228BALL_INLINE
229const Substring& Substring::operator = (const String& s)
230{
231  set(s);
232  return *this;
233}
234
235BALL_INLINE
236const Substring& Substring::operator = (const Substring& s)
237{
238  set(s);
239  return *this;
240}
241
242BALL_INLINE
243const Substring& Substring::operator = (const char* char_ptr)
244{
245  set(char_ptr);
246  return *this;
247}
248
249BALL_INLINE
250String* Substring::getBoundString()
251{
252  return bound_;
253}
254
255BALL_INLINE
256const String* Substring::getBoundString() const
257{
258  return bound_;
259}
260
261BALL_INLINE
262char* Substring::c_str()
263{
264  if (bound_ == 0)
265  {
266    throw UnboundSubstring(__FILE__, __LINE__);
267	}
268
269  return (char*)&(bound_->c_str()[from_]);
270}
271
272BALL_INLINE
273const char* Substring::c_str() const
274{
275  if (bound_ == 0)
276  {
277    throw UnboundSubstring(__FILE__, __LINE__);
278	}
279
280  return &(bound_->c_str()[from_]);
281}
282
283BALL_INLINE
284Index Substring::getFirstIndex() const
285{
286  if (bound_ == 0)
287  {
288    throw UnboundSubstring(__FILE__, __LINE__);
289	}
290
291  return from_;
292}
293
294BALL_INLINE
295Index Substring::getLastIndex() const
296{
297  if (bound_ == 0)
298  {
299    throw UnboundSubstring(__FILE__, __LINE__);
300	}
301
302  return to_;
303}
304
305BALL_INLINE
306char& Substring::operator [] (Index index)
307{
308  if (bound_ == 0)
309  {
310    throw UnboundSubstring(__FILE__, __LINE__);
311	}
312
313	Size len = String::EndPos;
314	validateRange_(index, len);
315
316  return (*bound_)[from_ + index];
317}
318
319BALL_INLINE
320char Substring::operator [] (Index index) const
321{
322  if (bound_ == 0)
323  {
324    throw UnboundSubstring(__FILE__, __LINE__);
325	}
326
327	Size len = String::EndPos;
328	validateRange_(index, len);
329
330  return (*bound_)[from_ + index];
331}
332
333BALL_INLINE
334bool Substring::isBound() const
335{
336  return (bound_ != 0);
337}
338
339BALL_INLINE
340bool Substring::isEmpty() const
341{
342  return (bound_ == 0);
343}
344
345BALL_INLINE
346int String::compare(char c, Index from) const
347{
348	validateIndex_(from);
349	return (c_str()[from] - c);
350}
351
352
353BALL_INLINE
354bool Substring::operator == (char c) const
355{
356  if (bound_ == 0)
357  {
358    throw UnboundSubstring(__FILE__, __LINE__);
359	}
360  return (bound_->compare(c, from_, to_ - from_ + 1) == 0);
361}
362
363BALL_INLINE
364bool Substring::operator != (char c) const
365{
366  if (bound_ == 0)
367  {
368    throw UnboundSubstring(__FILE__, __LINE__);
369	}
370
371  return (bound_->compare(c, from_, to_ - from_ + 1) != 0);
372}
373
374BALL_INLINE
375bool Substring::isValid() const
376{
377  return (bound_ != 0 && from_ >= 0 && from_ <= to_ && to_ < (Index)bound_->size()) ;
378}
379
380BALL_INLINE
381Substring& Substring::toLower()
382{
383  if (bound_ == 0)
384  {
385    throw UnboundSubstring(__FILE__, __LINE__);
386	}
387	(*bound_).toLower(from_, to_ - from_);
388  return *this;
389}
390
391BALL_INLINE
392Substring& Substring::toUpper()
393{
394  if (bound_ == 0)
395  {
396    throw UnboundSubstring(__FILE__, __LINE__);
397	}
398	(*bound_).toUpper(from_, to_ - from_);
399  return *this;
400}
401
402BALL_INLINE
403const String& String::operator = (const String& s)
404{
405  set(s);
406  return *this;
407}
408
409BALL_INLINE
410const String& String::operator = (const char* char_ptr)
411{
412  set(char_ptr, 0);
413  return *this;
414}
415
416BALL_INLINE
417
418#ifdef BALL_HAS_SSTREAM
419const String& String::operator = (std::stringstream& s)
420#else
421const String& String::operator = (std::strstream& s)
422#endif
423{
424  set(s);
425  return *this;
426}
427
428#define BALL_STRING_DEFINE_ASSIGNMENT_METHOD(Type) \
429BALL_INLINE \
430const String& String::operator = (Type t) \
431{ \
432  set(t); \
433\
434  return *this; \
435}
436
437BALL_STRING_DEFINE_ASSIGNMENT_METHOD(char)
438BALL_STRING_DEFINE_ASSIGNMENT_METHOD(unsigned char)
439BALL_STRING_DEFINE_ASSIGNMENT_METHOD(short)
440BALL_STRING_DEFINE_ASSIGNMENT_METHOD(unsigned short)
441BALL_STRING_DEFINE_ASSIGNMENT_METHOD(int)
442BALL_STRING_DEFINE_ASSIGNMENT_METHOD(unsigned int)
443BALL_STRING_DEFINE_ASSIGNMENT_METHOD(long)
444BALL_STRING_DEFINE_ASSIGNMENT_METHOD(unsigned long)
445#ifdef BALL_ALLOW_LONG64_TYPE_OVERLOADS
446BALL_STRING_DEFINE_ASSIGNMENT_METHOD(LongIndex)
447BALL_STRING_DEFINE_ASSIGNMENT_METHOD(LongSize)
448#endif
449BALL_STRING_DEFINE_ASSIGNMENT_METHOD(float)
450BALL_STRING_DEFINE_ASSIGNMENT_METHOD(double)
451#undef BALL_STRING_DEFINE_ASSIGNMENT_METHOD
452
453BALL_INLINE
454void String::setCompareMode(CompareMode mode)
455{
456  compare_mode_ = mode;
457}
458
459BALL_INLINE
460String::CompareMode String::getCompareMode()
461{
462  return compare_mode_;
463}
464
465BALL_INLINE
466char String::toChar() const
467{
468  return *c_str();
469}
470
471BALL_INLINE
472unsigned char String::toUnsignedChar() const
473{
474  return (unsigned char)*c_str();
475}
476
477BALL_INLINE
478Substring String::getSubstring(Index from, Size len) const
479{
480	validateRange_(from, len);
481  return Substring(*this, from, len);
482}
483
484BALL_INLINE
485Substring String::operator () (Index from, Size len) const
486{
487  return getSubstring(from, len);
488}
489
490BALL_INLINE
491String& String::trim(const char* trimmed)
492{
493  return trimRight(trimmed).trimLeft(trimmed);
494}
495
496BALL_INLINE
497String String::trim(const char* trimmed) const
498{
499	String tmp(*this);
500	tmp.trimRight(trimmed);
501	tmp.trimLeft(trimmed);
502  return tmp;
503}
504
505BALL_INLINE
506String& String::truncate(Size max_size)
507{
508  if (max_size < (Size) size())
509	{
510    resize(max_size);
511	}
512
513	return *this;
514}
515
516BALL_INLINE
517Substring String::left(Size len) const
518{
519	if (len > (Size)size())
520	{
521		len = (Size)size();
522	}
523
524  return Substring(*this, 0, len);
525}
526
527BALL_INLINE
528Substring String::instr(const String& patterns, Index from) const
529{
530  string::size_type found = find(patterns, from);
531
532  return (found == string::npos)
533         ? Substring(*this, 0, 0)
534         : Substring(*this, (Index)found, (Size)patterns.size());
535}
536
537BALL_INLINE
538String operator + (const String& s1, const string& s2)
539{
540  String result(s1);
541  result.append(s2);
542  return result;
543}
544
545BALL_INLINE
546String operator + (const string& s1, const String& s2)
547{
548  String result(s1);
549  result.append(s2);
550  return result;
551}
552
553BALL_INLINE
554String operator + (const String& s1, const String& s2)
555{
556  String result(s1);
557  result.append(s2);
558  return result;
559}
560
561BALL_INLINE
562String operator +(const String& s1, const char* char_ptr)
563{
564  String result(s1);
565  result.append(char_ptr);
566  return result;
567}
568
569BALL_INLINE
570String operator + (const String& s1, char c)
571{
572  String result(s1);
573  result.append(1, c);
574  return result;
575}
576
577#ifdef BALL_STD_STRING_HAS_RVALUE_REFERENCES
578///	Concatenates two strings
579BALL_INLINE
580String operator + (String&& s1, const string& s2)
581{
582	s1.append(s2);
583	return std::move(s1);
584}
585
586BALL_INLINE
587String operator + (String&& s1, const String& s2)
588{
589	s1.append(s2);
590	return std::move(s1);
591}
592
593BALL_INLINE
594String operator + (String&& s1, String&& s2)
595{
596	s1.append(s2);
597	return std::move(s1);
598}
599
600BALL_INLINE
601String operator + (const String& s1, string&& s2)
602{
603	return std::move(std::operator+(s1, std::move(s2)));
604}
605
606BALL_INLINE
607String operator + (const String& s1, String&& s2)
608{
609	return std::move(std::operator+(s1, std::move(s2)));
610}
611
612BALL_INLINE
613String operator + (string&& s1, const String& s2)
614{
615	s1.append(s2);
616	return std::move(s1);
617}
618
619BALL_INLINE
620String operator + (const string& s1, String&& s2)
621{
622	return std::move(std::operator+(s1, std::move(s2)));
623}
624
625/// Concatenates a string and a C type string
626BALL_INLINE
627String operator + (String&& s1, const char* char_ptr)
628{
629	s1 += char_ptr;
630	return std::move(s1);
631}
632
633/// Concatenates a C type string and a string
634BALL_INLINE
635String operator + (const char* char_ptr, String&& s)
636{
637	return std::move(std::operator+(char_ptr,std::move(s)));
638}
639
640/// Concatenates a string and a character
641BALL_INLINE
642String operator + (String&& s, char c)
643{
644	s += c;
645	return std::move(s);
646}
647
648/// Concatenates a character and a string
649BALL_INLINE
650String operator + (char c, String&& s)
651{
652	return std::move(std::operator+(c, std::move(s)));
653}
654
655#endif
656
657BALL_INLINE
658void String::destroy()
659{
660  assign("");
661}
662
663BALL_INLINE
664void String::clear()
665{
666  assign("");
667}
668
669BALL_INLINE
670bool String::has(char c) const
671{
672  return ((c != (char)0) && (find(c, 0) != string::npos));
673}
674
675BALL_INLINE
676bool String::hasSubstring(const String& s, Index from) const
677{
678	if (s.size() == 0)
679	{
680		return true;
681	}
682
683  return (find(s, from) != string::npos);
684}
685
686BALL_INLINE
687bool String::isEmpty() const
688{
689  return (size() == 0);
690}
691
692BALL_INLINE
693bool String::isAlpha(char c)
694{
695	return ((c != 0) && ((char*)strchr(CHARACTER_CLASS__ASCII_ALPHA, c) != 0));
696}
697
698BALL_INLINE
699bool String::isAlnum(char c)
700{
701	return ((c != 0) && ((char*)strchr(CHARACTER_CLASS__ASCII_ALPHANUMERIC, c) != 0));
702}
703
704BALL_INLINE
705bool String::isDigit(char c)
706{
707  return ((c != 0) && ((char*)strchr(CHARACTER_CLASS__ASCII_NUMERIC, c) != 0));
708}
709
710BALL_INLINE
711bool String::isFloat() const
712{
713	char* test;
714	char* str = const_cast<char*>(c_str());
715  errno = 0;
716
717//Get rid of those friggin warnings
718#if defined BALL_COMPILER_GXX && ((BALL_COMPILER_VERSION_MAJOR == 4 && BALL_COMPILER_VERSION_MINOR < 6) || BALL_COMPILER_VERSION_MAJOR < 4)
719	double d = 0;
720	d = strtod(str, &test);
721#else
722	strtod(str, &test);
723#endif
724	return (errno == 0 && *test == '\0');
725}
726
727BALL_INLINE
728bool String::isSpace(char c)
729{
730  return (c == ' ');
731}
732
733BALL_INLINE
734bool String::isWhitespace(char c)
735{
736  return ((c != 0) && ((char*)strchr(CHARACTER_CLASS__WHITESPACE, c) != 0));
737}
738
739BALL_INLINE
740bool String::operator != (const String& s) const
741{
742  return (compare(s) != 0);
743}
744
745BALL_INLINE
746bool String::operator < (const String& s) const
747{
748  return (compare(s) < 0);
749}
750
751BALL_INLINE
752bool String::operator <= (const String& s) const
753{
754  return (compare(s) <= 0);
755}
756
757BALL_INLINE
758bool String::operator >= (const String& s) const
759{
760  return (compare(s) >= 0);
761}
762
763BALL_INLINE
764bool String::operator > (const String& s) const
765{
766  return (compare(s) > 0);
767}
768
769BALL_INLINE
770bool String::operator == (const String& string) const
771{
772	return (compare(string.c_str()) == 0);
773}
774
775BALL_INLINE
776bool String::operator < (const char* char_ptr) const
777{
778  return (compare(char_ptr) < 0);
779}
780
781BALL_INLINE
782bool String::operator <= (const char* char_ptr) const
783{
784  return (compare(char_ptr) <= 0);
785}
786
787BALL_INLINE
788bool String::operator >= (const char* char_ptr) const
789{
790  return (compare(char_ptr) >= 0);
791}
792
793BALL_INLINE
794bool String::operator > (const char* char_ptr) const
795{
796  return (compare(char_ptr) > 0);
797}
798
799BALL_INLINE
800bool String::operator == (char c) const
801{
802  return (compare(c) == 0);
803}
804
805BALL_INLINE
806bool String::operator != (char c) const
807{
808  return (compare(c) != 0);
809}
810
811BALL_INLINE
812bool String::operator < (char c) const
813{
814  return (compare(c) < 0);
815}
816
817BALL_INLINE
818bool String::operator <= (char c) const
819{
820  return (compare(c) <= 0);
821}
822
823BALL_INLINE
824bool String::operator >= (char c) const
825{
826  return (compare(c) >= 0);
827}
828
829BALL_INLINE
830bool String::operator > (char c) const
831{
832  return (compare(c) > 0);
833}
834
835BALL_INLINE
836bool String::isValid() const
837{
838  return (c_str() != 0 && size() <= capacity());
839}
840
841BALL_INLINE
842std::istream& String::getline(std::istream& s,  char delimiter)
843{
844	static vector<char> line_buffer(8192);
845  s.getline(&(line_buffer[0]), 8191, delimiter);
846	set(&(line_buffer[0]));
847
848	return s;
849}
850
851BALL_INLINE
852bool operator != (const String& s, const Substring& substring)
853{
854	return (substring != s);
855}
856
857BALL_INLINE
858bool operator == (const String& s, const Substring& substring)
859{
860	return (substring == s);
861}
862
863BALL_INLINE
864void String::swap(String& s)
865{
866	string::swap(s);
867}
868
869BALL_INLINE
870bool operator == (const char* char_ptr, const String &s)
871{
872	return (s.compare(char_ptr) == 0);
873}
874
875BALL_INLINE
876bool operator != (const char* char_ptr, const String &s)
877{
878	return (s.compare(char_ptr) != 0);
879}
880
881BALL_INLINE
882bool operator < (const char* char_ptr, const String& s)
883{
884	return (s.compare(char_ptr) > 0);
885}
886
887BALL_INLINE
888bool operator <= (const char* char_ptr, const String &s)
889{
890	return (s.compare(char_ptr) >= 0);
891}
892
893BALL_INLINE
894bool operator >= (const char* char_ptr, const String& s)
895{
896	return (s.compare(char_ptr) <= 0);
897}
898
899BALL_INLINE
900bool operator > (const char* char_ptr, const String& s)
901{
902	return (s.compare(char_ptr) < 0);
903}
904
905BALL_INLINE
906bool operator == (char c, const String& s)
907{
908	return (s.compare(c) == 0);
909}
910
911BALL_INLINE
912bool operator != (char c, const String &s)
913{
914	return (s.compare(c) != 0);
915}
916
917BALL_INLINE
918bool operator < (char c, const String& s)
919{
920	return (s.compare(c) > 0);
921}
922
923BALL_INLINE
924bool operator <= (char c, const String &s)
925{
926	return (s.compare(c) >= 0);
927}
928
929BALL_INLINE
930bool operator >= (char c, const String &s)
931{
932	return (s.compare(c) <= 0);
933}
934
935BALL_INLINE
936bool operator > (char c, const String &s)
937{
938	return (s.compare(c) < 0);
939}
940