diff --git a/.gitignore b/.gitignore index de186d6072..ae5b7926b2 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,6 @@ *.exe *.out *.app + +# Bazel files +/bazel-* diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000..30152db444 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.1) + +project(opentelemetry-cpp) + +set(CMAKE_CXX_STANDARD 11) + +include(CTest) + +find_package(Threads) + +if(BUILD_TESTING) + find_package(GTest REQUIRED) + include_directories(SYSTEM ${GTEST_INCLUDE_DIRS}) +endif() + +add_subdirectory(api) diff --git a/WORKSPACE b/WORKSPACE new file mode 100644 index 0000000000..83ef873ce6 --- /dev/null +++ b/WORKSPACE @@ -0,0 +1,25 @@ +# Copyright 2019, OpenTelemetry Authors +# +# 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. + +workspace(name = "io_opentelemetry_cpp") + +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +# GoogleTest framework. +# Only needed for tests, not to build the OpenTelemetry library. +http_archive( + name = "com_google_googletest", + strip_prefix = "googletest-release-1.10.0", + urls = ["https://github.com/google/googletest/archive/release-1.10.0.tar.gz"], +) diff --git a/api/BUILD b/api/BUILD new file mode 100644 index 0000000000..e2fceae4c1 --- /dev/null +++ b/api/BUILD @@ -0,0 +1,7 @@ +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "api", + hdrs = glob(["include/**/*.h"]), + strip_include_prefix = "include", +) diff --git a/api/CMakeLists.txt b/api/CMakeLists.txt new file mode 100644 index 0000000000..d40de654ed --- /dev/null +++ b/api/CMakeLists.txt @@ -0,0 +1,15 @@ +include_directories(include) +add_library(opentelemetry_api INTERFACE) +target_include_directories( + opentelemetry_api INTERFACE include + $) + +install( + DIRECTORY include/opentelemetry + DESTINATION include + FILES_MATCHING + PATTERN "*.h") + +if(BUILD_TESTING) + add_subdirectory(test) +endif() diff --git a/api/include/opentelemetry/nostd/string_view.h b/api/include/opentelemetry/nostd/string_view.h new file mode 100644 index 0000000000..037223d30d --- /dev/null +++ b/api/include/opentelemetry/nostd/string_view.h @@ -0,0 +1,124 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace opentelemetry +{ +namespace nostd +{ +/** + * Back port of std::string_view to work with pre-cpp-17 compilers. + * + * Note: This provides a subset of the methods available on std::string_view but + * tries to be as compatible as possible with the std::string_view interface. + */ +class string_view +{ +public: + static constexpr std::size_t npos = std::string::npos; + + string_view() noexcept : length_(0), data_(nullptr) {} + + string_view(const char *str) noexcept : length_(std::strlen(str)), data_(str) {} + + string_view(const std::basic_string &str) noexcept + : length_(str.length()), data_(str.c_str()) + {} + + string_view(const char *str, size_t len) noexcept : length_(len), data_(str) {} + + explicit operator std::string() const { return {data_, length_}; } + + const char *data() const noexcept { return data_; } + + bool empty() const noexcept { return length_ == 0; } + + size_t length() const noexcept { return length_; } + + size_t size() const noexcept { return length_; } + + const char *begin() const noexcept { return data(); } + + const char *end() const noexcept { return data() + length(); } + + const char &operator[](std::size_t i) { return *(data() + i); } + + string_view substr(std::size_t pos, std::size_t n = npos) const + { + if (pos > length_) + { + throw std::out_of_range{"opentelemetry::nostd::string_view"}; + } + n = (std::min)(n, length_ - pos); + return string_view(data_ + pos, n); + } + +private: + // Note: uses the same binary layout as libstdc++'s std::string_view + // See + // https://github.com/gcc-mirror/gcc/blob/e0c554e4da7310df83bb1dcc7b8e6c4c9c5a2a4f/libstdc%2B%2B-v3/include/std/string_view#L466-L467 + size_t length_; + const char *data_; +}; + +inline bool operator==(string_view lhs, string_view rhs) noexcept +{ + return lhs.length() == rhs.length() && + std::equal(lhs.data(), lhs.data() + lhs.length(), rhs.data()); +} + +inline bool operator==(string_view lhs, const std::string &rhs) noexcept +{ + return lhs == string_view(rhs); +} + +inline bool operator==(const std::string &lhs, string_view rhs) noexcept +{ + return string_view(lhs) == rhs; +} + +inline bool operator==(string_view lhs, const char *rhs) noexcept +{ + return lhs == string_view(rhs); +} + +inline bool operator==(const char *lhs, string_view rhs) noexcept +{ + return string_view(lhs) == rhs; +} + +inline bool operator!=(string_view lhs, string_view rhs) noexcept +{ + return !(lhs == rhs); +} + +inline bool operator!=(string_view lhs, const std::string &rhs) noexcept +{ + return !(lhs == rhs); +} + +inline bool operator!=(const std::string &lhs, string_view rhs) noexcept +{ + return !(lhs == rhs); +} + +inline bool operator!=(string_view lhs, const char *rhs) noexcept +{ + return !(lhs == rhs); +} + +inline bool operator!=(const char *lhs, string_view rhs) noexcept +{ + return !(lhs == rhs); +} + +inline std::ostream &operator<<(std::ostream &os, string_view s) +{ + return os.write(s.data(), static_cast(s.length())); +} +} // namespace nostd +} // namespace opentelemetry diff --git a/api/test/CMakeLists.txt b/api/test/CMakeLists.txt new file mode 100644 index 0000000000..988b463c36 --- /dev/null +++ b/api/test/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(nostd) diff --git a/api/test/TBD b/api/test/TBD deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/api/test/nostd/BUILD b/api/test/nostd/BUILD new file mode 100644 index 0000000000..fffd03468b --- /dev/null +++ b/api/test/nostd/BUILD @@ -0,0 +1,10 @@ +cc_test( + name = "string_view_test", + srcs = [ + "string_view_test.cc", + ], + deps = [ + "//api", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/api/test/nostd/CMakeLists.txt b/api/test/nostd/CMakeLists.txt new file mode 100644 index 0000000000..946ed705e7 --- /dev/null +++ b/api/test/nostd/CMakeLists.txt @@ -0,0 +1,7 @@ +include(GoogleTest) + +add_executable(string_view_test string_view_test.cc) +target_link_libraries(string_view_test ${GTEST_BOTH_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api) +gtest_add_tests(TARGET string_view_test TEST_PREFIX nostd. TEST_LIST + string_view_test) diff --git a/api/test/nostd/string_view_test.cc b/api/test/nostd/string_view_test.cc new file mode 100644 index 0000000000..10b44fc58a --- /dev/null +++ b/api/test/nostd/string_view_test.cc @@ -0,0 +1,70 @@ +#include "opentelemetry/nostd/string_view.h" + +#include + +using opentelemetry::nostd::string_view; + +TEST(StringViewTest, DefaultConstruction) +{ + string_view ref; + EXPECT_EQ(ref.data(), nullptr); + EXPECT_EQ(ref.length(), 0); +} + +TEST(StringViewTest, CStringInitialization) +{ + const char *val = "hello world"; + + string_view ref(val); + + EXPECT_EQ(ref.data(), val); + EXPECT_EQ(ref.length(), std::strlen(val)); +} + +TEST(StringViewTest, StdStringInitialization) +{ + const std::string val = "hello world"; + + string_view ref(val); + + EXPECT_EQ(ref.data(), val.data()); + EXPECT_EQ(ref.length(), val.size()); +} + +TEST(StringViewTest, Copy) +{ + const std::string val = "hello world"; + + string_view ref(val); + string_view cpy(ref); + + EXPECT_EQ(cpy.data(), val); + EXPECT_EQ(cpy.length(), val.length()); + EXPECT_EQ(cpy, val); +} + +TEST(StringViewTest, Accessor) +{ + string_view s = "abc123"; + EXPECT_EQ(s.data(), &s[0]); + EXPECT_EQ(s.data() + 1, &s[1]); +} + +TEST(StringViewTest, ExplicitStdStringConversion) +{ + std::string s = static_cast(string_view{"abc"}); + EXPECT_EQ(s, "abc"); +} + +TEST(StringViewTest, SubstrPortion) +{ + string_view s = "abc123"; + EXPECT_EQ("123", s.substr(3)); + EXPECT_EQ("12", s.substr(3, 2)); +} + +TEST(StringViewTest, SubstrOutOfRange) +{ + string_view s = "abc123"; + EXPECT_THROW(s.substr(10), std::out_of_range); +}