summaryrefslogblamecommitdiffstatshomepage
path: root/src/lib/netlist/plib/pstring.h
blob: ced1cdc1f22e7b6126896735319fc7ee145ac6e3 (plain) (tree)
1
2
3
4
5
6
7
8
9





                               

                  
 
                   
                    
                 
 
                                                                                           
                                      
  

                                                                                 

                                                                                           



































                                                                                                                                       

                     

       
                              
 

                                                    


                                                              



                                  




                                                                           





                                                                                  
 

                  

                     

          
                                          
                   


                    
         
         
 
                                            






                                                                            
         

         

                                                                                           

                                 
                                                                      

                                               
                                            

         



                                          



                                                                      





                                       









                                                                                                       
         
 
                                                                                             
 









                                                                                                       
                                              

                                                                 
 





                                                                               
 
                                      

                                                                                           
 


                                                                    

                                                                       
                                                  





                                                                           
 
                                  
                                                                                                    
                                                                                              
                                                                                                                
                                                                                                            
 
                               






                                                                                         
 
                                                                                                                                          
 

                                                            
                                                                                     
 

                                                                                                                                                                                      
 


                                                                                       
 
                      
 

                                                      
 
                                                      
 

                                                             


                                                                      
                                                                                
         
 



                                                                         
 


                                                                         
                                                                  
         
 
                                                                                                              
 
                                                                       
 
                                
 

                                                               
                                                                 

          
                          

        



                 

                            



                                                                         
                                                         
                                                                                          
                                                                                            




                                                 
                           
                                

                                                    
         
                                    
                                       
                 
                                                  
                                      


                           
                                                  
         
                                                                                     












                                                
                                                  






                                     
                                           



                                                 
                                                                                     
                                         
                                   
                                              
                                                                                           
                                              
                                                                                                                           
                                              
                                                                                                                                                     


                                                  
                                                          
         

                               
                                                   


                                   

                                                                   


                                     


                                                                        
                 
                                           
                 



                                                                         

                 
                                                                        

                                    
                                  




                                          
 











                                                          
                                                                 






                                                      

                                                        









                                                  






                                                                          



                                                       










                                                                     























                                                                        
                                                                         












                                                              

                                                                
















                                                                






                                                                                  




































                                                                             

                                               

                                                
 
                                        
















                                                                     
 


                                                                      
                                                      
         
                                                   


                                                                    
                                                                 

                                                                               
                                                                                                                        


                                      

 
                       
// license:GPL-2.0+
// copyright-holders:Couriersud
/*
 * pstring.h
 */

#ifndef PSTRING_H_
#define PSTRING_H_

#include <iterator>
#include <exception>
#include <string>

// ----------------------------------------------------------------------------------------
// pstring: semi-immutable strings ...
//
// The only reason this class exists is the absence of support for multi-byte
// strings in std:: which I would consider usuable for the use-cases I encounter.
// ----------------------------------------------------------------------------------------

template <typename T>
class pstring_const_iterator final
{
public:

	typedef typename T::ref_value_type value_type;

	typedef value_type const *pointer;
	typedef value_type const &reference;
	typedef std::ptrdiff_t difference_type;
	typedef std::forward_iterator_tag iterator_category;
	typedef typename T::string_type string_type;
	typedef typename T::traits_type traits_type;

	pstring_const_iterator() noexcept : p() { }
	explicit constexpr pstring_const_iterator(const typename string_type::const_iterator &x) noexcept : p(x) { }
	pstring_const_iterator(const pstring_const_iterator &rhs) noexcept = default;
	pstring_const_iterator(pstring_const_iterator &&rhs) noexcept = default;
	pstring_const_iterator &operator=(const pstring_const_iterator &rhs) noexcept = default;
	pstring_const_iterator &operator=(pstring_const_iterator &&rhs) noexcept = default;

	pstring_const_iterator& operator++() noexcept { p += static_cast<difference_type>(traits_type::codelen(&(*p))); return *this; }
	pstring_const_iterator operator++(int) noexcept { pstring_const_iterator tmp(*this); operator++(); return tmp; }

