Bläddra i källkod

StringView constexpr. (#351)

Branimir Karadžić 3 veckor sedan
förälder
incheckning
808aa150f8
8 ändrade filer med 281 tillägg och 138 borttagningar
  1. 7 0
      include/bx/inline/bx.inl
  2. 157 41
      include/bx/inline/string.inl
  3. 2 2
      include/bx/platform.h
  4. 8 0
      include/bx/readerwriter.h
  5. 63 39
      include/bx/string.h
  6. 2 8
      src/dtoa.cpp
  7. 1 13
      src/string.cpp
  8. 41 35
      tests/string_test.cpp

+ 7 - 0
include/bx/inline/bx.inl

@@ -171,6 +171,13 @@ namespace bx
 		return __builtin_bit_cast(Ty, _from);
 		return __builtin_bit_cast(Ty, _from);
 	}
 	}
 
 
+	template<typename Ty, typename FromT>
+	inline constexpr bool narrowCastTest(Ty* _out, const FromT& _from)
+	{
+		*_out = static_cast<Ty>(_from);
+		return static_cast<FromT>(*_out) == _from;
+	}
+
 	template<typename Ty, typename FromT>
 	template<typename Ty, typename FromT>
 	inline Ty narrowCast(const FromT& _from, Location _location)
 	inline Ty narrowCast(const FromT& _from, Location _location)
 	{
 	{

+ 157 - 41
include/bx/inline/string.inl

@@ -44,8 +44,8 @@ namespace bx
 	}
 	}
 
 
 	template<int32_t SizeT>
 	template<int32_t SizeT>
-	inline constexpr StringLiteral::StringLiteral(const char (&str)[SizeT])
-		: m_ptr(str)
+	inline constexpr StringLiteral::StringLiteral(const char (&_str)[SizeT])
+		: m_ptr(_str)
 		, m_len(SizeT - 1)
 		, m_len(SizeT - 1)
 	{
 	{
 		BX_ASSERT('\0' == m_ptr[SizeT - 1], "Must be 0 terminated.");
 		BX_ASSERT('\0' == m_ptr[SizeT - 1], "Must be 0 terminated.");
@@ -61,20 +61,21 @@ namespace bx
 		return m_ptr;
 		return m_ptr;
 	}
 	}
 
 
-	inline void StringLiteral::clear()
+	inline constexpr void StringLiteral::clear()
 	{
 	{
 		m_ptr = "";
 		m_ptr = "";
 		m_len = 0;
 		m_len = 0;
 	}
 	}
 
 
-	inline bool StringLiteral::isEmpty() const
+	inline constexpr bool StringLiteral::isEmpty() const
 	{
 	{
 		return 0 == m_len;
 		return 0 == m_len;
 	}
 	}
 
 
-	inline StringView::StringView()
+	inline constexpr StringView::StringView()
 	{
 	{
-		clear();
+		m_ptr = "";
+		m_len = 0;
 	}
 	}
 
 
 	inline constexpr StringView::StringView(const StringLiteral& _str)
 	inline constexpr StringView::StringView(const StringLiteral& _str)
@@ -84,49 +85,49 @@ namespace bx
 	{
 	{
 	}
 	}
 
 
-	inline StringView::StringView(const StringView& _rhs)
+	inline constexpr StringView::StringView(const StringView& _rhs)
 	{
 	{
 		set(_rhs);
 		set(_rhs);
 	}
 	}
 
 
-	inline StringView::StringView(const StringView& _rhs, int32_t _start, int32_t _len)
+	inline constexpr StringView::StringView(const StringView& _rhs, int32_t _start, int32_t _len)
 	{
 	{
 		set(_rhs, _start, _len);
 		set(_rhs, _start, _len);
 	}
 	}
 
 
-	inline StringView& StringView::operator=(const char* _rhs)
+	inline constexpr StringView& StringView::operator=(const char* _rhs)
 	{
 	{
 		set(_rhs);
 		set(_rhs);
 		return *this;
 		return *this;
 	}
 	}
 
 
-	inline StringView& StringView::operator=(const StringView& _rhs)
+	inline constexpr StringView& StringView::operator=(const StringView& _rhs)
 	{
 	{
 		set(_rhs);
 		set(_rhs);
 		return *this;
 		return *this;
 	}
 	}
 
 
-	inline StringView::StringView(const char* _ptr)
+	inline constexpr StringView::StringView(const char* _ptr)
 	{
 	{
 		set(_ptr, INT32_MAX);
 		set(_ptr, INT32_MAX);
 	}
 	}
 
 
