/* * Copyright 2019 by its authors. See AUTHORS. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _EINA_STRINGSHARE_HH #define _EINA_STRINGSHARE_HH #include #include #include #include #include /** * @addtogroup Eina_Cxx_Data_Types_Group * * @{ */ namespace efl { namespace eina { /** * @defgroup Eina_Cxx_Stringshare_Group Stringshare * @ingroup Eina_Cxx_Data_Types_Group * * C++ Binding to Eina_Stringshare. * * This class allows you to store a single copy of a string, and use in * multiple places throughout your program. * * This is a method to reduce the number of duplicated strings kept in * memory. It's pretty common for the same strings to be dynamically * allocated repeatedly between applications and libraries, especially in * circumstances where you could have multiple copies of a structure that * allocates the string. So rather than duplicating and freeing these * strings, you request a read-only pointer to an existing string and * only incur the overhead of a hash look-up. * * It sounds like micro-optimizing, but profiling has shown this can have * a significant impact as you scale the number of copies up. It improves * string creation/destruction speed, reduces memory use and decreases * memory fragmentation, so a win all-around. * * @{ */ /** * Type for stealing the ownership of a string that was previously shared. */ struct steal_stringshare_ref_t {}; /** * Constant instance of @c steal_stringshare_ref_t for quick reference. */ steal_stringshare_ref_t const steal_stringshare_ref = {}; /** * Stringshare class. It provides an OOP interface to the * @c Eina_Stringshare functions, and automatically take care of sharing * the string upon construction and deleting it upon destruction using * the RAII programming idiom. * * It also provides additional member functions to facilitate the access * to the string content, much like a STL string. */ struct stringshare { typedef char value_type; typedef value_type& reference; typedef value_type const& const_reference; typedef value_type* pointer; typedef value_type const* const_pointer; typedef const_pointer const_iterator; typedef std::reverse_iterator const_reverse_iterator; typedef std::ptrdiff_t difference_type; typedef std::size_t size_type; /** * @brief Default constructor. Creates a new object holding an shared empty string. * @see stringshare(const char* str) */ stringshare() : _string( ::eina_stringshare_add("") ) {} /** * @brief Share an instance of the given string wrapped by the newly created @c stringshare object. * @param NULL-terminated string to be shared. * * This constructor creates an eina::stringshare object that * shares the given string and wraps the shared pointer, providing an * OOP interface to the string content. If the string is already * shared this constructor simple increment its reference counter and * wraps the shared pointer. * * @see stringshare(const char* str, steal_stringshare_ref_t) */ stringshare(const char* str) : _string( ::eina_stringshare_add(str) ) { } /** * @brief Create an eina::stringshare that steal the ownership of the given shared string. * @param str Shared string whose ownership should be stolen. * * This constructor creates an eina::stringshare object that * steals the ownership of the given shared string. At destruction * time, the reference counter for the shared string will be * decremented. * * The second parameter is an empty object of a specific type that * should be supplied to explicitly inform that this is the intended * constructor; and to differentiate this from * @ref stringshare(const char* str). * * @warning @p str should be a string that was previously shared (most * likely by an call to the native @c eina_stringshare_add function). * If the string is not shared, upon destruction time bad things will * happen, likely a segmentation fault. * * @see stringshare(const char* str) */ stringshare(const char* str, steal_stringshare_ref_t) : _string( str ) { } /** * @brief Share the string between the iterator. * @param i Iterator to the initial position of the string (inclusive). * @param j Iterator to the final position of the string (exclusive). * @note The ending position (pointed by @p j) is not considered. * @see stringshare(const char* str) */ template stringshare(InputIterator i, InputIterator j , typename eina::enable_if ::value && !eina::is_contiguous_iterator::value >::type* = 0) { std::string tmp; while(i != j) { tmp.push_back(*i); ++i; } _string = ::eina_stringshare_add(tmp.c_str()); } /** * @brief Share the string between the iterator. * @param i Iterator to the initial position of the string (inclusive). * @param j Iterator to the final position of the string (exclusive). * @note The ending position (pointed by @p j) is not considered. * @see stringshare(const char* str) */ template stringshare(ContiguousMemoryIterator i, ContiguousMemoryIterator j , typename eina::enable_if ::value>::type* = 0) : _string( ::eina_stringshare_add_length(&*i, j - i) ) { } /** * @brief Destructor. Delete the shared string. * * Decreases the reference counter associated with the shared string. * If the reference counter reaches 0, the memory associated with the * string is freed. */ ~stringshare() { ::eina_stringshare_del(_string); } /** * @brief Copy constructor. Creates a new eina::stringshare associated with the same shared string. * @param other Another eina::stringshare. * * This constructor increments the reference counter to the shared * string associated with @p other. * * @see stringshare(const char* str) */ stringshare(stringshare const& other) : _string( eina_stringshare_ref(other._string) ) {} /** * @brief Replace the current shared string. * @param other Another eina::stringshare. * * This operator replaces the current shared string by the string * shared by @p other. The reference counter of the older shared * string is decremented (the string is released if needed) and the * reference counter of the given shared string is incremented. */ stringshare& operator=(stringshare const& other) { ::eina_stringshare_refplace(&_string, other._string); return *this; } /** * @brief Replace the current shared string. * @param c_string NULL-terminated string. * * This operator replaces the shared string currently associated with * this object by a shared instance of @p c_string. * * @see stringshare(const char* str) */ stringshare& operator=(const char* c_string) { ::eina_stringshare_replace(&_string, c_string); return *this; } /** * @brief Get a constant iterator pointing to the first character of the string. * @return Constant iterator to the initial position of the string. * * This member function returns a constant iterator pointing to the * first character of the string. If the string is empty the iterator * is equal to the one returned by @ref end() const. */ const_iterator begin() const { return _string; } /** * @brief Get a constant iterator to the position following the last character of the string. * @return Constant iterator to the final position of the string. * * This member function returns an constant iterator to the position * following the last character in the string. If the string is empty * the iterator is equal to the one returned by @ref begin(). * * @note Note that attempting to access this position causes undefined * behavior. */ const_iterator end() const { return _string + size(); } /** * @brief Get a constant reverse iterator pointing to the reverse begin of the string. * @return Constant reverse iterator pointing to the reverse begin of the string. * * This member function returns a constant reverse iterator pointing * to the last character of the string. If the string is empty the * returned reverse iterator is the same as the one returned by * @ref rend() const. */ const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } /** * @brief Get a constant reverse iterator pointing to the reverse end of the string. * @return Constant reverse iterator pointing to the reverse end of the string. * * This member function returns a constant reverse iterator pointing * to the position before the first character of the string. If the * string is empty the returned iterator is the same as the one * returned by @ref rbegin() const. * * @note Note that attempting to access this position causes undefined * behavior. */ const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } /** * @brief Get a constant iterator pointing to the first character of the string. * @return Constant iterator to the initial position of the string. * * This member function works just like @ref begin() const. But it is * granted to always return a constant iterator. */ const_iterator cbegin() const { return begin(); } /** * @brief Get a constant iterator to the position following the last character of the string. * @return Constant iterator to the final position of the string. * * This member function works just like @ref end() const. But it is * granted to always return a constant iterator. */ const_iterator cend() const { return end(); } /** * @brief Get a constant reverse iterator pointing to the reverse begin of the string. * @return Constant reverse iterator pointing to the reverse begin of the string. * * This member function works just like @ref rbegin() const. But it is * granted to always return a constant reverse iterator. */ const_reverse_iterator crbegin() const { return rbegin(); } /** * @brief Get a constant reverse iterator pointing to the reverse end of the string. * @return Constant reverse iterator pointing to the reverse end of the string. * * This member function works just like @ref rend() const. But it is * granted to always return a constant reverse iterator. */ const_reverse_iterator crend() const { return rend(); } /** * @brief Get the size of the string. * @return Number of characters in the string. */ size_type size() const { return eina_stringshare_strlen(_string); } /** * @brief Alias to @ref size() const. */ size_type length() const { return size(); } /** * @brief Get the maximum number of characters a string can hold. * @return Maximum number of characters a string can hold. */ size_type max_size() const { return -1; } /** * @brief Check if the string has no characters. * @return @c true if the string has no characters, @c false otherwise. */ bool empty() const { return _string[0] == 0; } /** * @brief Get the character at the given position. * @param i Position of the character in the string. * @return Constant reference to the character at the given position. * @note Do not check if the given position exceeds the string size. */ const_reference operator[](size_type i) const { return _string[i]; } /** * @brief Get the character at the given position. * @param i Position of the character in the string. * @return Constant reference to the character at the given position. * @throw std::out_of_range if the given position exceeds the string size. * * This member function returns a constant reference to the character * at the position @p i. If @p i exceeds the string size this function * will throw a std::out_of_range. */ const_reference at(size_type i) const { if(i < size()) return (*this)[i]; else EFL_CXX_THROW(std::out_of_range("")); } /** * @brief Get the last character of the string. * @return Constant reference to the last character of the string. */ const_reference back() const { return _string[size()-1]; } /** * @brief Get the first character of the string. * @return Constant reference to the first character of the string. */ const_reference front() const { return _string[0]; } /** * @brief Swap shared strings with other eina::stringshare. */ void swap(stringshare& other) { std::swap(_string, other._string); } /** * @brief Get the c-like shared string currently associated with the object. * @return Pointer to the shared string. * @note The pointer returned may be invalidated by calls to non-const member functions. */ const char* c_str() const { return _string; } /** * @brief Alias to @ref c_str() const. */ const char* data() const { return _string; } private: /** * @internal */ Eina_Stringshare* _string; }; /** * Specialization of the default template to define the * stringshare::const_iterator as a contiguous iterator. */ template <> struct is_contiguous_iterator : true_type {}; /** * @brief Check if two eina::stringshare objects represent the same string. * @return @c true if the strings of the objects are equal, @c false otherwise. * * This operator checks if two eina::stringshare objects * represent the same string. Because of the nature of the objects, * this operation falls into a simple pointer comparison, since * identical strings are represented by the same instance. */ inline bool operator==(stringshare const& lhs, stringshare const& rhs) { return lhs.c_str() == rhs.c_str(); } /** * @brief Check if two eina::stringshare objects represent different strings. * @return @c true if the strings of the objects are different, @c false otherwise. * * This function essentially returns the opposite of * @ref operator==(stringshare const& lhs, stringshare const& rhs). */ inline bool operator!=(stringshare const& lhs, stringshare const& rhs) { return !(lhs == rhs); } /** * @brief Compare an eina::stringshare object with a c-like string. * @return @c true if the content of the eina::stringshare * string is equal the content of the given string, @c false * otherwise. */ inline bool operator==(stringshare const& lhs, const char* rhs) { return lhs.c_str() == rhs || std::strcmp(lhs.c_str(), rhs) == 0; } /** * @brief Compare an eina::stringshare object with a c-like string. * @return @c true if the content of the eina::stringshare * string is different from content of the given string, * @c false otherwise. */ inline bool operator!=(stringshare const& lhs, const char* rhs) { return !(lhs == rhs); } /** * @brief Compare an eina::stringshare object with a c-like string. * @return @c true if the content of the eina::stringshare * string is equal the content of the given string, @c false * otherwise. */ inline bool operator==(const char* lhs, stringshare const& rhs) { return rhs == lhs; } /** * @brief Compare an eina::stringshare object with a c-like string. * @return @c true if the content of the eina::stringshare * string is different from content of the given string, * @c false otherwise. */ inline bool operator!=(const char* lhs, stringshare const& rhs) { return !(lhs == rhs); } /** * @} */ } } /** * @} */ #endif