From 49285226d66189e2cea6c8b1fa59a4273ad05bc0 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 24 Aug 2015 14:47:11 +0200 Subject: Add "exact" constructor to path --- butl/path | 45 ++++++++++++++++++++++++++++----------------- butl/path.txx | 19 ++++++++++++++----- 2 files changed, 42 insertions(+), 22 deletions(-) diff --git a/butl/path b/butl/path index 7f97f49..194f65d 100644 --- a/butl/path +++ b/butl/path @@ -238,26 +238,39 @@ namespace butl struct iterator; typedef std::reverse_iterator reverse_iterator; - // Construct special empty path. Note that we have to provide our + // Create a special empty path. Note that we have to provide our // own implementation rather than using '=default' to make clang // allow default-initialized const instances of this type. // basic_path () {}; explicit - basic_path (C const* s): base_type (s) {init ();} + basic_path (C const* s): base_type (s) {init (this->path_);} basic_path (C const* s, size_type n) - : base_type (string_type (s, n)) {init ();} + : base_type (string_type (s, n)) {init (this->path_);} explicit - basic_path (string_type s): base_type (std::move (s)) {init ();} + basic_path (string_type s): base_type (std::move (s)) {init (this->path_);} basic_path (const string_type& s, size_type n) - : base_type (string_type (s, 0, n)) {init ();} + : base_type (string_type (s, 0, n)) {init (this->path_);} basic_path (const string_type& s, size_type p, size_type n) - : base_type (string_type (s, p, n)) {init ();} + : base_type (string_type (s, p, n)) {init (this->path_);} + + // Create a path using the exact string representation. If + // the string is not a valid path or if it would require a + // modification, then empty path is created instead and the + // passed string rvalue-reference is left untouched. See + // also string() && below. + // + enum exact_type {exact}; + basic_path (string_type&& s, exact_type) + { + if (init (s, true)) + this->path_ = std::move (s); + } // Create a path as a sub-path identified by the [begin, end) // range of components. @@ -268,16 +281,10 @@ namespace butl : basic_path (rend.base (), rbegin.base ()) {} void - swap (basic_path& p) - { - this->path_.swap (p.path_); - } + swap (basic_path& p) {this->path_.swap (p.path_);} void - clear () - { - this->path_.clear (); - } + clear () {this->path_.clear ();} // Get/set current working directory. Throw std::system_error // to report the underlying OS errors. @@ -561,11 +568,15 @@ namespace butl basic_path (string_type s, bool i): base_type (std::move (s)) { if (i) - init (); + init (this->path_); } - void - init (); + // If exact is true, return whether the initialization was + // successful, that is, the passed string is a valid path + // and no modifications were necessary. + // + bool + init (string_type& s, bool exact = false); }; template diff --git a/butl/path.txx b/butl/path.txx index 6d418ff..20e9e00 100644 --- a/butl/path.txx +++ b/butl/path.txx @@ -243,14 +243,23 @@ namespace butl } template - void basic_path:: - init () + bool basic_path:: + init (string_type& s, bool exact) { // Strip trailing slashes except for the case where the single // slash represents the root directory. // - size_type n (this->path_.size ()); - for (; n > 1 && traits::is_separator (this->path_[n - 1]); --n) ; - this->path_.resize (n); + size_type n (s.size ()); + for (; n > 1 && traits::is_separator (s[n - 1]); --n) ; + + if (n != s.size ()) + { + if (!exact) + this->path_.resize (n); + + return !exact; + } + + return true; } } -- cgit v1.1