-	inline StringView::StringView(const char* _ptr, int32_t _len)
+	inline constexpr StringView::StringView(const char* _ptr, int32_t _len)
 	{
 	{
 		set(_ptr, _len);
 		set(_ptr, _len);
 	}
 	}
 
 
-	inline StringView::StringView(const char* _ptr, const char* _term)
+	inline constexpr StringView::StringView(const char* _ptr, const char* _term)
 	{
 	{
 		set(_ptr, _term);
 		set(_ptr, _term);
 	}
 	}
 
 
-	inline void StringView::set(const char* _ptr)
+	inline constexpr void StringView::set(const char* _ptr)
 	{
 	{
 		set(_ptr, INT32_MAX);
 		set(_ptr, INT32_MAX);
 	}
 	}
 
 
-	inline void StringView::set(const char* _ptr, int32_t _len)
+	inline constexpr void StringView::set(const char* _ptr, int32_t _len)
 	{
 	{
 		clear();
 		clear();
 
 
@@ -138,68 +139,99 @@ namespace bx
 		}
 		}
 	}
 	}
 
 
-	inline void StringView::set(const char* _ptr, const char* _term)
+	inline constexpr void StringView::set(const char* _ptr, const char* _term)
 	{
 	{
 		set(_ptr, int32_t(_term-_ptr) );
 		set(_ptr, int32_t(_term-_ptr) );
 	}
 	}
 
 
-	inline void StringView::set(const StringView& _str)
+	inline constexpr void StringView::set(const StringView& _str)
 	{
 	{
 		set(_str, 0, INT32_MAX);
 		set(_str, 0, INT32_MAX);
 	}
 	}
 
 
-	inline void StringView::set(const StringView& _str, int32_t _start, int32_t _len)
+	inline constexpr void StringView::set(const StringView& _str, int32_t _start, int32_t _len)
 	{
 	{
 		const int32_t start = min(_start, _str.m_len);
 		const int32_t start = min(_start, _str.m_len);
 		const int32_t len   = clamp(_str.m_len - start, 0, min(_len, _str.m_len) );
 		const int32_t len   = clamp(_str.m_len - start, 0, min(_len, _str.m_len) );
 		set(_str.m_ptr + start, len);
 		set(_str.m_ptr + start, len);
 	}
 	}
 
 
-	inline void StringView::clear()
+	inline constexpr void StringView::clear()
 	{
 	{
 		m_ptr = "";
 		m_ptr = "";
 		m_len = 0;
 		m_len = 0;
 		m_0terminated = true;
 		m_0terminated = true;
 	}
 	}
 
 
-	inline const char* StringView::getPtr() const
+	inline constexpr const char* StringView::getPtr() const
 	{
 	{
 		return m_ptr;
 		return m_ptr;
 	}
 	}
 
 
-	inline const char* StringView::getTerm() const
+	inline constexpr const char* StringView::getTerm() const
 	{
 	{
 		return m_ptr + m_len;
 		return m_ptr + m_len;
 	}
 	}
 
 
-	inline bool StringView::isEmpty() const
+	inline constexpr bool StringView::isEmpty() const
 	{
 	{
 		return 0 == m_len;
 		return 0 == m_len;
 	}
 	}
 
 
-	inline int32_t StringView::getLength() const
+	inline constexpr int32_t StringView::getLength() const
 	{
 	{
 		return m_len;
 		return m_len;
 	}
 	}
 
 
-	inline bool StringView::is0Terminated() const
+	inline constexpr bool StringView::is0Terminated() const
 	{
 	{
 		return m_0terminated;
 		return m_0terminated;
 	}
 	}
 
 
-	inline bool operator==(const StringView& _lhs, const StringView& _rhs)
+	inline constexpr bool operator==(const StringView& _lhs, const StringView& _rhs)
 	{
 	{
-		return 0 == strCmp(_lhs, _rhs);
+		const int32_t len = _lhs.getLength();
+
+		if (len != _rhs.getLength() )
+		{
+			return false;
+		}
+
+		if (0 == len)
+		{
+			return true;
+		}
+
+		const char* lhs = _lhs.getPtr();
+		const char* rhs = _rhs.getPtr();
+
+		if constexpr (!isConstantEvaluated() )
+		{
+			// note: comparison of addresses of literals has unspecified value
+			if (lhs == rhs)
+			{
+				return true;
+			}
+		}
+
+		for (int32_t ii = 0, num = len-1
+			; ii < num && *lhs == *rhs
+			; ++ii, ++lhs, ++rhs
+			)
+		{
+		}
+
+		return *lhs == *rhs;
 	}
 	}
 
 