	bool operator==(const pstring_const_iterator& rhs) const noexcept { return p == rhs.p; }
	bool operator!=(const pstring_const_iterator& rhs) const noexcept { return p != rhs.p; }

	reference operator*() const noexcept { return *reinterpret_cast<pointer>(&(*p)); }
	pointer operator->() const noexcept { return reinterpret_cast<pointer>(&(*p)); }

private:
	template <typename G> friend struct pstring_t;
	typename string_type::const_iterator p;
};


template <typename F>
struct pstring_t
{
public:
	typedef F traits_type;

	typedef typename traits_type::mem_t mem_t;
	typedef typename traits_type::code_t code_t;
	typedef std::size_t     size_type;
	typedef std::ptrdiff_t difference_type;
	typedef typename traits_type::string_type string_type;

	class ref_value_type final
	{
	public:
		ref_value_type() = delete;
		ref_value_type(const ref_value_type &) = delete;
		ref_value_type(ref_value_type &&) = delete;
		ref_value_type &operator=(const ref_value_type &) = delete;
		ref_value_type &operator=(ref_value_type &&) = delete;
		operator code_t() const noexcept { return traits_type::code(&m); }
	private:
		const mem_t m;
	};
	typedef const ref_value_type& const_reference ;
	typedef const_reference reference;

	enum enc_t
	{
		UTF8,
		UTF16
	};

	// simple construction/destruction
	pstring_t()
	{
	}
	~pstring_t()
	{
	}

	// FIXME: Do something with encoding
	pstring_t(const mem_t *string, const enc_t enc)
	: m_str(string)
	{
	}

	pstring_t(const mem_t *string, const size_type len, const enc_t enc)
	: m_str(string, len)
	{
	}

	template<typename C, std::size_t N,
		class = typename std::enable_if<std::is_same<C, const mem_t>::value>::type>
	pstring_t(C (&string)[N])
	{
		static_assert(N > 0,"pstring from array of length 0");
		if (string[N-1] != 0)
			throw std::exception();
		m_str.assign(string, N - 1);
	}

	pstring_t(const pstring_t &string)
	: m_str(string.m_str)
	{ }

	explicit pstring_t(const string_type &string, const enc_t enc)
		: m_str(string)
	{ }

	pstring_t(pstring_t &&string)
	: m_str(string.m_str)
	{  }

	explicit pstring_t(code_t code)
	{
		*this += code;
	}

	template <typename T,
		class = typename std::enable_if<!std::is_same<T, pstring_t::traits_type>::value>::type>
	explicit pstring_t(const pstring_t<T> &string)
	{
		m_str.clear();
		for (auto &c : string)
			*this += static_cast<code_t>(c); // FIXME: codepage conversion for u8
	}

	pstring_t &operator=(const pstring_t &string) { m_str = string.m_str; return *this; }

	template <typename T,
		class = typename std::enable_if<!std::is_same<T, pstring_t::traits_type>::value>::type>
	pstring_t &operator=(const pstring_t<T> &string)
	{
		m_str.clear();
		for (auto &c : string)
			*this += c;
		return *this;
	}

	// no non-const const_iterator for now
	typedef pstring_const_iterator<pstring_t> iterator;
	typedef pstring_const_iterator<pstring_t> const_iterator;

	iterator begin() { return iterator(m_str.begin()); }
	iterator end() { return iterator(m_str.end()); }
	const_iterator begin() const { return const_iterator(m_str.begin()); }
	const_iterator end() const { return const_iterator(m_str.end()); }
	const_iterator cbegin() const { return const_iterator(m_str.begin()); }
	const_iterator cend() const { return const_iterator(m_str.end()); }

	// C string conversion helpers
	const mem_t *c_str() const  {   return static_cast<const mem_t *>(m_str.c_str()); }
	const mem_t *data() const  {    return c_str(); }

	size_type length() const { return traits_type::len(m_str); }
	size_type size() const { return traits_type::len(m_str); }
	bool empty() const { return m_str.size() == 0; }

	pstring_t substr(size_type start, size_type nlen = npos) const;
	int compare(const pstring_t &right) const;

	size_type find(const pstring_t &search, size_type start = 0) const;
	size_type find(code_t search, size_type start = 0) const;

