You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

544 lines
16 KiB

/*
* 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 <Eina.h>
#include <eina_type_traits.hh>
#include <eina_throw.hh>
#include <cstring>
#include <stdexcept>
/**
* @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_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 <tt>NULL</tt>-terminated string to be shared.
*
* This constructor creates an <tt>eina::stringshare</tt> 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 <tt>eina::stringshare</tt> that steal the ownership of the given shared string.
* @param str Shared string whose ownership should be stolen.
*
* This constructor creates an <tt>eina::stringshare</tt> 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 <typename InputIterator>
stringshare(InputIterator i, InputIterator j
, typename eina::enable_if
<!eina::is_integral<InputIterator>::value
&& !eina::is_contiguous_iterator<InputIterator>::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 <typename ContiguousMemoryIterator>
stringshare(ContiguousMemoryIterator i, ContiguousMemoryIterator j
, typename eina::enable_if
<eina::is_contiguous_iterator<ContiguousMemoryIterator>::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 <tt>eina::stringshare</tt> associated with the same shared string.
* @param other Another <tt>eina::stringshare</tt>.
*
* 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 <tt>eina::stringshare</tt>.
*
* 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 <tt>NULL</tt>-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 <tt>std::out_of_range</tt> 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 <tt>std::out_of_range</tt>.
*/
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 <tt>eina::stringshare</tt>.
*/
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
* <tt>stringshare::const_iterator</tt> as a contiguous iterator.
*/
template <>
struct is_contiguous_iterator<stringshare::const_iterator> : true_type {};
/**
* @brief Check if two <tt>eina::stringshare</tt> objects represent the same string.
* @return @c true if the strings of the objects are equal, @c false otherwise.
*
* This operator checks if two <tt>eina::stringshare</tt> 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 <tt>eina::stringshare</tt> 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 <tt>eina::stringshare</tt> object with a c-like string.
* @return @c true if the content of the <tt>eina::stringshare</tt>
* 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 <tt>eina::stringshare</tt> object with a c-like string.
* @return @c true if the content of the <tt>eina::stringshare</tt>
* 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 <tt>eina::stringshare</tt> object with a c-like string.
* @return @c true if the content of the <tt>eina::stringshare</tt>
* 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 <tt>eina::stringshare</tt> object with a c-like string.
* @return @c true if the content of the <tt>eina::stringshare</tt>
* 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