-	inline bool overlap(const StringView& _a, const StringView& _b)
+	inline constexpr bool overlap(const StringView& _a, const StringView& _b)
 	{
 	{
 		return _a.getTerm() > _b.getPtr()
 		return _a.getTerm() > _b.getPtr()
 			&& _b.getTerm() > _a.getPtr()
 			&& _b.getTerm() > _a.getPtr()
 			;
 			;
 	}
 	}
 
 
-	inline bool contain(const StringView& _a, const StringView& _b)
+	inline constexpr bool contain(const StringView& _a, const StringView& _b)
 	{
 	{
 		return _a.getPtr()  <= _b.getPtr()
 		return _a.getPtr()  <= _b.getPtr()
 			&& _a.getTerm() >= _b.getTerm()
 			&& _a.getTerm() >= _b.getTerm()
@@ -207,76 +239,76 @@ namespace bx
 	}
 	}
 
 
 	template<uint16_t MaxCapacityT>
 	template<uint16_t MaxCapacityT>
-	inline FixedStringT<MaxCapacityT>::FixedStringT()
+	inline constexpr FixedStringT<MaxCapacityT>::FixedStringT()
 		: m_len(0)
 		: m_len(0)
 	{
 	{
 	}
 	}
 
 
 	template<uint16_t MaxCapacityT>
 	template<uint16_t MaxCapacityT>
-	inline FixedStringT<MaxCapacityT>::FixedStringT(const char* _str)
+	inline constexpr FixedStringT<MaxCapacityT>::FixedStringT(const char* _str)
 		: FixedStringT<MaxCapacityT>()
 		: FixedStringT<MaxCapacityT>()
 	{
 	{
 		set(_str);
 		set(_str);
 	}
 	}
 
 
 	template<uint16_t MaxCapacityT>
 	template<uint16_t MaxCapacityT>
-	inline FixedStringT<MaxCapacityT>::FixedStringT(const StringView& _str)
+	inline constexpr FixedStringT<MaxCapacityT>::FixedStringT(const StringView& _str)
 		: FixedStringT<MaxCapacityT>()
 		: FixedStringT<MaxCapacityT>()
 	{
 	{
 		set(_str);
 		set(_str);
 	}
 	}
 
 
 	template<uint16_t MaxCapacityT>
 	template<uint16_t MaxCapacityT>
-	inline FixedStringT<MaxCapacityT>::~FixedStringT()
+	inline constexpr FixedStringT<MaxCapacityT>::~FixedStringT()
 	{
 	{
 	}
 	}
 
 
 	template<uint16_t MaxCapacityT>
 	template<uint16_t MaxCapacityT>
-	inline void FixedStringT<MaxCapacityT>::set(const char* _str)
+	inline constexpr void FixedStringT<MaxCapacityT>::set(const char* _str)
 	{
 	{
 		set(StringView(_str) );
 		set(StringView(_str) );
 	}
 	}
 
 
 	template<uint16_t MaxCapacityT>
 	template<uint16_t MaxCapacityT>
-	inline void FixedStringT<MaxCapacityT>::set(const StringView& _str)
+	inline constexpr void FixedStringT<MaxCapacityT>::set(const StringView& _str)
 	{
 	{
 		int32_t copied = strCopy(m_storage, MaxCapacityT, _str);
 		int32_t copied = strCopy(m_storage, MaxCapacityT, _str);
 		m_len = copied;
 		m_len = copied;
 	}
 	}
 
 
 	template<uint16_t MaxCapacityT>
 	template<uint16_t MaxCapacityT>
-	inline void FixedStringT<MaxCapacityT>::append(const StringView& _str)
+	inline constexpr void FixedStringT<MaxCapacityT>::append(const StringView& _str)
 	{
 	{
 		m_len += strCopy(&m_storage[m_len], MaxCapacityT-m_len, _str);
 		m_len += strCopy(&m_storage[m_len], MaxCapacityT-m_len, _str);
 	}
 	}
 
 
 	template<uint16_t MaxCapacityT>
 	template<uint16_t MaxCapacityT>
-	inline void FixedStringT<MaxCapacityT>::clear()
+	inline constexpr void FixedStringT<MaxCapacityT>::clear()
 	{
 	{
 		m_len = 0;
 		m_len = 0;
 		m_storage[0] = '\0';
 		m_storage[0] = '\0';
 	}
 	}
 
 
 	template<uint16_t MaxCapacityT>
 	template<uint16_t MaxCapacityT>