	size_type find_first_not_of(const pstring_t &no) const;
	size_type find_last_not_of(const pstring_t &no) const;

	// concatenation operators
	pstring_t& operator+=(const pstring_t &string) { m_str.append(string.m_str); return *this; }
	pstring_t& operator+=(const code_t c) { traits_type::encode(c, m_str); return *this; }
	friend pstring_t operator+(const pstring_t &lhs, const pstring_t &rhs) { return pstring_t(lhs) += rhs; }
	friend pstring_t operator+(const pstring_t &lhs, const code_t rhs) { return pstring_t(lhs) += rhs; }

	// comparison operators
	bool operator==(const pstring_t &string) const { return (compare(string) == 0); }
	bool operator!=(const pstring_t &string) const { return (compare(string) != 0); }

	bool operator<(const pstring_t &string) const { return (compare(string) < 0); }
	bool operator<=(const pstring_t &string) const { return (compare(string) <= 0); }
	bool operator>(const pstring_t &string) const { return (compare(string) > 0); }
	bool operator>=(const pstring_t &string) const { return (compare(string) >= 0); }

	const_reference at(const size_type pos) const { return *reinterpret_cast<const ref_value_type *>(F::nthcode(m_str.c_str(),pos)); }

	/* The following is not compatible to std::string */

	bool equals(const pstring_t &string) const { return (compare(string) == 0); }

	bool startsWith(const pstring_t &arg) const { return arg.mem_t_size() > mem_t_size() ? false : m_str.compare(0, arg.mem_t_size(), arg.m_str) == 0; }
	bool endsWith(const pstring_t &arg) const { return arg.mem_t_size() > mem_t_size() ? false : m_str.compare(mem_t_size()-arg.mem_t_size(), arg.mem_t_size(), arg.m_str) == 0; }

	pstring_t replace_all(const pstring_t &search, const pstring_t &replace) const;
	pstring_t cat(const pstring_t &s) const { return *this + s; }
	pstring_t cat(code_t c) const { return *this + c; }

	// conversions

	double as_double(bool *error = nullptr) const;
	long as_long(bool *error = nullptr) const;

	/* the following are extensions to <string> */

	size_type mem_t_size() const { return m_str.size(); }

	pstring_t left(size_type len) const { return substr(0, len); }
	pstring_t right(size_type nlen) const
	{
		return nlen >= length() ? *this : substr(length() - nlen, nlen);
	}

	pstring_t ltrim(const pstring_t &ws = pstring_t(" \t\n\r")) const
	{
		return substr(find_first_not_of(ws));
	}

	pstring_t rtrim(const pstring_t &ws = pstring_t(" \t\n\r")) const
	{
		auto f = find_last_not_of(ws);
		return f == npos ? pstring_t() : substr(0, f + 1);
	}

	pstring_t trim(const pstring_t &ws = pstring_t(" \t\n\r")) const { return this->ltrim(ws).rtrim(ws); }

	pstring_t rpad(const pstring_t &ws, const size_type cnt) const;

	pstring_t ucase() const;

	const string_type &cpp_string() const { return m_str; }

	static const size_type npos = static_cast<size_type>(-1);

protected:
	string_type m_str;

private:
};

struct pu8_traits
{
	typedef char mem_t;
	typedef char code_t;
	typedef std::string string_type;
	static std::size_t len(const string_type &p) { return p.size(); }
	static std::size_t codelen(const mem_t *p) { return 1; }
	static std::size_t codelen(const code_t c) { return 1; }
	static code_t code(const mem_t *p) { return *p; }
	static void encode(const code_t c, string_type &s) { s += static_cast<mem_t>(c); }
	static const mem_t *nthcode(const mem_t *p, const std::size_t n) { return &(p[n]); }
};

