blob: b581d4375a26b6d5ede9742e625c182899e2c2ed [file] [log] [blame]
// Copyright 2017 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.devtools.build.lib.vfs;
import com.google.common.base.Preconditions;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
/**
* Abstract base class for {@link PathFragment} instances that will be allocated when Blaze is run
* on a non-Windows platform.
*/
abstract class UnixPathFragment extends PathFragment {
static final Helper HELPER = new Helper();
/**
* We have two concrete subclasses with zero per-instance additional memory overhead. Do not add
* any fields. See the comment on memory use in PathFragment for details on the current
* per-instance memory usage.
*/
protected UnixPathFragment(String[] segments) {
super(segments);
}
@Override
protected int computeHashCode() {
int h = 0;
for (String segment : segments) {
int segmentHash = segment.hashCode();
h = h * 31 + segmentHash;
}
return h;
}
@Override
public String windowsVolume() {
return "";
}
@Override
public char getDriveLetter() {
return '\0';
}
private static class Helper extends PathFragment.Helper {
private static final char SEPARATOR_CHAR = '/';
@Override
PathFragment create(String path) {
boolean isAbsolute = path.length() > 0 && isSeparator(path.charAt(0));
return isAbsolute
? new AbsoluteUnixPathFragment(segment(path, 1))
: new RelativeUnixPathFragment(segment(path, 0));
}
@Override
PathFragment createAlreadyInterned(char driveLetter, boolean isAbsolute, String[] segments) {
Preconditions.checkState(driveLetter == '\0', driveLetter);
return isAbsolute
? new AbsoluteUnixPathFragment(segments)
: new RelativeUnixPathFragment(segments);
}
@Override
char getPrimarySeparatorChar() {
return SEPARATOR_CHAR;
}
@Override
boolean isSeparator(char c) {
return c == SEPARATOR_CHAR;
}
@Override
boolean containsSeparatorChar(String path) {
return path.indexOf(SEPARATOR_CHAR) != -1;
}
@Override
boolean segmentsEqual(int length, String[] segments1, int offset1, String[] segments2) {
if ((segments1.length - offset1) < length || segments2.length < length) {
return false;
}
for (int i = 0; i < length; ++i) {
String seg1 = segments1[i + offset1];
String seg2 = segments2[i];
if ((seg1 == null) != (seg2 == null)) {
return false;
}
if (seg1 == null) {
continue;
}
if (!seg1.equals(seg2)) {
return false;
}
}
return true;
}
@Override
protected int compare(PathFragment pathFragment1, PathFragment pathFragment2) {
if (pathFragment1.isAbsolute() != pathFragment2.isAbsolute()) {
return pathFragment1.isAbsolute() ? -1 : 1;
}
String[] segments1 = pathFragment1.segments();
String[] segments2 = pathFragment2.segments();
int len1 = segments1.length;
int len2 = segments2.length;
int n = Math.min(len1, len2);
for (int i = 0; i < n; i++) {
String seg1 = segments1[i];
String seg2 = segments2[i];
int cmp = seg1.compareTo(seg2);
if (cmp != 0) {
return cmp;
}
}
return len1 - len2;
}
}
private static final class AbsoluteUnixPathFragment extends UnixPathFragment {
private AbsoluteUnixPathFragment(String[] segments) {
super(segments);
}
@Override
public boolean isAbsolute() {
return true;
}
@Override
protected int computeHashCode() {
int h = Boolean.TRUE.hashCode();
h = h * 31 + super.computeHashCode();
return h;
}
@Override
public boolean equals(Object other) {
if (!(other instanceof AbsoluteUnixPathFragment)) {
return false;
}
if (this == other) {
return true;
}
AbsoluteUnixPathFragment otherAbsoluteUnixPathFragment = (AbsoluteUnixPathFragment) other;
return HELPER.segmentsEqual(this.segments, otherAbsoluteUnixPathFragment.segments);
}
// Java serialization looks for the presence of this method in the concrete class. It is not
// inherited from the parent class.
@Override
protected Object writeReplace() {
return super.writeReplace();
}
// Java serialization looks for the presence of this method in the concrete class. It is not
// inherited from the parent class.
@Override
protected void readObject(ObjectInputStream stream) throws InvalidObjectException {
super.readObject(stream);
}
}
private static final class RelativeUnixPathFragment extends UnixPathFragment {
private RelativeUnixPathFragment(String[] segments) {
super(segments);
}
@Override
public boolean isAbsolute() {
return false;
}
@Override
protected int computeHashCode() {
int h = Boolean.FALSE.hashCode();
h = h * 31 + super.computeHashCode();
return h;
}
@Override
public boolean equals(Object other) {
if (!(other instanceof RelativeUnixPathFragment)) {
return false;
}
if (this == other) {
return true;
}
RelativeUnixPathFragment otherRelativeUnixPathFragment = (RelativeUnixPathFragment) other;
return HELPER.segmentsEqual(this.segments, otherRelativeUnixPathFragment.segments);
}
// Java serialization looks for the presence of this method in the concrete class. It is not
// inherited from the parent class.
@Override
protected Object writeReplace() {
return super.writeReplace();
}
// Java serialization looks for the presence of this method in the concrete class. It is not
// inherited from the parent class.
@Override
protected void readObject(ObjectInputStream stream) throws InvalidObjectException {
super.readObject(stream);
}
}
}