-	inline bool FixedStringT<MaxCapacityT>::isEmpty() const
+	inline constexpr bool FixedStringT<MaxCapacityT>::isEmpty() const
 	{
 	{
 		return 0 == m_len;
 		return 0 == m_len;
 	}
 	}
 
 
 	template<uint16_t MaxCapacityT>
 	template<uint16_t MaxCapacityT>
-	inline int32_t FixedStringT<MaxCapacityT>::getLength() const
+	inline constexpr int32_t FixedStringT<MaxCapacityT>::getLength() const
 	{
 	{
 		return m_len;
 		return m_len;
 	}
 	}
 
 
 	template<uint16_t MaxCapacityT>
 	template<uint16_t MaxCapacityT>
-	inline const char* FixedStringT<MaxCapacityT>::getCPtr() const
+	inline constexpr const char* FixedStringT<MaxCapacityT>::getCPtr() const
 	{
 	{
 		return m_storage;
 		return m_storage;
 	}
 	}
 
 
 	template<uint16_t MaxCapacityT>
 	template<uint16_t MaxCapacityT>
-	inline FixedStringT<MaxCapacityT>::operator StringView() const
+	inline constexpr FixedStringT<MaxCapacityT>::operator StringView() const
 	{
 	{
 		return StringView(m_storage, m_len);
 		return StringView(m_storage, m_len);
 	}
 	}
@@ -438,11 +470,23 @@ namespace bx
 		return m_line;
 		return m_line;
 	}
 	}
 
 
-	inline int32_t strLen(const StringView& _str, int32_t _max)
+	inline constexpr int32_t strLen(const StringView& _str, int32_t _max)
 	{
 	{
 		return min(_str.getLength(), _max);
 		return min(_str.getLength(), _max);
 	}
 	}
 
 
+	inline constexpr int32_t strLen(const char* _str, int32_t _max)
+	{
+		if (NULL == _str)
+		{
+			return 0;
+		}
+
+		const char* ptr = _str;
+		for (; 0 < _max && *ptr != '\0'; ++ptr, --_max) {};
+		return int32_t(ptr - _str);
+	}
+
 	inline bool hasPrefix(const StringView& _str, const StringView& _prefix)
 	inline bool hasPrefix(const StringView& _str, const StringView& _prefix)
 	{
 	{
 		const int32_t len = _prefix.getLength();
 		const int32_t len = _prefix.getLength();
@@ -479,4 +523,76 @@ namespace bx
 		return _str;
 		return _str;
 	}
 	}
 
 
+	inline bool fromString(int8_t* _out, const StringView& _str)
+	{
+		long long tmp;
+		fromString(&tmp, _str);
+
+		return narrowCastTest(_out, tmp);
+	}
+
+	inline bool fromString(uint8_t* _out, const StringView& _str)
+	{
+		long long tmp;
+		fromString(&tmp, _str);
+
+		return narrowCastTest(_out, tmp);
+	}
+
+	inline bool fromString(int16_t* _out, const StringView& _str)
+	{
+		long long tmp;
+		fromString(&tmp, _str);
+
+		return narrowCastTest(_out, tmp);
+	}
+
+	inline bool fromString(uint16_t* _out, const StringView& _str)
+	{
+		long long tmp;
+		fromString(&tmp, _str);
+
+		return narrowCastTest(_out, tmp);
+	}
+
+	inline bool fromString(int32_t* _out, const StringView& _str)
+	{
+		long long tmp;
+		fromString(&tmp, _str);
+
+		return narrowCastTest(_out, tmp);
+	}
+
+	inline bool fromString(uint32_t* _out, const StringView& _str)
+	{
+		long long tmp;
+		fromString(&tmp, _str);
+
+		return narrowCastTest(_out, tmp);
+	}
+
+	inline bool fromString(long* _out, const StringView& _str)
+	{
+		long long tmp;
+		fromString(&tmp, _str);
+
+		return narrowCastTest(_out, tmp);
+	}
+
+	inline bool fromString(unsigned long* _out, const StringView& _str)
+	{
+		long long tmp;
+		fromString(&tmp, _str);
+
+		return narrowCastTest(_out, tmp);
+	}
+
+	inline bool fromString(unsigned long long* _out, const StringView& _str)
+	{
+		long long tmp;
+		fromString(&tmp, _str);
+
+		return narrowCastTest(_out, tmp);
+	}
+
 } // namespace bx
 } // namespace bx

+ 2 - 2
include/bx/platform.h

@@ -452,9 +452,9 @@
 
 
 #if defined(__cplusplus)
 #if defined(__cplusplus)
 
 