/* No checking, this may deliver invalid codes */
struct putf8_traits
{
	typedef char mem_t;
	typedef char32_t code_t;
	typedef std::string string_type;
	static std::size_t len(const string_type &p)
	{
		std::size_t ret = 0;
		for (const auto &c : p)
		{
			if (!((c & 0xC0) == 0x80))
				ret++;
		}
		return ret;
	}
	static std::size_t codelen(const mem_t *p)
	{
		const unsigned char *p1 = reinterpret_cast<const unsigned char *>(p);
		if ((*p1 & 0x80) == 0x00)
			return 1;
		else if ((*p1 & 0xE0) == 0xC0)
			return 2;
		else if ((*p1 & 0xF0) == 0xE0)
			return 3;
		else if ((*p1 & 0xF8) == 0xF0)
			return 4;
		else
		{
			return 1; // not correct
		}
	}
	static std::size_t codelen(const code_t c)
	{
		if (c < 0x0080)
			return 1;
		else if (c < 0x800)
			return 2;
		else if (c < 0x10000)
			return 3;
		else /* U+10000 U+1FFFFF */
			return 4; /* no checks */
	}
	static code_t code(const mem_t *p)
	{
		const unsigned char *p1 = reinterpret_cast<const unsigned char *>(p);
		if ((*p1 & 0x80) == 0x00)
			return *p1;
		else if ((*p1 & 0xE0) == 0xC0)
			return static_cast<code_t>(((p1[0] & 0x3f) << 6) | (p1[1] & 0x3f));
		else if ((*p1 & 0xF0) == 0xE0)
			return static_cast<code_t>(((p1[0] & 0x1f) << 12) | ((p1[1] & 0x3f) << 6) | ((p1[2] & 0x3f) << 0));
		else if ((*p1 & 0xF8) == 0xF0)
			return static_cast<code_t>(((p1[0] & 0x0f) << 18) | ((p1[1] & 0x3f) << 12) | ((p1[2] & 0x3f) << 6)  | ((p1[3] & 0x3f) << 0));
		else
			return *p1; // not correct
	}
	static void encode(const code_t c, string_type &s)
	{
		if (c < 0x0080)
		{
			s += static_cast<mem_t>(c);
		}
		else if (c < 0x800)
		{
			s += static_cast<mem_t>(0xC0 | (c >> 6));
			s += static_cast<mem_t>(0x80 | (c & 0x3f));
		}
		else if (c < 0x10000)
		{
			s += static_cast<mem_t>(0xE0 | (c >> 12));
			s += static_cast<mem_t>(0x80 | ((c>>6) & 0x3f));
			s += static_cast<mem_t>(0x80 | (c & 0x3f));
		}
		else /* U+10000 U+1FFFFF */
		{
			s += static_cast<mem_t>(0xF0 | (c >> 18));
			s += static_cast<mem_t>(0x80 | ((c>>12) & 0x3f));
			s += static_cast<mem_t>(0x80 | ((c>>6) & 0x3f));
			s += static_cast<mem_t>(0x80 | (c & 0x3f));
		}
	}
	static const mem_t *nthcode(const mem_t *p, const std::size_t n)
	{
		const mem_t *p1 = p;
		std::size_t i = n;
		while (i-- > 0)
			p1 += codelen(p1);
		return p1;
	}
};

struct putf16_traits
{
	typedef char16_t mem_t;
	typedef char32_t code_t;
	typedef std::u16string string_type;
	static std::size_t len(const string_type &p)
	{
		std::size_t ret = 0;
		auto i = p.begin();
		while (i != p.end())
		{
			// FIXME: check that size is equal
			uint16_t c = static_cast<uint16_t>(*i++);
			if (!((c & 0xd800) == 0xd800))
				ret++;
		}
		return ret;
	}
	static std::size_t codelen(const mem_t *p)
	{
		uint16_t c = static_cast<uint16_t>(*p);
		return ((c & 0xd800) == 0xd800) ? 2 : 1;
	}
	static std::size_t codelen(const code_t c)
	{
		if (c < 0x10000)
			return 1;
		else /* U+10000 U+1FFFFF */
			return 2;
	}
	static code_t code(const mem_t *p)
	{
		uint32_t c = static_cast<uint32_t>(*p++);
		if ((c & 0xd800) == 0xd800)
		{
			c = (c - 0xd800) << 10;
			c += static_cast<uint32_t>(*p) - 0xdc00 + 0x10000;
		}
		return static_cast<code_t>(c);
	}
	static void encode(code_t c, string_type &s)
	{
		uint32_t cu = static_cast<uint32_t>(c);
		if (c > 0xffff)
		{ //make a surrogate pair
			uint32_t t = ((cu - 0x10000) >> 10) + 0xd800;
			cu = (cu & 0x3ff) + 0xdc00;
			s += static_cast<mem_t>(t);
			s += static_cast<mem_t>(cu);
		}
		else
		{
			s += static_cast<mem_t>(cu);
		}
	}
	static const mem_t *nthcode(const mem_t *p, const std::size_t n)
	{
		std::size_t i = n;
		while (i-- > 0)
			p += codelen(p);
		return p;
	}
};

