summaryrefslogtreecommitdiff
path: root/src/bindings/cxx/eina_cxx/eina_stringshare.hh
blob: e7e2f67a92811573db68b3fc055d3db718be1e5d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
#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