-static_assert(__cplusplus >= BX_LANGUAGE_CPP17, "\n\n"
+static_assert(__cplusplus >= BX_LANGUAGE_CPP20, "\n\n"
 	"\t** IMPORTANT! **\n\n"
 	"\t** IMPORTANT! **\n\n"
-	"\tC++17 standard support is required to build.\n"
+	"\tC++20 standard support is required to build.\n"
 	"\t\n");
 	"\t\n");
 
 
 // https://releases.llvm.org/
 // https://releases.llvm.org/

+ 8 - 0
include/bx/readerwriter.h

@@ -282,6 +282,14 @@ namespace bx
 	/// Write C string.
 	/// Write C string.
 	int32_t write(WriterI* _writer, const char* _str, Error* _err);
 	int32_t write(WriterI* _writer, const char* _str, Error* _err);
 
 
+	///
+	template<typename Ty>
+	inline int32_t write(WriterI* _writer, const Ty& _value, Error* _err);
+
+	///
+	template<>
+	int32_t write(WriterI* _writer, const StringView& _str, Error* _err);
+
 	/// Write formatted string.
 	/// Write formatted string.
 	int32_t write(WriterI* _writer, const StringView& _format, va_list _argList, Error* _err);
 	int32_t write(WriterI* _writer, const StringView& _format, va_list _argList, Error* _err);
 
 

+ 63 - 39
include/bx/string.h

@@ -32,7 +32,7 @@ namespace bx
 		/// Construct string literal from C-style string literal.
 		/// Construct string literal from C-style string literal.
 		///
 		///
 		template<int32_t SizeT>
 		template<int32_t SizeT>
-		constexpr StringLiteral(const char (&str)[SizeT]);
+		constexpr StringLiteral(const char (&_str)[SizeT]);
 
 
 		/// Returns string length.
 		/// Returns string length.
 		///
 		///
@@ -43,11 +43,11 @@ namespace bx
 		constexpr const char* getCPtr() const;
 		constexpr const char* getCPtr() const;
 
 
 		///
 		///
-		void clear();
+		constexpr void clear();
 
 
 		/// Returns `true` if string is empty.
 		/// Returns `true` if string is empty.
 		///
 		///
-		bool isEmpty() const;
+		constexpr bool isEmpty() const;
 
 
 	private:
 	private:
 		const char* m_ptr;
 		const char* m_ptr;
@@ -61,75 +61,75 @@ namespace bx
 	public:
 	public:
 		/// Construct default/empty string view.
 		/// Construct default/empty string view.
 		///
 		///
-		StringView();
+		constexpr StringView();
 
 
 		/// Construct string view from string literal.
 		/// Construct string view from string literal.
 		///
 		///
 		constexpr StringView(const StringLiteral& _str);
 		constexpr StringView(const StringLiteral& _str);
 
 
 		///
 		///
-		StringView(const StringView& _rhs);
+		constexpr StringView(const StringView& _rhs);
 
 
 		///
 		///
-		StringView(const StringView& _rhs, int32_t _start, int32_t _len);
+		constexpr StringView(const StringView& _rhs, int32_t _start, int32_t _len);
 
 
 		///
 		///
-		StringView& operator=(const char* _rhs);
+		constexpr StringView& operator=(const char* _rhs);
 
 
 		///
 		///
-		StringView& operator=(const StringView& _rhs);
+		constexpr StringView& operator=(const StringView& _rhs);
 
 
 		///
 		///
-		StringView(const char* _ptr);
+		constexpr StringView(const char* _ptr);
 
 
 		///
 		///
-		StringView(const char* _ptr, int32_t _len);
+		constexpr StringView(const char* _ptr, int32_t _len);
 
 
 		///
 		///
-		StringView(const char* _ptr, const char* _term);
+		constexpr StringView(const char* _ptr, const char* _term);
 
 
 		///
 		///
-		void set(const char* _ptr);
+		constexpr void set(const char* _ptr);
 
 
 		///
 		///
-		void set(const char* _ptr, int32_t _len);
+		constexpr void set(const char* _ptr, int32_t _len);
 
 
 		///
 		///
-		void set(const char* _ptr, const char* _term);
+		constexpr void set(const char* _ptr, const char* _term);
 
 
 		///
 		///
-		void set(const StringView& _str);
+		constexpr void set(const StringView& _str);
 
 
 		///
 		///
-		void set(const StringView& _str, int32_t _start, int32_t _len);
+		constexpr void set(const StringView& _str, int32_t _start, int32_t _len);
 
 
 		///
 		///