struct pwchar_traits
{
	typedef wchar_t mem_t;
	typedef char32_t code_t;
	typedef std::wstring string_type;
	static std::size_t len(const string_type &p)
	{
		if (sizeof(wchar_t) == 2)
		{
			std::size_t ret = 0;
			auto i = p.begin();
			while (i != p.end())
			{
				// FIXME: check that size is equal
				uint32_t c = static_cast<uint32_t>(*i++);
				if (!((c & 0xd800) == 0xd800))
					ret++;
			}
			return ret;
		}
		else
			return p.size();
	}

	static std::size_t codelen(const mem_t *p)
	{
		if (sizeof(wchar_t) == 2)
		{
			uint16_t c = static_cast<uint16_t>(*p);
			return ((c & 0xd800) == 0xd800) ? 2 : 1;
		}
		else
			return 1;
	}

	static std::size_t codelen(const code_t c)
	{
		if (sizeof(wchar_t) == 2)
			return ((c & 0xd800) == 0xd800) ? 2 : 1;
		else
			return 1;
	}

	static code_t code(const mem_t *p)
	{
		if (sizeof(wchar_t) == 2)
		{
			uint32_t c = static_cast<uint32_t>(*p++);
			if ((c & 0xd800) == 0xd800)
			{
				c = (c - 0xd800) << 10;
				c += static_cast<uint32_t>(*p) - 0xdc00 + 0x10000;
			}
			return static_cast<code_t>(c);
		}
		else
			return static_cast<code_t>(*p);
	}

	static void encode(code_t c, string_type &s)
	{
		if (sizeof(wchar_t) == 2)
		{
			uint32_t cu = static_cast<uint32_t>(c);
			if (c > 0xffff)
			{ //make a surrogate pair
				uint32_t t = ((cu - 0x10000) >> 10) + 0xd800;
				cu = (cu & 0x3ff) + 0xdc00;
				s += static_cast<mem_t>(t);
				s += static_cast<mem_t>(cu);
			}
			else
				s += static_cast<mem_t>(cu);
		}
		else
			s += static_cast<wchar_t>(c);
	}
	static const mem_t *nthcode(const mem_t *p, const std::size_t n)
	{
		if (sizeof(wchar_t) == 2)
		{
			std::size_t i = n;
			while (i-- > 0)
				p += codelen(p);
			return p;
		}
		else
			return p + n;
	}
};

extern template struct pstring_t<pu8_traits>;
extern template struct pstring_t<putf8_traits>;
extern template struct pstring_t<putf16_traits>;
extern template struct pstring_t<pwchar_traits>;

typedef pstring_t<putf8_traits> pstring;
typedef pstring_t<putf16_traits> pu16string;
typedef pstring_t<pwchar_traits> pwstring;

namespace plib
{
	template<typename T>
	pstring to_string(const T &v)
	{
		return pstring(std::to_string(v), pstring::UTF8);
	}

	template<typename T>
	pwstring to_wstring(const T &v)
	{
		return pwstring(std::to_wstring(v), pwstring::UTF16);
	}
}

// custom specialization of std::hash can be injected in namespace std
namespace std
{
	template<typename T> struct hash<pstring_t<T>>
	{
		typedef pstring_t<T> argument_type;
		typedef std::size_t result_type;
		result_type operator()(argument_type const& s) const
		{
			const pstring::mem_t *string = s.c_str();
			result_type result = 5381;
			for (pstring::mem_t c = *string; c != 0; c = *string++)
				result = ((result << 5) + result ) ^ (result >> (32 - 5)) ^ static_cast<result_type>(c);
			return result;
		}
	};
}

#endif /* PSTRING_H_ */