Skip to content

Commit

Permalink
Add a backport of std::string_view (#13)
Browse files Browse the repository at this point in the history
* Ignore bazel files.

* Add a string_view backport.

* Add test cases for string_view.

* Update commenting.

* Add additional test assertion.

* Add substr method.

* Remove separate catch2 target.

* Add cmake build.

* Convert to gtest.

* Add gtests to cmake build.

* Remove catch tests.

* Run clang-format.

* Add missing link library.

* Add pthreads

* Reformat.
  • Loading branch information
rnburn authored Dec 17, 2019
1 parent 34988af commit b411cde
Show file tree
Hide file tree
Showing 11 changed files with 278 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,6 @@
*.exe
*.out
*.app

# Bazel files
/bazel-*
16 changes: 16 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)
25 changes: 25 additions & 0 deletions WORKSPACE
Original file line number Diff line number Diff line change
@@ -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"],
)
7 changes: 7 additions & 0 deletions api/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package(default_visibility = ["//visibility:public"])

cc_library(
name = "api",
hdrs = glob(["include/**/*.h"]),
strip_include_prefix = "include",
)
15 changes: 15 additions & 0 deletions api/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
include_directories(include)
add_library(opentelemetry_api INTERFACE)
target_include_directories(
opentelemetry_api INTERFACE include
$<INSTALL_INTERFACE:include/opentelemetry>)

install(
DIRECTORY include/opentelemetry
DESTINATION include
FILES_MATCHING
PATTERN "*.h")

if(BUILD_TESTING)
add_subdirectory(test)
endif()
124 changes: 124 additions & 0 deletions api/include/opentelemetry/nostd/string_view.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
#pragma once

#include <algorithm>
#include <cstring>
#include <ostream>
#include <stdexcept>
#include <string>

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<char> &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<std::streamsize>(s.length()));
}
} // namespace nostd
} // namespace opentelemetry
1 change: 1 addition & 0 deletions api/test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
add_subdirectory(nostd)
Empty file removed api/test/TBD
Empty file.
10 changes: 10 additions & 0 deletions api/test/nostd/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
cc_test(
name = "string_view_test",
srcs = [
"string_view_test.cc",
],
deps = [
"//api",
"@com_google_googletest//:gtest_main",
],
)
7 changes: 7 additions & 0 deletions api/test/nostd/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)
70 changes: 70 additions & 0 deletions api/test/nostd/string_view_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#include "opentelemetry/nostd/string_view.h"

#include <gtest/gtest.h>

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<std::string>(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);
}

0 comments on commit b411cde

Please sign in to comment.