-		void clear();
+		constexpr void clear();
 
 
 		/// Returns pointer to non-terminated string.
 		/// Returns pointer to non-terminated string.
 		///
 		///
 		/// @attention Use of this pointer in standard C/C++ functions is not safe. You must use it
 		/// @attention Use of this pointer in standard C/C++ functions is not safe. You must use it
 		///   in conjunction with `getTerm()` or getLength()`.
 		///   in conjunction with `getTerm()` or getLength()`.
 		///
 		///
-		const char* getPtr() const;
+		constexpr const char* getPtr() const;
 
 
 		/// Returns pointer past last character in string view.
 		/// Returns pointer past last character in string view.
 		///
 		///
 		/// @attention Dereferencing this pointer is not safe.
 		/// @attention Dereferencing this pointer is not safe.
 		///
 		///
-		const char* getTerm() const;
+		constexpr const char* getTerm() const;
 
 
 		/// Returns `true` if string is empty.
 		/// Returns `true` if string is empty.
 		///
 		///
-		bool isEmpty() const;
+		constexpr bool isEmpty() const;
 
 
 		/// Returns string length.
 		/// Returns string length.
 		///
 		///
-		int32_t getLength() const;
+		constexpr int32_t getLength() const;
 
 
 		/// Returns `true` if string is zero terminated.
 		/// Returns `true` if string is zero terminated.
 		///
 		///
-		bool is0Terminated() const;
+		constexpr bool is0Terminated() const;
 
 
 	protected:
 	protected:
 		const char* m_ptr;
 		const char* m_ptr;
@@ -138,13 +138,13 @@ namespace bx
 	};
 	};
 
 
 	/// Compare two string views.
 	/// Compare two string views.
-	bool operator==(const StringView& _lhs, const StringView& _rhs);
+	constexpr bool operator==(const StringView& _lhs, const StringView& _rhs);
 
 
 	/// Returns true if two string views overlap.
 	/// Returns true if two string views overlap.
-	bool overlap(const StringView& _a, const StringView& _b);
+	constexpr bool overlap(const StringView& _a, const StringView& _b);
 
 
 	/// Returns true if string view `_a` contains string view `_b`.
 	/// Returns true if string view `_a` contains string view `_b`.
-	bool contain(const StringView& _a, const StringView& _b);
+	constexpr bool contain(const StringView& _a, const StringView& _b);
 
 
 	/// Fixed capacity string.
 	/// Fixed capacity string.
 	///
 	///
