diff options
author | Steven Moreland <smoreland@google.com> | 2017-01-18 16:46:01 -0800 |
---|---|---|
committer | Steven Moreland <smoreland@google.com> | 2017-01-18 16:46:43 -0800 |
commit | 7ae3d54cb65f1309cb643b83a2040225ad5f3128 (patch) | |
tree | bc0737699dceef45b421f4c13328bba5200fe2a3 /utils | |
parent | 6a01fb58a5656eb86b2aff69b87cca6c6dc5ccbd (diff) | |
download | hidl-7ae3d54cb65f1309cb643b83a2040225ad5f3128.tar.gz |
Move FQName to libhidl-gen-util.
This will allow other libraries to process FQNames, namely libhidl.
Test: compiles
Change-Id: I015a69e016c5cef37f42e02b54c22663315e3676
Diffstat (limited to 'utils')
-rw-r--r-- | utils/Android.bp | 1 | ||||
-rw-r--r-- | utils/FQName.cpp | 483 | ||||
-rw-r--r-- | utils/include/hidl-util/FQName.h | 217 |
3 files changed, 701 insertions, 0 deletions
diff --git a/utils/Android.bp b/utils/Android.bp index a6c37a62..4f788d66 100644 --- a/utils/Android.bp +++ b/utils/Android.bp @@ -22,6 +22,7 @@ cc_library_shared { srcs: [ "Formatter.cpp", "StringHelper.cpp", + "FQName.cpp" ], shared_libs: [ "libbase", diff --git a/utils/FQName.cpp b/utils/FQName.cpp new file mode 100644 index 00000000..1aad6f0f --- /dev/null +++ b/utils/FQName.cpp @@ -0,0 +1,483 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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. + */ + +#include "FQName.h" + +#include "StringHelper.h" + +#include <android-base/logging.h> +#include <iostream> +#include <regex> +#include <sstream> + +#define RE_COMPONENT "[a-zA-Z_][a-zA-Z_0-9]*" +#define RE_PATH RE_COMPONENT "(?:[.]" RE_COMPONENT ")*" +#define RE_MAJOR "[0-9]+" +#define RE_MINOR "[0-9]+" + +// android.hardware.foo@1.0::IFoo.Type +static const std::regex kRE1("(" RE_PATH ")@(" RE_MAJOR ")[.](" RE_MINOR ")::(" RE_PATH ")"); +// @1.0::IFoo.Type +static const std::regex kRE2("@(" RE_MAJOR ")[.](" RE_MINOR ")::(" RE_PATH ")"); +// android.hardware.foo@1.0 (for package declaration and whole package import) +static const std::regex kRE3("(" RE_PATH ")@(" RE_MAJOR ")[.](" RE_MINOR ")"); +// IFoo.Type +static const std::regex kRE4("(" RE_COMPONENT ")([.]" RE_COMPONENT ")+"); +// Type (a plain identifier) +static const std::regex kRE5("(" RE_COMPONENT ")"); + +// android.hardware.foo@1.0::IFoo.Type:MY_ENUM_VALUE +static const std::regex kRE6("(" RE_PATH ")@(" RE_MAJOR ")[.](" RE_MINOR ")::(" RE_PATH "):(" RE_COMPONENT ")"); +// @1.0::IFoo.Type:MY_ENUM_VALUE +static const std::regex kRE7("@(" RE_MAJOR ")[.](" RE_MINOR ")::(" RE_PATH "):(" RE_COMPONENT ")"); +// IFoo.Type:MY_ENUM_VALUE +static const std::regex kRE8("(" RE_PATH "):(" RE_COMPONENT ")"); + +// 1.0 +static const std::regex kREVer("(" RE_MAJOR ")[.](" RE_MINOR ")"); + +namespace android { + +FQName::FQName() + : mValid(false), + mIsIdentifier(false) { +} + +FQName::FQName(const std::string &s) + : mValid(false), + mIsIdentifier(false) { + setTo(s); +} + +FQName::FQName( + const std::string &package, + const std::string &version, + const std::string &name, + const std::string &valueName) + : mValid(true), + mIsIdentifier(false), + mPackage(package), + mName(name), + mValueName(valueName) { + setVersion(version); + + // Check if this is actually a valid fqName + FQName other; + other.setTo(this->string()); + CHECK(other.mValid && (*this) == other); +} + +FQName::FQName(const FQName& other) + : mValid(other.mValid), + mIsIdentifier(other.mIsIdentifier), + mPackage(other.mPackage), + mMajor(other.mMajor), + mMinor(other.mMinor), + mName(other.mName), + mValueName(other.mValueName) { +} + +FQName::FQName(const std::vector<std::string> &names) + : mValid(false), + mIsIdentifier(false) { + setTo(StringHelper::JoinStrings(names, ".")); +} + +bool FQName::isValid() const { + return mValid; +} + +bool FQName::isIdentifier() const { + return mIsIdentifier; +} + +bool FQName::isFullyQualified() const { + return !mPackage.empty() && !version().empty() && !mName.empty(); +} + +bool FQName::isValidValueName() const { + return mIsIdentifier + || (!mName.empty() && !mValueName.empty()); +} + +bool FQName::setTo(const std::string &s) { + mPackage.clear(); + mMajor.clear(); + mMinor.clear(); + mName.clear(); + + mValid = true; + + std::smatch match; + if (std::regex_match(s, match, kRE1)) { + CHECK_EQ(match.size(), 5u); + + mPackage = match.str(1); + mMajor = match.str(2); + mMinor = match.str(3); + mName = match.str(4); + } else if (std::regex_match(s, match, kRE2)) { + CHECK_EQ(match.size(), 4u); + + mMajor = match.str(1); + mMinor = match.str(2); + mName = match.str(3); + } else if (std::regex_match(s, match, kRE3)) { + CHECK_EQ(match.size(), 4u); + + mPackage = match.str(1); + mMajor = match.str(2); + mMinor = match.str(3); + } else if (std::regex_match(s, match, kRE4)) { + mName = match.str(0); + } else if (std::regex_match(s, match, kRE5)) { + mIsIdentifier = true; + mName = match.str(0); + } else if (std::regex_match(s, match, kRE6)) { + CHECK_EQ(match.size(), 6u); + + mPackage = match.str(1); + mMajor = match.str(2); + mMinor = match.str(3); + mName = match.str(4); + mValueName = match.str(5); + } else if (std::regex_match(s, match, kRE7)) { + CHECK_EQ(match.size(), 5u); + + mMajor = match.str(1); + mMinor = match.str(2); + mName = match.str(3); + mValueName = match.str(4); + } else if (std::regex_match(s, match, kRE8)) { + CHECK_EQ(match.size(), 3u); + + mName = match.str(1); + mValueName = match.str(2); + } else { + mValid = false; + } + + // mValueName must go with mName. + CHECK(mValueName.empty() || !mName.empty()); + + // package without version is not allowed. + CHECK(mPackage.empty() || !version().empty()); + + return isValid(); +} + +std::string FQName::package() const { + return mPackage; +} + +std::string FQName::version() const { + CHECK(mMajor.empty() == mMinor.empty()); + if (mMajor.empty() && mMinor.empty()) { + return ""; + } + return mMajor + "." + mMinor; +} + +std::string FQName::sanitizedVersion() const { + CHECK(mMajor.empty() == mMinor.empty()); + if (mMajor.empty() && mMinor.empty()) { + return ""; + } + return "V" + mMajor + "_" + mMinor; +} + +std::string FQName::atVersion() const { + std::string v = version(); + return v.empty() ? "" : ("@" + v); +} + +void FQName::setVersion(const std::string &v) { + if (v.empty()) { + mMajor.clear(); + mMinor.clear(); + return; + } + std::smatch match; + if (std::regex_match(v, match, kREVer)) { + CHECK_EQ(match.size(), 3u); + + mMajor = match.str(1); + mMinor = match.str(2); + } else { + mValid = false; + } +} + +std::string FQName::name() const { + return mName; +} + +std::vector<std::string> FQName::names() const { + std::vector<std::string> res {}; + std::istringstream ss(name()); + std::string s; + while (std::getline(ss, s, '.')) { + res.push_back(s); + } + return res; +} + +std::string FQName::valueName() const { + return mValueName; +} + +FQName FQName::typeName() const { + return FQName(mPackage, version(), mName); +} + +void FQName::applyDefaults( + const std::string &defaultPackage, + const std::string &defaultVersion) { + + // package without version is not allowed. + CHECK(mPackage.empty() || !version().empty()); + + if (mPackage.empty()) { + mPackage = defaultPackage; + } + + if (version().empty()) { + setVersion(defaultVersion); + } +} + +std::string FQName::string() const { + CHECK(mValid); + + std::string out; + out.append(mPackage); + out.append(atVersion()); + if (!mName.empty()) { + if (!mPackage.empty() || !version().empty()) { + out.append("::"); + } + out.append(mName); + + if (!mValueName.empty()) { + out.append(":"); + out.append(mValueName); + } + } + + return out; +} + +void FQName::print() const { + if (!mValid) { + LOG(INFO) << "INVALID"; + return; + } + + LOG(INFO) << string(); +} + +bool FQName::operator<(const FQName &other) const { + return string() < other.string(); +} + +bool FQName::operator==(const FQName &other) const { + return string() == other.string(); +} + +bool FQName::operator!=(const FQName &other) const { + return !(*this == other); +} + +std::string FQName::getInterfaceName() const { + CHECK(names().size() == 1) << "Must be a top level type"; + CHECK(!mName.empty() && mName[0] == 'I') << mName; + + return mName; +} + +std::string FQName::getInterfaceBaseName() const { + // cut off the leading 'I'. + return getInterfaceName().substr(1); +} + +std::string FQName::getInterfaceHwName() const { + return "IHw" + getInterfaceBaseName(); +} + +std::string FQName::getInterfaceProxyName() const { + return "BpHw" + getInterfaceBaseName(); +} + +std::string FQName::getInterfaceStubName() const { + return "BnHw" + getInterfaceBaseName(); +} + +std::string FQName::getInterfacePassthroughName() const { + return "Bs" + getInterfaceBaseName(); +} + +FQName FQName::getInterfaceProxyFqName() const { + return FQName(package(), version(), getInterfaceProxyName()); +} + +FQName FQName::getInterfaceStubFqName() const { + return FQName(package(), version(), getInterfaceStubName()); +} + +FQName FQName::getInterfacePassthroughFqName() const { + return FQName(package(), version(), getInterfacePassthroughName()); +} + +FQName FQName::getTypesForPackage() const { + return FQName(package(), version(), "types"); +} + +FQName FQName::getPackageAndVersion() const { + return FQName(package(), version(), ""); +} + +FQName FQName::getTopLevelType() const { + auto idx = mName.find('.'); + + if (idx == std::string::npos) { + return *this; + } + + return FQName(mPackage, version(), mName.substr(0, idx)); +} + +std::string FQName::tokenName() const { + std::vector<std::string> components; + getPackageAndVersionComponents(&components, true /* cpp_compatible */); + + if (!mName.empty()) { + std::vector<std::string> nameComponents; + StringHelper::SplitString(mName, '.', &nameComponents); + + components.insert(components.end(), nameComponents.begin(), nameComponents.end()); + } + + return StringHelper::JoinStrings(components, "_"); +} + +std::string FQName::cppNamespace() const { + std::vector<std::string> components; + getPackageAndVersionComponents(&components, true /* cpp_compatible */); + + std::string out = "::"; + out += StringHelper::JoinStrings(components, "::"); + + return out; +} + +std::string FQName::cppLocalName() const { + std::vector<std::string> components; + StringHelper::SplitString(mName, '.', &components); + + return StringHelper::JoinStrings(components, "::") + + (mValueName.empty() ? "" : ("::" + mValueName)); +} + +std::string FQName::cppName() const { + std::string out = cppNamespace(); + + std::vector<std::string> components; + StringHelper::SplitString(name(), '.', &components); + out += "::"; + out += StringHelper::JoinStrings(components, "::"); + if (!mValueName.empty()) { + out += "::" + mValueName; + } + + return out; +} + +std::string FQName::javaPackage() const { + std::vector<std::string> components; + getPackageAndVersionComponents(&components, true /* cpp_compatible */); + + return StringHelper::JoinStrings(components, "."); +} + +std::string FQName::javaName() const { + return javaPackage() + "." + name() + + (mValueName.empty() ? "" : ("." + mValueName)); +} + +void FQName::getPackageComponents(std::vector<std::string> *components) const { + StringHelper::SplitString(package(), '.', components); +} + +void FQName::getPackageAndVersionComponents( + std::vector<std::string> *components, + bool cpp_compatible) const { + getPackageComponents(components); + + if (!cpp_compatible) { + components->push_back(getPackageMajorVersion() + + "." + getPackageMinorVersion()); + return; + } + + components->push_back(sanitizedVersion()); +} + +std::string FQName::getPackageMajorVersion() const { + return mMajor; +} + +std::string FQName::getPackageMinorVersion() const { + return mMinor; +} + +bool FQName::endsWith(const FQName &other) const { + std::string s1 = string(); + std::string s2 = other.string(); + + size_t pos = s1.rfind(s2); + if (pos == std::string::npos || pos + s2.size() != s1.size()) { + return false; + } + + // A match is only a match if it is preceded by a "boundary", i.e. + // we perform a component-wise match from the end. + // "az" is not a match for "android.hardware.foo@1.0::IFoo.bar.baz", + // "baz", "bar.baz", "IFoo.bar.baz", "@1.0::IFoo.bar.baz" are. + if (pos == 0) { + // matches "android.hardware.foo@1.0::IFoo.bar.baz" + return true; + } + + if (s1[pos - 1] == '.') { + // matches "baz" and "bar.baz" + return true; + } + + if (s1[pos - 1] == ':') { + // matches "IFoo.bar.baz" + return true; + } + + if (s1[pos] == '@') { + // matches "@1.0::IFoo.bar.baz" + return true; + } + + return false; +} + +} // namespace android + diff --git a/utils/include/hidl-util/FQName.h b/utils/include/hidl-util/FQName.h new file mode 100644 index 00000000..28c14ff2 --- /dev/null +++ b/utils/include/hidl-util/FQName.h @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * 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. + */ + +#ifndef FQNAME_H_ + +#define FQNAME_H_ + +#include <android-base/macros.h> +#include <string> +#include <vector> + +namespace android { + +struct FQName { + explicit FQName(); + explicit FQName(const std::string &s); + + FQName(const std::string &package, + const std::string &version, + const std::string &name, + const std::string &valueName = ""); + + // a synonym to FQName(names.join(".")) + FQName(const std::vector<std::string> &names); + + FQName(const FQName& other); + + bool isValid() const; + bool isIdentifier() const; + bool setTo(const std::string &s); + + void applyDefaults( + const std::string &defaultPackage, + const std::string &defaultVersion); + + std::string package() const; + // Return version in the form "@1.0" if it is present, otherwise empty string. + std::string atVersion() const; + // Return version in the form "1.0" if it is present, otherwise empty string. + std::string version() const; + // Return version in the form "V1_0" if it is present, otherwise empty string. + std::string sanitizedVersion() const; + + // The next two methods return the name part of the FQName, that is, the + // part after the version field. For example: + // + // package android.hardware.tests.foo@1.0; + // interface IFoo { + // struct bar { + // struct baz { + // ... + // }; + // }; + // }; + // + // package android.hardware.tests.bar@1.0; + // import android.hardware.tests.foo@1.0; + // interface { + // struct boo { + // IFoo.bar.baz base; + // }; + // } + // + // The FQName for base is android.hardware.tests.foo@1.0::IFoo.bar.baz; so + // FQName::name() will return "IFoo.bar.baz". FQName::names() will return + // std::vector<std::string>{"IFoo","bar","baz"} + + std::string name() const; + std::vector<std::string> names() const; + + // The next two methods returns two parts of the FQName, that is, + // the first part package + version + name, the second part valueName. + FQName typeName() const; + std::string valueName() const; + + bool isFullyQualified() const; + + // true if: + // 1. (package)?(version)?(name):(valueName) + // 2. (valueName), aka a single identifier + bool isValidValueName() const; + + void print() const; + std::string string() const; + + bool operator<(const FQName &other) const; + bool operator==(const FQName &other) const; + bool operator!=(const FQName &other) const; + + // Must be called on an interface + // android.hardware.foo@1.0::IBar + // -> Bar + std::string getInterfaceBaseName() const; + + // Must be called on an interface + // android.hardware.foo@1.0::IBar + // -> IBar + std::string getInterfaceName() const; + + // Must be called on an interface + // android.hardware.foo@1.0::IBar + // -> IHwBar + std::string getInterfaceHwName() const; + + // Must be called on an interface + // android.hardware.foo@1.0::IBar + // -> BpBar + std::string getInterfaceProxyName() const; + + // Must be called on an interface + // android.hardware.foo@1.0::IBar + // -> BnBar + std::string getInterfaceStubName() const; + + // Must be called on an interface + // android.hardware.foo@1.0::IBar + // -> BsBar + std::string getInterfacePassthroughName() const; + + // Must be called on an interface + // android.hardware.foo@1.0::IBar + // -> android.hardware.foo@1.0::BpBar + FQName getInterfaceProxyFqName() const; + + // Must be called on an interface + // android.hardware.foo@1.0::IBar + // -> android.hardware.foo@1.0::BnBar + FQName getInterfaceStubFqName() const; + + // Must be called on an interface + // android.hardware.foo@1.0::IBar + // -> android.hardware.foo@1.0::BsBar + FQName getInterfacePassthroughFqName() const; + + // Replace whatever after :: with "types" + // android.hardware.foo@1.0::Abc.Type:VALUE + // -> android.hardware.foo@1.0::types + FQName getTypesForPackage() const; + + // android.hardware.foo@1.0::Abc.Type:VALUE + // -> android.hardware.foo@1.0 + FQName getPackageAndVersion() const; + + // the following comments all assume that the FQName + // is android.hardware.foo@1.0::IBar.Baz.Bam + + // returns highest type in the hidl namespace, i.e. + // android.hardware.foo@1.0::IBar + FQName getTopLevelType() const; + + // returns an unambiguous fully qualified name which can be + // baked into a token, i.e. + // android_hardware_Foo_V1_0_IBar_Baz + std::string tokenName() const; + + // Returns an absolute C++ namespace prefix, i.e. + // ::android::hardware::Foo::V1_0. + std::string cppNamespace() const; + + // Returns a name qualified assuming we are in cppNamespace, i.e. + // IBar::Baz. + std::string cppLocalName() const; + + // Returns a fully qualified absolute C++ type name, i.e. + // ::android::hardware::Foo::V1_0::IBar::Baz. + std::string cppName() const; + + // Returns the java package name, i.e. "android.hardware.Foo.V1_0". + std::string javaPackage() const; + + // Returns the fully qualified java type name, + // i.e. "android.hardware.Foo.V1_0.IBar.Baz" + std::string javaName() const; + + bool endsWith(const FQName &other) const; + + void getPackageComponents(std::vector<std::string> *components) const; + + void getPackageAndVersionComponents( + std::vector<std::string> *components, + bool cpp_compatible) const; + + std::string getPackageMajorVersion() const; + + std::string getPackageMinorVersion() const; + +private: + bool mValid; + bool mIsIdentifier; + std::string mPackage; + std::string mMajor; + std::string mMinor; + std::string mName; + std::string mValueName; + + void setVersion(const std::string &v); +}; + +static const FQName gIBaseFqName = FQName{"android.hidl.base@1.0::IBase"}; +static const FQName gIBasePackageFqName = FQName{"android.hidl.base@1.0"}; + +} // namespace android + +#endif // FQNAME_H_ |