#ifndef OPAQUE_EXPERIMENTAL_SAFER_STRING_TYPEDEF_HPP #define OPAQUE_EXPERIMENTAL_SAFER_STRING_TYPEDEF_HPP // // Copyright (c) 2016 // Kyle Markley. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // 2. Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // 3. Neither the name of the author nor the names of any contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. // #include "../data.hpp" #include #include namespace opaque { namespace experimental { /// \addtogroup typedefs /// @{ /// /// Safer string opaque typedef base type /// /// This is an opaque typedef base class for standard strings, but without /// interoperability with character arrays in ways that would modify the /// opaque object or create new opaque object instances. /// /// Template arguments: /// -# S : The string type (e.g. std::string) /// -# R : The result type, your subclass /// template struct safer_string_typedef : data { private: using base = opaque::data; public: using typename base::underlying_type; using typename base::opaque_type; using base::value; typedef typename S::traits_type traits_type; typedef typename S::value_type value_type; typedef typename S::allocator_type allocator_type; typedef typename S::size_type size_type; typedef typename S::difference_type difference_type; typedef typename S::reference reference; typedef typename S::const_reference const_reference; typedef typename S::pointer pointer; typedef typename S::const_pointer const_pointer; typedef typename S::iterator iterator; typedef typename S::const_iterator const_iterator; typedef typename S::reverse_iterator reverse_iterator; typedef typename S::const_reverse_iterator const_reverse_iterator; static const size_type npos = size_type(0)-size_type(1); private: typedef allocator_type Allocator; typedef typename std::allocator_traits::value_type charT; public: // // Constructor philosophy // // 1) Provide for explicit construction from an instance of underlying_type. // // 2) Constructors that have an argument of underlying_type are provided in // in two flavors: an explicit one taking underlying_type, and one taking // opaque_type that has the explicitness of the original. // // 3) Constructors that do not have an argument of underlying_type are made // explicit. // explicit safer_string_typedef(const underlying_type& str) noexcept : base(str) { } explicit safer_string_typedef( underlying_type&& str) noexcept : base(std::move(str)) { } // // The default constructor has the C++14 interface; a zero-argument // form (defaulted below) and a single-argument form taking an Allocator. // explicit safer_string_typedef(const Allocator& a) : base(a) { } explicit safer_string_typedef(const underlying_type& str, size_type pos, size_type n = npos, const Allocator& a = Allocator()) : base(str.value, pos, n, a) { } safer_string_typedef(const opaque_type& str, size_type pos, size_type n = npos, const Allocator& a = Allocator()) : base(str.value, pos, n, a) { } explicit safer_string_typedef(const charT* s, size_type n, const Allocator& a = Allocator()) : base(s, n, a) { } explicit safer_string_typedef(const charT* s, const Allocator& a = Allocator()) : base(s, a) { } explicit safer_string_typedef(size_type n, charT c, const Allocator& a = Allocator()) : base(n, c, a) { } template explicit safer_string_typedef(InputIterator Begin, InputIterator End, const Allocator& a = Allocator()) : base(Begin, End, a) { } explicit safer_string_typedef(std::initializer_list il, const Allocator& a = Allocator()) : base(il, a) { } explicit safer_string_typedef(const underlying_type& str, const Allocator& a) : base(str.value, a) { } explicit safer_string_typedef(underlying_type&& str, const Allocator& a) : base(std::move(str.value), a) { } safer_string_typedef(const opaque_type& str, const Allocator& a) : base(str.value, a) { } safer_string_typedef(opaque_type&& str, const Allocator& a) : base(std::move(str.value), a) { } // opaque_type& operator=(const charT* s); opaque_type& operator=(charT c) { value = c; return downcast(); } opaque_type& operator=(std::initializer_list il) { value = il; return downcast(); } iterator begin() noexcept { return value.begin() ; } const_iterator begin() const noexcept { return value.begin() ; } iterator end() noexcept { return value.end() ; } const_iterator end() const noexcept { return value.end() ; } reverse_iterator rbegin() noexcept { return value.rbegin() ; } const_reverse_iterator rbegin() const noexcept { return value.rbegin() ; } reverse_iterator rend() noexcept { return value.rend() ; } const_reverse_iterator rend() const noexcept { return value.rend() ; } const_iterator cbegin() const noexcept { return value.cbegin() ; } const_iterator cend() const noexcept { return value.cend() ; } const_reverse_iterator crbegin() const noexcept { return value.crbegin(); } const_reverse_iterator crend() const noexcept { return value.crend() ; } size_type size() const noexcept { return value.size(); } size_type length() const noexcept { return value.length(); } size_type max_size() const noexcept { return value.max_size(); } void resize(size_type n, charT c) { return value.resize(n, c); } void resize(size_type n) { return value.resize(n); } size_type capacity() const noexcept { return value.capacity(); } void reserve(size_type res_arg = 0) { return value.reserve(res_arg); } void shrink_to_fit() { return value.shrink_to_fit(); } void clear() noexcept { return value.clear(); } bool empty() const noexcept { return value.empty(); } const_reference operator[](size_type pos) const { return value[pos]; } reference operator[](size_type pos) { return value[pos]; } const_reference at(size_type n) const { return value.at(n); } reference at(size_type n) { return value.at(n); } const charT& front() const { return value.front(); } charT& front() { return value.front(); } const charT& back() const { return value.back(); } charT& back() { return value.back(); } opaque_type& operator+=(const opaque_type& str) { value += str.value; return downcast(); } // opaque_type& operator+=(const charT* s); opaque_type& operator+=(charT c) { value += c; return downcast(); } opaque_type& operator+=(std::initializer_list il) { value += il; return downcast(); } opaque_type& append(const opaque_type& str) { value.append(str.value); return downcast(); } // C++14 interface opaque_type& append(const opaque_type& str, size_type pos, size_type n = npos) { value.append(str.value, pos, n); return downcast(); } //opaque_type& append(const charT* s, size_type n); //opaque_type& append(const charT* s); opaque_type& append(size_type n, charT c) { value.append(n, c); return downcast(); } template opaque_type& append(InputIterator first, InputIterator last) { value.append(first, last); return downcast(); } opaque_type& append(std::initializer_list il) { value.append(il); return downcast(); } void push_back(charT c) { return value.push_back(c); } opaque_type& assign(const opaque_type& str) { value.assign(str.value); return downcast(); } opaque_type& assign(opaque_type&& str) noexcept { value.assign(std::move(str.value)); return downcast(); } // C++14 interface opaque_type& assign(const opaque_type& str, size_type pos, size_type n = npos) { value.assign(str.value, pos, n); return downcast(); } // opaque_type& assign(const charT* s, size_type n); // opaque_type& assign(const charT* s); opaque_type& assign(size_type n, charT c) { value.assign(n, c); return downcast(); } template opaque_type& assign(InputIterator first, InputIterator last) { value.assign(first, last); return downcast(); } opaque_type& assign(std::initializer_list il) { value.assign(il); return downcast(); } opaque_type& insert(size_type pos1, const opaque_type& str) { value.insert(pos1, str.value); return downcast(); } // C++14 interface opaque_type& insert(size_type pos1, const opaque_type& str, size_type pos2, size_type n = npos) { value.insert(pos1, str.value, pos2, n); return downcast(); } // opaque_type& insert(size_type pos, const charT* s, size_type n); // opaque_type& insert(size_type pos, const charT* s); opaque_type& insert(size_type pos, size_type n, charT c) { value.insert(pos, n, c); return downcast(); } // C++03 interface iterator insert(iterator p, charT c) { return insert(p, c); } // C++03 interface iterator insert(iterator p, size_type n, charT c) { return insert(p, n, c); } // C++03 interface template iterator insert(iterator p, InputIterator first, InputIterator last) { return insert(p, first, last); } iterator insert(const_iterator p, charT c) { return insert(p, c); } iterator insert(const_iterator p, size_type n, charT c) { return insert(p, n, c); } template iterator insert(const_iterator p, InputIterator first, InputIterator last) { return insert(p, first, last); } iterator insert(const_iterator p, std::initializer_list il) { return insert(p, il); } opaque_type& erase(size_type pos = 0, size_type n = npos) { value.erase(pos, n); return downcast(); } // C++03 interface iterator erase(iterator p) { return value.erase(p); } // C++03 interface iterator erase(iterator first, iterator last) { return value.erase(first, last); } iterator erase(const_iterator p) { return value.erase(p); } iterator erase(const_iterator first, const_iterator last) { return value.erase(first, last); } void pop_back() { return value.pop_back(); } opaque_type& replace(size_type pos1, size_type n1, const opaque_type& str) { value.replace(pos1, n1, str.value); return downcast(); } // C++14 interface opaque_type& replace(size_type pos1, size_type n1, const opaque_type& str, size_type pos2, size_type n2 = npos) { value.replace(pos1, n1, str.value, pos2, n2); return downcast(); } // opaque_type& replace(size_type pos, size_type n1, const charT* s, // size_type n2); // opaque_type& replace(size_type pos, size_type n1, const charT* s); opaque_type& replace(size_type pos, size_type n1, size_type n2, charT c) { value.replace(pos, n1, n2, c); return downcast(); } opaque_type& replace(const_iterator i1, const_iterator i2, const opaque_type& str) { value.replace(i1, i2, str.value); return downcast(); } opaque_type& replace(const_iterator i1, const_iterator i2, const charT* s, size_type n) { value.replace(i1, i2, s, n); return downcast(); } opaque_type& replace(const_iterator i1, const_iterator i2, const charT* s) { value.replace(i1, i2, s); return downcast(); } opaque_type& replace(const_iterator i1, const_iterator i2, size_type n, charT c) { value.replace(i1, i2, n, c); return downcast(); } template opaque_type& replace(const_iterator i1, const_iterator i2, InputIterator j1, InputIterator j2) { value.replace(i1, i2, j1, j2); return downcast(); } opaque_type& replace(const_iterator i1, const_iterator i2, std::initializer_list il) { value.replace(i1, i2, il); return downcast(); } size_type copy(charT* s, size_type n, size_type pos = 0) const { return value.copy(s, n, pos); } void swap(opaque_type& str) { return value.swap(str.value); } const charT* c_str() const noexcept { return value.c_str(); } const charT* data() const noexcept { return value.data(); } allocator_type get_allocator() const noexcept { return value.get_allocator(); } size_type find (const opaque_type& str, size_type pos = 0) const noexcept { return value.find(str.value, pos); } size_type find (const charT* s, size_type pos, size_type n) const { return value.find(s, pos, n); } size_type find (const charT* s, size_type pos = 0) const { return value.find(s, pos); } size_type find (charT c, size_type pos = 0) const noexcept { return value.find(c, pos); } size_type rfind(const opaque_type& str, size_type pos = npos) const noexcept { return value.rfind(str.value, pos); } size_type rfind(const charT* s, size_type pos, size_type n) const { return value.rfind(s, pos, n); } size_type rfind(const charT* s, size_type pos = npos) const { return value.rfind(s, pos); } size_type rfind(charT c, size_type pos = npos) const noexcept { return value.rfind(c, pos); } size_type find_first_of(const opaque_type& str, size_type pos = 0) const noexcept { return value.find_first_of(str.value, pos); } size_type find_first_of(const charT* s, size_type pos, size_type n) const { return value.find_first_of(s, pos, n); } size_type find_first_of(const charT* s, size_type pos = 0) const { return value.find_first_of(s, pos); } size_type find_first_of(charT c, size_type pos = 0) const noexcept { return value.find_first_of(c, pos); } size_type find_last_of (const opaque_type& str, size_type pos = npos) const noexcept { return value.find_last_of(str.value, pos); } size_type find_last_of (const charT* s, size_type pos, size_type n) const { return value.find_last_of(s, pos, n); } size_type find_last_of (const charT* s, size_type pos = npos) const { return value.find_last_of(s, pos); } size_type find_last_of (charT c, size_type pos = npos) const noexcept { return value.find_last_of(c, pos); } size_type find_first_not_of(const opaque_type& str, size_type pos = 0) const noexcept { return value.find_first_not_of(str.value, pos); } size_type find_first_not_of(const charT* s, size_type pos, size_type n) const { return value.find_first_not_of(s, pos, n); } size_type find_first_not_of(const charT* s, size_type pos = 0) const { return value.find_first_not_of(s, pos); } size_type find_first_not_of(charT c, size_type pos = 0) const noexcept { return value.find_first_not_of(c, pos); } size_type find_last_not_of (const opaque_type& str, size_type pos = npos) const noexcept { return value.find_last_not_of(str.value, pos); } size_type find_last_not_of (const charT* s, size_type pos, size_type n) const { return value.find_last_not_of(s, pos, n); } size_type find_last_not_of (const charT* s, size_type pos = npos) const { return value.find_last_not_of(s, pos); } size_type find_last_not_of (charT c, size_type pos = npos) const noexcept { return value.find_last_not_of(c, pos); } opaque_type substr(size_type pos = 0, size_type n = npos) const { return opaque_type(value.substr(pos, n)); } int compare(const opaque_type& str) const noexcept { return value.compare(str.value); } int compare(size_type pos1, size_type n1, const opaque_type& str) const { return value.compare(pos1, n1, str.value); } // C++14 interface int compare(size_type pos1, size_type n1, const opaque_type& str, size_type pos2, size_type n2 = npos) const { return value.compare(pos1, n1, str.value, pos2, n2); } int compare(const charT* s) const { return value.compare(s); } int compare(size_type pos1, size_type n1, const charT* s) const { return value.compare(pos1, n1, s); } int compare(size_type pos1, size_type n1, const charT* s, size_type n2) const { return value.compare(pos1, n1, s, n2); } friend opaque_type operator+(const opaque_type& l, const opaque_type& r) { return opaque_type( l.value + r.value ); } friend opaque_type operator+( opaque_type&& l, const opaque_type& r) { return opaque_type(std::move(l.value) + r.value ); } friend opaque_type operator+(const opaque_type& l, opaque_type&& r) { return opaque_type( l.value + std::move(r.value)); } friend opaque_type operator+( opaque_type&& l, opaque_type&& r) { return opaque_type(std::move(l.value) + std::move(r.value)); } // friend opaque_type operator+(const charT* lhs, const opaque_type& rhs); // friend opaque_type operator+(const charT* lhs, opaque_type&& rhs); friend opaque_type operator+( charT lhs, const opaque_type& rhs) { return lhs + rhs.value ; } friend opaque_type operator+( charT lhs, opaque_type&& rhs) { return lhs + std::move(rhs.value); } // friend opaque_type operator+(const opaque_type& lhs, const charT* rhs); // friend opaque_type operator+( opaque_type&& lhs, const charT* rhs); friend opaque_type operator+(const opaque_type& lhs, charT rhs) { return lhs.value + rhs; } friend opaque_type operator+( opaque_type&& lhs, charT rhs) { return std::move(lhs.value) + rhs; } friend bool operator==(const opaque_type& lhs, const opaque_type& rhs) { return lhs.value == rhs.value; } friend bool operator==(const charT* lhs, const opaque_type& rhs) { return lhs == rhs.value; } friend bool operator==(const opaque_type& lhs, const charT* rhs) { return lhs.value == rhs ; } friend bool operator!=(const opaque_type& lhs, const opaque_type& rhs) { return lhs.value != rhs.value; } friend bool operator!=(const charT* lhs, const opaque_type& rhs) { return lhs != rhs.value; } friend bool operator!=(const opaque_type& lhs, const charT* rhs) { return lhs.value != rhs ; } friend bool operator< (const opaque_type& lhs, const opaque_type& rhs) { return lhs.value < rhs.value; } friend bool operator< (const charT* lhs, const opaque_type& rhs) { return lhs < rhs.value; } friend bool operator< (const opaque_type& lhs, const charT* rhs) { return lhs.value < rhs ; } friend bool operator> (const opaque_type& lhs, const opaque_type& rhs) { return lhs.value > rhs.value; } friend bool operator> (const charT* lhs, const opaque_type& rhs) { return lhs > rhs.value; } friend bool operator> (const opaque_type& lhs, const charT* rhs) { return lhs.value > rhs ; } friend bool operator<=(const opaque_type& lhs, const opaque_type& rhs) { return lhs.value <= rhs.value; } friend bool operator<=(const charT* lhs, const opaque_type& rhs) { return lhs <= rhs.value; } friend bool operator<=(const opaque_type& lhs, const charT* rhs) { return lhs.value <= rhs ; } friend bool operator>=(const opaque_type& lhs, const opaque_type& rhs) { return lhs.value >= rhs.value; } friend bool operator>=(const charT* lhs, const opaque_type& rhs) { return lhs >= rhs.value; } friend bool operator>=(const opaque_type& lhs, const charT* rhs) { return lhs.value >= rhs ; } friend void swap(opaque_type& lhs, opaque_type& rhs) { using std::swap; return swap(lhs.value, rhs.value); } safer_string_typedef() = default; safer_string_typedef(const safer_string_typedef& ) = default; safer_string_typedef( safer_string_typedef&&) = default; safer_string_typedef& operator=(const safer_string_typedef& ) = default; safer_string_typedef& operator=( safer_string_typedef&&) = default; protected: ~safer_string_typedef() = default; using base::downcast; }; /// @} } } #endif