@@ -153,44 +153,44 @@ namespace bx
 	{
 	{
 	public:
 	public:
 		///
 		///
-		FixedStringT();
+		constexpr FixedStringT();
 
 
 		///
 		///
-		FixedStringT(const char* _str);
+		constexpr FixedStringT(const char* _str);
 
 
 		///
 		///
-		FixedStringT(const StringView& _str);
+		constexpr FixedStringT(const StringView& _str);
 
 
 		///
 		///
-		~FixedStringT();
+		constexpr ~FixedStringT();
 
 
 		///
 		///
-		void set(const char* _str);
+		constexpr void set(const char* _str);
 
 
 		///
 		///
-		void set(const StringView& _str);
+		constexpr void set(const StringView& _str);
 
 
 		///
 		///
-		void append(const StringView& _str);
+		constexpr void append(const StringView& _str);
 
 
 		///
 		///
-		void clear();
+		constexpr void clear();
 
 
 		/// Returns `true` if string is empty.
 		/// Returns `true` if string is empty.
 		///
 		///
-		bool isEmpty() const;
+		constexpr bool isEmpty() const;
 
 
 		/// Returns string length.
 		/// Returns string length.
 		///
 		///
-		int32_t getLength() const;
+		constexpr int32_t getLength() const;
 
 
 		/// Returns zero-terminated C string pointer.
 		/// Returns zero-terminated C string pointer.
 		///
 		///
-		const char* getCPtr() const;
+		constexpr const char* getCPtr() const;
 
 
 		/// Implicitly converts FixedStringT to StringView.
 		/// Implicitly converts FixedStringT to StringView.
 		///
 		///
-		operator StringView() const;
+		constexpr operator StringView() const;
 
 
 	private:
 	private:
 		char    m_storage[MaxCapacityT];
 		char    m_storage[MaxCapacityT];
@@ -342,10 +342,10 @@ namespace bx
 	int32_t strCmpV(const StringView& _lhs, const StringView& _rhs, int32_t _max = INT32_MAX);
 	int32_t strCmpV(const StringView& _lhs, const StringView& _rhs, int32_t _max = INT32_MAX);
 
 
 	/// Get string length.
 	/// Get string length.
-	int32_t strLen(const char* _str, int32_t _max = INT32_MAX);
+	constexpr int32_t strLen(const char* _str, int32_t _max = INT32_MAX);
 
 
 	/// Get string length.
 	/// Get string length.
-	int32_t strLen(const StringView& _str, int32_t _max = INT32_MAX);
+	constexpr int32_t strLen(const StringView& _str, int32_t _max = INT32_MAX);
 
 
 	/// Copy _num characters from string _src to _dst buffer of maximum _dstSize capacity
 	/// Copy _num characters from string _src to _dst buffer of maximum _dstSize capacity
 	/// including zero terminator. Copy will be terminated with '\0'.
 	/// including zero terminator. Copy will be terminated with '\0'.
@@ -480,12 +480,36 @@ namespace bx
 	/// Converts string to double value.
 	/// Converts string to double value.
 	bool fromString(double* _out, const StringView& _str);
 	bool fromString(double* _out, const StringView& _str);
 
 
+	/// Converts string to 8-bit integer value.
+	bool fromString(int8_t* _out, const StringView& _str);
+
+	/// Converts string to 8-bit unsigned integer value.
+	bool fromString(uint8_t* _out, const StringView& _str);
+
+	/// Converts string to 8-bit integer value.
+	bool fromString(int16_t* _out, const StringView& _str);
+
+	/// Converts string to 8-bit unsigned integer value.
+	bool fromString(uint16_t* _out, const StringView& _str);
+
 	/// Converts string to 32-bit integer value.
 	/// Converts string to 32-bit integer value.
 	bool fromString(int32_t* _out, const StringView& _str);
 	bool fromString(int32_t* _out, const StringView& _str);
 
 
 	/// Converts string to 32-bit unsigned integer value.
 	/// Converts string to 32-bit unsigned integer value.
 	bool fromString(uint32_t* _out, const StringView& _str);
 	bool fromString(uint32_t* _out, const StringView& _str);
 
 
+	/// Converts string to
+	bool fromString(long* _out, const StringView& _str);
+
+	/// Converts string to
+	bool fromString(unsigned long* _out, const StringView& _str);
+
+	/// Converts string to 64-bit long long value.
+	bool fromString(long long* _out, const StringView& _str);
+
+	/// Converts string to 64-bit unsigned long long value.
+	bool fromString(unsigned long long* _out, const StringView& _str);
+
 	///
 	///
 	class LineReader
 	class LineReader
 	{
 	{

+ 2 - 8
src/dtoa.cpp

@@ -1093,7 +1093,7 @@ namespace bx
 		return true;
 		return true;
 	}
 	}
 
 
-	bool fromString(int32_t* _out, const StringView& _str)
+	bool fromString(long long* _out, const StringView& _str)
 	{
 	{
 		StringView str = strLTrimSpace(_str);
 		StringView str = strLTrimSpace(_str);
 
 
@@ -1113,7 +1113,7 @@ namespace bx
 			break;
 			break;
 		}
 		}
 
 
-		int32_t result = 0;
+		long long result = 0;
 
 
 		for (ch = *ptr++; isNumeric(ch) && ptr <= term; ch = *ptr++)
 		for (ch = *ptr++; isNumeric(ch) && ptr <= term; ch = *ptr++)
 		{
 		{
@@ -1125,10 +1125,4 @@ namespace bx
 		return true;
 		return true;
 	}
 	}
 
 
-	bool fromString(uint32_t* _out, const StringView& _str)
-	{
-		fromString( (int32_t*)_out, _str);
-		return true;
-	}
-
 } // namespace bx
 } // namespace bx

+ 1 - 13
src/string.cpp

@@ -165,7 +165,7 @@ namespace bx
 
 
 	typedef char (*CharFn)(char _ch);
 	typedef char (*CharFn)(char _ch);
 
 
-	inline char toNoop(char _ch)
+	inline constexpr char toNoop(char _ch)
 	{
 	{
 		return _ch;
 		return _ch;
 	}
 	}
@@ -290,18 +290,6 @@ namespace bx
 			);
 			);
 	}
 	}
 
 
