source: rrlib_uri/tPath.h @ 17:1b2e312c7b52

17.03
Last change on this file since 17:1b2e312c7b52 was 17:1b2e312c7b52, checked in by Max Reichardt <max.reichardt@…>, 17 months ago

Makes path iterator copy constructible (erroneously wasn't)

File size: 12.2 KB
Line 
1//
2// You received this file as part of RRLib
3// Robotics Research Library
4//
5// Copyright (C) Finroc GbR (finroc.org)
6//
7// This program is free software; you can redistribute it and/or modify
8// it under the terms of the GNU General Public License as published by
9// the Free Software Foundation; either version 2 of the License, or
10// (at your option) any later version.
11//
12// This program is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15// GNU General Public License for more details.
16//
17// You should have received a copy of the GNU General Public License along
18// with this program; if not, write to the Free Software Foundation, Inc.,
19// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20//
21//----------------------------------------------------------------------
22/*!\file    rrlib/uri/tPath.h
23 *
24 * \author  Max Reichardt
25 *
26 * \date    2017-01-29
27 *
28 * \brief   Contains tPath
29 *
30 * \b tPath
31 *
32 * A path.
33 * A path consists of list of path elements (strings).
34 *
35 */
36//----------------------------------------------------------------------
37#ifndef __rrlib__uri__tPath_h__
38#define __rrlib__uri__tPath_h__
39
40//----------------------------------------------------------------------
41// External includes (system with <>, local with "")
42//----------------------------------------------------------------------
43#include <tuple>
44#include <cstring>
45#include <iostream>
46#include "rrlib/serialization/serialization.h"
47
48//----------------------------------------------------------------------
49// Internal includes with ""
50//----------------------------------------------------------------------
51#include "rrlib/uri/tStringRange.h"
52
53//----------------------------------------------------------------------
54// Namespace declaration
55//----------------------------------------------------------------------
56namespace rrlib
57{
58namespace uri
59{
60
61//----------------------------------------------------------------------
62// Forward declarations / typedefs / enums
63//----------------------------------------------------------------------
64
65//----------------------------------------------------------------------
66// Class declaration
67//----------------------------------------------------------------------
68//! Path
69/*!
70 * A path.
71 * A path consists of list of path elements.
72 *
73 * Implementation note: the whole path is efficiently stored in one continuous block of memory
74 */
75class tPath
76{
77
78//----------------------------------------------------------------------
79// Public methods and typedefs
80//----------------------------------------------------------------------
81public:
82
83  class tConstIterator;
84
85  /*! Path elements */
86  typedef tStringRange tElement;
87
88  /*! Creates empty path */
89  tPath() :
90    element_count(0)
91  {}
92
93
94  /*!
95   * Constructs path from string
96   *
97   * \param path_string String (e.g. /element1/element2)
98   * \param separator Separator of path elements
99   */
100  tPath(const tStringRange& path_string, char separator = '/') :
101    tPath()
102  {
103    Set(path_string, separator);
104  }
105  tPath(const std::string& path_string, char separator = '/') : tPath(tStringRange(path_string), separator) {}
106  tPath(const char* path_string, char separator = '/') : tPath(tStringRange(path_string), separator) {}
107
108  /*!
109   * Constructs path from iterator over string elements - e.g.
110   *   tPath(string_vector.begin(), string_vector.end())
111   * String elements can be std::string, const char*, or tStringRange.
112   *
113   * \param absolute Whether this is an abolute path
114   * \param begin String element begin iterator
115   * \param end String element end iterator
116   */
117  template <typename TStringIterator>
118  tPath(bool absolute, TStringIterator begin, TStringIterator end) :
119    tPath()
120  {
121    Set(absolute, begin, end);
122  }
123
124  /*!
125   * Append path to this path (possibly eliminating '..' and '.' entries)
126   *
127   * \param append Path to append
128   * \return Result
129   */
130  tPath Append(const tPath& append) const;
131
132  /*!
133   * \return Begin iterator for path elements
134   */
135  tConstIterator Begin() const
136  {
137    return tConstIterator(*this, 0);
138  }
139
140  /*!
141   * Clear path
142   */
143  void Clear()
144  {
145    element_count = 0;
146    memory.clear();
147  }
148
149  /*!
150   * \return Number of path elements this path and the other path have in common
151   */
152  size_t CountCommonElements(const tPath& other) const
153  {
154    size_t max = std::max(other.Size(), this->Size());
155    for (size_t i = 0; i < max; i++)
156    {
157      if ((*this)[i] != other[i])
158      {
159        return i;
160      }
161    }
162    return max;
163  }
164
165  /*!
166   * \return End iterator for path elements
167   */
168  tConstIterator End() const
169  {
170    return tConstIterator(*this, element_count);
171  }
172
173  /*!
174   * \return Whether this is an abolute path
175   */
176  bool IsAbsolute() const
177  {
178    return GetPathStringBegin()[0] == '/';
179  }
180
181  /*!
182   * \return Absolute version of this path
183   */
184  inline tPath MakeAbsolute() const
185  {
186    return tPath(true, Begin(), End());
187  }
188
189  /*!
190   * \return Relative version of this path
191   */
192  inline tPath MakeRelative() const
193  {
194    return tPath(false, Begin(), End());
195  }
196
197  /*!
198   * Removes dot segments ('/./' and '/../') in this path.
199   * (as e.g. described in RFC 3986 section 5.2.4 for URIs)
200   *
201   * \return Number of '..' elements beyond top-level for relative paths (e.g. if path starts with "../../" this would be 2). For absolute paths always returns zero.
202   */
203  size_t RemoveDotSegments();
204
205  /*!
206   * Sets path elements from string
207   *
208   * \param path_string String (e.g. /element1/element2)
209   * \param separator Separator of path elements
210   */
211  void Set(const tStringRange& path_string, char separator);
212
213  /*!
214   * Sets path elements from iterator - e.g.
215   *   path.Set(string_vector.begin(), string_vector.end())
216   * String elements can either be std::string or const char*.
217   *
218   * \param absolute Whether this is an abolute path
219   * \param begin String element begin iterator
220   * \param end String element end iterator
221   */
222  template <typename TStringIterator>
223  void Set(bool absolute, TStringIterator begin, TStringIterator end)
224  {
225    element_count = end - begin;
226
227    // Create element table
228    uint elements[element_count + 1];
229    uint lengths[element_count + 1];
230    uint current_offset = absolute ? 1 : 0;
231    for (auto it = begin; it != end; ++it)
232    {
233      size_t length = StringLength(*it);
234      elements[it - begin] = current_offset;
235      current_offset += (length + 1);
236      lengths[it - begin] = length;
237    }
238    elements[element_count] = current_offset;
239
240    // Allocate and fill memory
241    long int table_size = (element_count + 1) * sizeof(uint);
242    size_t required_memory = table_size + current_offset;
243    memory.resize(required_memory);
244    memcpy(&memory[0], elements, table_size);
245    char* buffer = &memory[table_size];
246    if (absolute)
247    {
248      (*buffer) = '/';
249      buffer++;
250    }
251    for (auto it = begin; it != end; ++it)
252    {
253      memcpy(buffer, GetConstCharPointer(*it), lengths[it - begin]);
254      buffer += lengths[it - begin];
255      (*buffer) = '/';
256      buffer++;
257    }
258
259    memory[required_memory - 1] = 0; // Null-terminator
260  }
261
262  /*!
263   * \return Number of elements in path
264   */
265  size_t Size() const
266  {
267    return element_count;
268  }
269
270  /*!
271   * \return Total number of characters in path - including separators and terminator
272   */
273  size_t TotalCharacters() const
274  {
275    return memory.size() - (element_count + 1) * sizeof(uint);
276  }
277
278  friend bool operator==(const tPath& lhs, const tPath& rhs)
279  {
280    return lhs.element_count == rhs.element_count && lhs.memory == rhs.memory;
281  }
282  friend bool operator<(const tPath& lhs, const tPath& rhs)
283  {
284    return std::tie(lhs.element_count, lhs.memory) < std::tie(rhs.element_count, rhs.memory);
285  }
286  tElement operator[](size_t index) const
287  {
288    const uint* table = GetElementOffsetTable();
289    const char* chars = GetPathStringBegin();
290    return tElement(chars + table[index], table[index + 1] - table[index] - 1);
291  }
292  friend inline std::ostream& operator << (std::ostream& stream, const tPath& path) // for command line output
293  {
294    stream.write(path.GetPathStringBegin(), &path.memory.back() - path.GetPathStringBegin());
295    return stream;
296  }
297
298
299  /*!
300   * Iterator over path elements (tStringRanges)
301   */
302  class tConstIterator
303  {
304  public:
305
306    tConstIterator(const tPath& path, size_t element_index) :
307      path(&path),
308      element_index(element_index),
309      element()
310    {
311      UpdateElement();
312    }
313
314    friend bool operator==(const tConstIterator& lhs, const tConstIterator& rhs)
315    {
316      return (*lhs.path == *rhs.path) && lhs.element_index == rhs.element_index;
317    }
318    friend bool operator!=(const tConstIterator& lhs, const tConstIterator& rhs)
319    {
320      return !(lhs == rhs);
321    }
322    const tElement& operator*() const
323    {
324      return element;
325    }
326    inline const tElement* operator->() const
327    {
328      return &(operator*());
329    }
330    inline tConstIterator& operator++()
331    {
332      element_index++;
333      UpdateElement();
334      return *this;
335    }
336    inline tConstIterator operator ++ (int)
337    {
338      tConstIterator temp(*this);
339      operator++();
340      return temp;
341    }
342    friend size_t operator+(const tConstIterator& lhs, const tConstIterator& rhs)
343    {
344      return lhs.element_index + rhs.element_index;
345    }
346    friend size_t operator-(const tConstIterator& lhs, const tConstIterator& rhs)
347    {
348      return lhs.element_index - rhs.element_index;
349    }
350    friend tConstIterator operator+(const tConstIterator& lhs, size_t rhs)
351    {
352      return tConstIterator(*lhs.path, lhs.element_index + rhs);
353    }
354    friend tConstIterator operator-(const tConstIterator& lhs, size_t rhs)
355    {
356      return tConstIterator(*lhs.path, lhs.element_index - rhs);
357    }
358
359  private:
360
361    const tPath* path;
362    size_t element_index;
363    tElement element;
364
365    void UpdateElement()
366    {
367      element = element_index >= path->element_count ? tStringRange() : (*path)[element_index];
368    }
369  };
370
371//----------------------------------------------------------------------
372// Private fields and methods
373//----------------------------------------------------------------------
374private:
375
376  /*! Number of elements in path */
377  size_t element_count;
378
379  /*!
380   * Memory allocated to store path:
381   * - offsets of elements (uint)
382   * - length of below (uint)   (to uniformly be able to determine length of last element in [] operator)
383   * - const char* containing whole path separated with slashes and terminated with zero
384   */
385  std::vector<char> memory;
386
387  /*!
388   * \param String to get const char* pointer of
389   * \return Const char*
390   */
391  static const char* GetConstCharPointer(const std::string& string)
392  {
393    return string.c_str();
394  }
395  static const char* GetConstCharPointer(const char* string)
396  {
397    return string;
398  }
399  static const char* GetConstCharPointer(const tStringRange& string)
400  {
401    return string.CharPointer();
402  }
403
404  /*!
405   * \return Pointer to first entry of element offset table
406   */
407  const uint* GetElementOffsetTable() const
408  {
409    return reinterpret_cast<const uint*>(&memory[0]);
410  }
411
412  /*!
413   * \return Pointer to start of path string
414   */
415  const char* GetPathStringBegin() const
416  {
417    return memory.size() ? &memory[(element_count + 1) * sizeof(uint)] : "\0";
418  }
419
420  /*!
421   * \param string String to obtain length from
422   * \return String length
423   */
424  static size_t StringLength(const std::string& string)
425  {
426    return string.length();
427  }
428  static size_t StringLength(const char* string)
429  {
430    return strlen(string);
431  }
432  static size_t StringLength(const tStringRange& string)
433  {
434    return string.Length();
435  }
436};
437
438
439inline bool operator!=(const tPath& lhs, const tPath& rhs)
440{
441  return !(lhs == rhs);
442}
443
444serialization::tOutputStream& operator << (serialization::tOutputStream& stream, const tPath& path);
445serialization::tInputStream& operator >> (serialization::tInputStream& stream, tPath& path);
446serialization::tStringOutputStream& operator << (serialization::tStringOutputStream& stream, const tPath& path);
447serialization::tStringInputStream& operator >> (serialization::tStringInputStream& stream, tPath& path);
448
449//----------------------------------------------------------------------
450// End of namespace declaration
451//----------------------------------------------------------------------
452}
453}
454
455
456#endif
Note: See TracBrowser for help on using the repository browser.