aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--butl/path68
-rw-r--r--butl/path.ixx15
-rw-r--r--butl/path.txx31
3 files changed, 98 insertions, 16 deletions
diff --git a/butl/path b/butl/path
index 193eae4..33c3d11 100644
--- a/butl/path
+++ b/butl/path
@@ -74,13 +74,20 @@ namespace butl
static size_type
find_separator (string_type const& s, size_type pos = 0)
{
- for (size_type n (s.size ()); pos < n; ++pos)
+ const C* r (find_separator (s.c_str () + pos, s.size () - pos));
+ return r != nullptr ? r - s.c_str () : string_type::npos;
+ }
+
+ static const C*
+ find_separator (const C* s, size_type n)
+ {
+ for (const C* e (s + n); s != e; ++s)
{
- if (is_separator (s[pos]))
- return pos;
+ if (is_separator (*s))
+ return s;
}
- return string_type::npos;
+ return nullptr;
}
static size_type
@@ -360,10 +367,10 @@ namespace butl
public:
bool
- empty () const
- {
- return this->path_.empty ();
- }
+ empty () const {return this->path_.empty ();}
+
+ size_type
+ size () const {return this->path_.size ();}
// Return true if this path doesn't have any directories. Note
// that "/foo" is not a simple path (it is "foo" in root directory)
@@ -562,6 +569,15 @@ namespace butl
basic_path&
operator/= (basic_path const&);
+ // Append a single path component (must not contain directory separators)
+ // as a string, without first constructing the path object.
+ //
+ basic_path&
+ operator/= (string_type const&);
+
+ basic_path&
+ operator/= (const C*);
+
basic_path
operator+ (string_type const& s) const
{
@@ -569,6 +585,12 @@ namespace butl
}
basic_path
+ operator+ (const C* s) const
+ {
+ return basic_path (this->path_ + s);
+ }
+
+ basic_path
operator+ (C c) const
{
return basic_path (this->path_ + c);
@@ -582,6 +604,13 @@ namespace butl
}
basic_path&
+ operator+= (const C* s)
+ {
+ this->path_ += s;
+ return *this;
+ }
+
+ basic_path&
operator+= (C c)
{
this->path_ += c;
@@ -622,6 +651,11 @@ namespace butl
init (this->path_);
}
+ // Common implementation for operator=/().
+ //
+ void
+ combine (const C*, size_type);
+
private:
template <class P, class C1, class K1>
friend P butl::path_cast (const basic_path<C1, K1>&);
@@ -648,6 +682,24 @@ namespace butl
return r;
}
+ template <typename C, typename K>
+ inline basic_path<C, K>
+ operator/ (basic_path<C, K> const& x, std::basic_string<C> const& y)
+ {
+ basic_path<C, K> r (x);
+ r /= y;
+ return r;
+ }
+
+ template <typename C, typename K>
+ inline basic_path<C, K>
+ operator/ (basic_path<C, K> const& x, const C* y)
+ {
+ basic_path<C, K> r (x);
+ r /= y;
+ return r;
+ }
+
template <typename C, typename K1, typename K2>
inline bool
operator== (const basic_path<C, K1>& x, const basic_path<C, K2>& y)
diff --git a/butl/path.ixx b/butl/path.ixx
index 1628ece..48d6576 100644
--- a/butl/path.ixx
+++ b/butl/path.ixx
@@ -233,4 +233,19 @@ namespace butl
return string ();
}
#endif
+
+ template <typename C, typename K>
+ inline void basic_path<C, K>::
+ combine (const C* r, size_type rn)
+ {
+ size_type ln (this->path_.size ());
+
+ if (ln != 0 && rn != 0)
+ {
+ if (!traits::is_separator (this->path_[ln - 1]))
+ this->path_ += traits::directory_separator;
+ }
+
+ this->path_.append (r, rn);
+ }
}
diff --git a/butl/path.txx b/butl/path.txx
index 35c6956..94fbd90 100644
--- a/butl/path.txx
+++ b/butl/path.txx
@@ -61,16 +61,31 @@ namespace butl
if (r.absolute () && !this->path_.empty ()) // Allow ('' / '/foo').
throw invalid_basic_path<C> (r.path_);
- if (this->path_.empty () || r.path_.empty ())
- {
- this->path_ += r.path_;
- return *this;
- }
+ combine (r.path_.c_str (), r.path_.size ());
+ return *this;
+ }
+
+ template <typename C, typename K>
+ basic_path<C, K>& basic_path<C, K>::
+ operator/= (string_type const& r)
+ {
+ if (traits::find_separator (r) != string_type::npos)
+ throw invalid_basic_path<C> (r);
+
+ combine (r.c_str (), r.size ());
+ return *this;
+ }
+
+ template <typename C, typename K>
+ basic_path<C, K>& basic_path<C, K>::
+ operator/= (const C* r)
+ {
+ size_type rn (string_type::traits_type::length (r));
- if (!traits::is_separator (this->path_[this->path_.size () - 1]))
- this->path_ += traits::directory_separator;
+ if (traits::find_separator (r, rn) != nullptr)
+ throw invalid_basic_path<C> (r);
- this->path_ += r.path_;
+ combine (r, rn);
return *this;
}