-	int32_t strLen(const char* _str, int32_t _max)
-	{
-		if (NULL == _str)
-		{
-			return 0;
-		}
-
-		const char* ptr = _str;
-		for (; 0 < _max && *ptr != '\0'; ++ptr, --_max) {};
-		return int32_t(ptr - _str);
-	}
-
 	inline int32_t strCopy(char* _dst, int32_t _dstSize, const char* _src, int32_t _num)
 	inline int32_t strCopy(char* _dst, int32_t _dstSize, const char* _src, int32_t _num)
 	{
 	{
 		BX_ASSERT(NULL != _dst, "_dst can't be NULL!");
 		BX_ASSERT(NULL != _dst, "_dst can't be NULL!");

+ 41 - 35
tests/string_test.cpp

@@ -13,41 +13,6 @@
 
 
 bx::AllocatorI* g_allocator;
 bx::AllocatorI* g_allocator;
 
 
-TEST_CASE("StringLiteral", "[string]")
-{
-	constexpr bx::StringLiteral tmp[] = { "1389", "abvgd", "mac", "pod" };
-
-	REQUIRE(bx::isSorted(tmp, BX_COUNTOF(tmp) ) );
-
-	STATIC_REQUIRE(4 == tmp[0].getLength() );
-	REQUIRE(4 == bx::strLen(tmp[0]) );
-	REQUIRE(0 == bx::strCmp("1389", tmp[0]) );
-
-	STATIC_REQUIRE(5 == tmp[1].getLength() );
-	REQUIRE(5 == bx::strLen(tmp[1]) );
-	REQUIRE(0 == bx::strCmp("abvgd", tmp[1]) );
-
-	STATIC_REQUIRE(3 == tmp[2].getLength() );
-	REQUIRE(3 == bx::strLen(tmp[2]) );
-	REQUIRE(0 == bx::strCmp("mac", tmp[2]) );
-
-	STATIC_REQUIRE(3 == tmp[3].getLength() );
-	REQUIRE(3 == bx::strLen(tmp[3]) );
-	REQUIRE(0 == bx::strCmp("pod", tmp[3]) );
-
-	constexpr bx::StringLiteral copy(tmp[0]);
-
-	STATIC_REQUIRE(4 == copy.getLength() );
-	REQUIRE(4 == bx::strLen(copy) );
-	REQUIRE(0 == bx::strCmp("1389", copy) );
-
-	constexpr bx::StringView sv(tmp[1]);
-
-	REQUIRE(5 == sv.getLength() );
-	REQUIRE(5 == bx::strLen(sv) );
-	REQUIRE("abvgd" == sv);
-}
-
 TEST_CASE("stringPrintfTy", "[string]")
 TEST_CASE("stringPrintfTy", "[string]")
 {
 {
 	std::string test;
 	std::string test;
@@ -492,6 +457,47 @@ TEST_CASE("fromString int32_t", "[string]")
 	REQUIRE(testFromString(-21,    "-021") );
 	REQUIRE(testFromString(-21,    "-021") );
 }
 }
 
 
+TEST_CASE("StringLiteral", "[string]")
+{
+	constexpr bx::StringLiteral tmp[] = { "1389", "abvgd", "mac", "pod" };
+
+	REQUIRE(bx::isSorted(tmp, BX_COUNTOF(tmp) ) );
+
+	STATIC_REQUIRE(4 == tmp[0].getLength() );
+	STATIC_REQUIRE(4 == bx::strLen(tmp[0]) );
+	REQUIRE(0 == bx::strCmp("1389", tmp[0]) );
+
+	STATIC_REQUIRE(5 == tmp[1].getLength() );
+	STATIC_REQUIRE(5 == bx::strLen(tmp[1]) );
+	REQUIRE(0 == bx::strCmp("abvgd", tmp[1]) );
+
+	STATIC_REQUIRE(3 == tmp[2].getLength() );
+	STATIC_REQUIRE(3 == bx::strLen(tmp[2]) );
+	REQUIRE(0 == bx::strCmp("mac", tmp[2]) );
+
+	STATIC_REQUIRE(3 == tmp[3].getLength() );
+	STATIC_REQUIRE(3 == bx::strLen(tmp[3]) );
+	REQUIRE(0 == bx::strCmp("pod", tmp[3]) );
+
+	constexpr bx::StringLiteral copy(tmp[0]);
+	STATIC_REQUIRE(4 == copy.getLength() );
+	REQUIRE(4 == bx::strLen(copy) );
+	REQUIRE(0 == bx::strCmp("1389", copy) );
+
+	constexpr bx::StringView sv(tmp[1]);
+	STATIC_REQUIRE(5 == sv.getLength() );
+	STATIC_REQUIRE(5 == bx::strLen(sv) );
+	STATIC_REQUIRE("abvgd" == sv);
+}
+
+TEST_CASE("StringView constexpr", "[string]")
+{
+	constexpr bx::StringView sv("1389");
+
+	STATIC_REQUIRE(sv == "1389");
+	STATIC_REQUIRE(4  == bx::strLen(sv) );
+}
+
 TEST_CASE("StringView", "[string]")
 TEST_CASE("StringView", "[string]")
 {
 {
 	bx::StringView sv("test");
 	bx::StringView sv("test");