source: rrlib_uri/tPath.h @ 19:49b39ac77cad

17.03 tip
Last change on this file since 19:49b39ac77cad was 19:49b39ac77cad, checked in by Max Reichardt <max.reichardt@…>, 6 months ago

Adds a std::ostream stream operator for tStringRange as well as typedefs and minor tweaks to tPath::tConstIterator (so that std::iterator_traits return a valid result). This e.g. enables using the latter with rrlib::util::Join.

File size: 12.7 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    typedef long int difference_type;
307    typedef const tElement value_type;
308    typedef const tElement* pointer;
309    typedef const tElement& reference;
310    typedef std::bidirectional_iterator_tag iterator_category;
311
312    tConstIterator(const tPath& path, long int element_index) :
313      path(&path),
314      element_index(element_index),
315      element()
316    {
317      UpdateElement();
318    }
319
320    friend bool operator==(const tConstIterator& lhs, const tConstIterator& rhs)
321    {
322      return (*lhs.path == *rhs.path) && lhs.element_index == rhs.element_index;
323    }
324    friend bool operator!=(const tConstIterator& lhs, const tConstIterator& rhs)
325    {
326      return !(lhs == rhs);
327    }
328    const tElement& operator*() const
329    {
330      return element;
331    }
332    inline const tElement* operator->() const
333    {
334      return &(operator*());
335    }
336    inline tConstIterator& operator++()
337    {
338      element_index++;
339      UpdateElement();
340      return *this;
341    }
342    inline tConstIterator operator ++ (int)
343    {
344      tConstIterator temp(*this);
345      operator++();
346      return temp;
347    }
348    inline tConstIterator& operator--()
349    {
350      element_index--;
351      UpdateElement();
352      return *this;
353    }
354    inline tConstIterator operator -- (int)
355    {
356      tConstIterator temp(*this);
357      operator--();
358      return temp;
359    }
360    friend long int operator+(const tConstIterator& lhs, const tConstIterator& rhs)
361    {
362      return lhs.element_index + rhs.element_index;
363    }
364    friend long int operator-(const tConstIterator& lhs, const tConstIterator& rhs)
365    {
366      return lhs.element_index - rhs.element_index;
367    }
368    friend tConstIterator operator+(const tConstIterator& lhs, long int rhs)
369    {
370      return tConstIterator(*lhs.path, lhs.element_index + rhs);
371    }
372    friend tConstIterator operator-(const tConstIterator& lhs, long int rhs)
373    {
374      return tConstIterator(*lhs.path, lhs.element_index - rhs);
375    }
376
377  private:
378
379    const tPath* path;
380    long int element_index;
381    tElement element;
382
383    void UpdateElement()
384    {
385      element = static_cast<unsigned long int>(element_index) >= path->element_count ? tStringRange() : (*path)[element_index];
386    }
387  };
388
389//----------------------------------------------------------------------
390// Private fields and methods
391//----------------------------------------------------------------------
392private:
393
394  /*! Number of elements in path */
395  size_t element_count;
396
397  /*!
398   * Memory allocated to store path:
399   * - offsets of elements (uint)
400   * - length of below (uint)   (to uniformly be able to determine length of last element in [] operator)
401   * - const char* containing whole path separated with slashes and terminated with zero
402   */
403  std::vector<char> memory;
404
405  /*!
406   * \param String to get const char* pointer of
407   * \return Const char*
408   */
409  static const char* GetConstCharPointer(const std::string& string)
410  {
411    return string.c_str();
412  }
413  static const char* GetConstCharPointer(const char* string)
414  {
415    return string;
416  }
417  static const char* GetConstCharPointer(const tStringRange& string)
418  {
419    return string.CharPointer();
420  }
421
422  /*!
423   * \return Pointer to first entry of element offset table
424   */
425  const uint* GetElementOffsetTable() const
426  {
427    return reinterpret_cast<const uint*>(&memory[0]);
428  }
429
430  /*!
431   * \return Pointer to start of path string
432   */
433  const char* GetPathStringBegin() const
434  {
435    return memory.size() ? &memory[(element_count + 1) * sizeof(uint)] : "\0";
436  }
437
438  /*!
439   * \param string String to obtain length from
440   * \return String length
441   */
442  static size_t StringLength(const std::string& string)
443  {
444    return string.length();
445  }
446  static size_t StringLength(const char* string)
447  {
448    return strlen(string);
449  }
450  static size_t StringLength(const tStringRange& string)
451  {
452    return string.Length();
453  }
454};
455
456
457inline bool operator!=(const tPath& lhs, const tPath& rhs)
458{
459  return !(lhs == rhs);
460}
461
462serialization::tOutputStream& operator << (serialization::tOutputStream& stream, const tPath& path);
463serialization::tInputStream& operator >> (serialization::tInputStream& stream, tPath& path);
464serialization::tStringOutputStream& operator << (serialization::tStringOutputStream& stream, const tPath& path);
465serialization::tStringInputStream& operator >> (serialization::tStringInputStream& stream, tPath& path);
466
467//----------------------------------------------------------------------
468// End of namespace declaration
469//----------------------------------------------------------------------
470}
471}
472
473
474#endif
Note: See TracBrowser for help on using the repository browser.