1// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef TOOLS_GN_SOURCE_DIR_H_
6#define TOOLS_GN_SOURCE_DIR_H_
7
8#include <algorithm>
9#include <string>
10
11#include "base/containers/hash_tables.h"
12#include "base/files/file_path.h"
13#include "base/logging.h"
14#include "base/strings/string_piece.h"
15
16class SourceFile;
17
18// Represents a directory within the source tree. Source dirs begin and end in
19// slashes.
20//
21// If there is one slash at the beginning, it will mean a system-absolute file
22// path. On Windows, absolute system paths will be of the form "/C:/foo/bar".
23//
24// Two slashes at the beginning indicate a path relative to the source root.
25class SourceDir {
26 public:
27  enum SwapIn { SWAP_IN };
28
29  SourceDir();
30  explicit SourceDir(const base::StringPiece& p);
31  // Swaps the given string in without copies. The given string will be empty
32  // after this call.
33  SourceDir(SwapIn, std::string* s);
34  ~SourceDir();
35
36  // Resolves a file or dir name relative to this source directory. Will return
37  // an empty SourceDir/File on error. Empty input is always an error (it's
38  // possible we should say ResolveRelativeDir vs. an empty string should be
39  // the source dir, but we require "." instead).
40  //
41  // If source_root is supplied, these functions will additionally handle the
42  // case where the input is a system-absolute but still inside the source
43  // tree. This is the case for some external tools.
44  SourceFile ResolveRelativeFile(
45      const base::StringPiece& p,
46      const base::StringPiece& source_root = base::StringPiece()) const;
47  SourceDir ResolveRelativeDir(
48      const base::StringPiece& p,
49      const base::StringPiece& source_root = base::StringPiece()) const;
50
51  // Resolves this source file relative to some given source root. Returns
52  // an empty file path on error.
53  base::FilePath Resolve(const base::FilePath& source_root) const;
54
55  bool is_null() const { return value_.empty(); }
56  const std::string& value() const { return value_; }
57
58  // Returns true if this path starts with a "//" which indicates a path
59  // from the source root.
60  bool is_source_absolute() const {
61    return value_.size() >= 2 && value_[0] == '/' && value_[1] == '/';
62  }
63
64  // Returns true if this path starts with a single slash which indicates a
65  // system-absolute path.
66  bool is_system_absolute() const {
67    return !is_source_absolute();
68  }
69
70  // Returns a source-absolute path starting with only one slash at the
71  // beginning (normally source-absolute paths start with two slashes to mark
72  // them as such). This is normally used when concatenating directories
73  // together.
74  //
75  // This function asserts that the directory is actually source-absolute. The
76  // return value points into our buffer.
77  base::StringPiece SourceAbsoluteWithOneSlash() const {
78    CHECK(is_source_absolute());
79    return base::StringPiece(&value_[1], value_.size() - 1);
80  }
81
82  void SwapValue(std::string* v);
83
84  bool operator==(const SourceDir& other) const {
85    return value_ == other.value_;
86  }
87  bool operator!=(const SourceDir& other) const {
88    return !operator==(other);
89  }
90  bool operator<(const SourceDir& other) const {
91    return value_ < other.value_;
92  }
93
94  void swap(SourceDir& other) {
95    value_.swap(other.value_);
96  }
97
98 private:
99  friend class SourceFile;
100  std::string value_;
101
102  // Copy & assign supported.
103};
104
105namespace BASE_HASH_NAMESPACE {
106
107#if defined(COMPILER_GCC)
108template<> struct hash<SourceDir> {
109  std::size_t operator()(const SourceDir& v) const {
110    hash<std::string> h;
111    return h(v.value());
112  }
113};
114#elif defined(COMPILER_MSVC)
115inline size_t hash_value(const SourceDir& v) {
116  return hash_value(v.value());
117}
118#endif  // COMPILER...
119
120}  // namespace BASE_HASH_NAMESPACE
121
122inline void swap(SourceDir& lhs, SourceDir& rhs) {
123  lhs.swap(rhs);
124}
125
126#endif  // TOOLS_GN_SOURCE_DIR_H_
127