diff --git a/CMakeLists.txt b/CMakeLists.txt index c4fa73aa..340055ce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,18 +4,18 @@ project (benchmark) # Make sure we can import out CMake functions list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") -# We need threads in this project +# Resolve dependent packages find_package(Threads REQUIRED) # Import and build Google Test include(ExternalProject) set_directory_properties(properties EP_PREFIX "${CMAKE_BINARY_DIR}/third_party") ExternalProject_Add(googletest - URL "https://googletest.googlecode.com/files/gtest-1.7.0.zip" - URL_MD5 2d6ec8ccdf5c46b05ba54a9fd1d130d7 - SOURCE_DIR "${CMAKE_BINARY_DIR}/third_party/gtest" - CMAKE_ARGS "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" - INSTALL_COMMAND "") + URL "https://googletest.googlecode.com/files/gtest-1.7.0.zip" + URL_MD5 2d6ec8ccdf5c46b05ba54a9fd1d130d7 + SOURCE_DIR "${CMAKE_BINARY_DIR}/third_party/gtest" + CMAKE_ARGS "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" + INSTALL_COMMAND "") ExternalProject_Get_Property(googletest source_dir) include_directories(${source_dir}/include) ExternalProject_Get_Property(googletest binary_dir) @@ -49,20 +49,20 @@ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG") # Set OS if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - add_definitions(-DOS_MACOSX) + add_definitions(-DOS_MACOSX) endif() if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") - add_definitions(-DOS_LINUX) + add_definitions(-DOS_LINUX) endif() if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") - add_definitions(-DOS_WINDOWS) + add_definitions(-DOS_WINDOWS) endif() # Set CPU if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "x86") - add_definitions(-DARCH_X86) + add_definitions(-DARCH_X86) endif() # Read the git tags to determine the project version @@ -77,6 +77,12 @@ message("-- Version: ${VERSION}") set(GENERIC_LIB_VERSION ${VERSION}) string(SUBSTRING ${VERSION} 0 1 GENERIC_LIB_SOVERSION) +# C++ feature checks +include(CXXFeatureCheck) +cxx_feature_check(STD_REGEX) +cxx_feature_check(GNU_POSIX_REGEX) +cxx_feature_check(POSIX_REGEX) + # Set up directories include_directories(${PROJECT_SOURCE_DIR}/include) include_directories(${PROJECT_SOURCE_DIR}/src) diff --git a/cmake/AddCXXCompilerFlag.cmake b/cmake/AddCXXCompilerFlag.cmake index d4a2de05..e52c1848 100644 --- a/cmake/AddCXXCompilerFlag.cmake +++ b/cmake/AddCXXCompilerFlag.cmake @@ -1,21 +1,21 @@ -# - Adds a compiler FLAG if it is supported by the compiler +# - Adds a compiler flag if it is supported by the compiler # -# This function checks that the supplied compiler FLAG is supported and then -# adds it to the corresponding compiler FLAGs +# This function checks that the supplied compiler flag is supported and then +# adds it to the corresponding compiler flags # -# add_cxx_compiler_FLAG( []) +# add_cxx_compiler_flag( []) # # - Example # # include(AddCXXCompilerFlag) -# add_cxx_compiler_FLAG(-Wall) -# add_cxx_compiler_FLAG(-no-strict-aliasing RELEASE) +# add_cxx_compiler_flag(-Wall) +# add_cxx_compiler_flag(-no-strict-aliasing RELEASE) # Requires CMake 2.6+ -if(__add_cxx_compiler_FLAG) +if(__add_cxx_compiler_flag) return() endif() -set(__add_cxx_compiler_FLAG INCLUDED) +set(__add_cxx_compiler_flag INCLUDED) include(CheckCXXCompilerFlag) @@ -25,13 +25,12 @@ function(add_cxx_compiler_flag FLAG) string(TOLOWER ${VARIANT} VARIANT) set(VARIANT " ${VARIANT}") endif() - message("-- Check compiler${VARIANT} flag ${FLAG}") - string(TOUPPER ${FLAG} SANITIZED_FLAG) - string(REGEX REPLACE "[^A-Za-z_0-9]" "_" ${SANITIZED_FLAG} SANITIZED_FLAG) + string(TOUPPER "HAVE_${FLAG}" SANITIZED_FLAG) + string(REGEX REPLACE "[^A-Za-z_0-9]" "_" SANITIZED_FLAG ${SANITIZED_FLAG}) + string(REGEX REPLACE "_+" "_" SANITIZED_FLAG ${SANITIZED_FLAG}) check_cxx_compiler_flag(${FLAG} ${SANITIZED_FLAG}) if(${SANITIZED_FLAG}) - message("-- Check compiler${VARIANT} flag ${FLAG} -- works") - string(REGEX REPLACE "[^A-Za-z_0-9]" "_" "${VARIANT}" VARIANT) + string(REGEX REPLACE "[^A-Za-z_0-9]" "_" VARIANT "${VARIANT}") string(TOUPPER "${VARIANT}" VARIANT) set(CMAKE_CXX_FLAGS${VARIANT} "${CMAKE_CXX_FLAGS}${VARIANT} ${FLAG}" PARENT_SCOPE) endif() diff --git a/cmake/CXXFeatureCheck.cmake b/cmake/CXXFeatureCheck.cmake new file mode 100644 index 00000000..7adebcac --- /dev/null +++ b/cmake/CXXFeatureCheck.cmake @@ -0,0 +1,34 @@ +# - Compile and run code to check for C++ features +# +# This functions compiles a source file under the `cmake` folder +# and adds the corresponding `HAVE_[FILENAME]` flag to the CMake +# environment +# +# cxx_feature_check( []) +# +# - Example +# +# include(CXXFeatureCheck) +# cxx_feature_check(STD_REGEX) +# Requires CMake 2.6+ + +if(__cxx_feature_check) + return() +endif() +set(__cxx_feature_check INCLUDED) + +function(cxx_feature_check FILE) + string(TOLOWER ${FILE} FILE) + string(TOUPPER ${FILE} VAR) + string(TOUPPER "HAVE_${VAR}" FEATURE) + message("-- Performing Test ${FEATURE}") + try_run(RUN_${FEATURE} COMPILE_${FEATURE} ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/${FILE}.cpp) + if(RUN_${FEATURE} EQUAL 0) + message("-- Performing Test ${FEATURE} -- Success") + set(HAVE_${VAR} 1 PARENT_SCOPE) + add_definitions(-DHAVE_${VAR}) + else() + message("-- Performing Test ${FEATURE} -- Failed") + endif() +endfunction() + diff --git a/cmake/gnu_posix_regex.cpp b/cmake/gnu_posix_regex.cpp new file mode 100644 index 00000000..480ab25c --- /dev/null +++ b/cmake/gnu_posix_regex.cpp @@ -0,0 +1,12 @@ +#include +#include +int main() { + std::string str = "test0159"; + regex_t re; + int ec = regcomp(&re, "^[a-z]+[0-9]+$", REG_EXTENDED | REG_NOSUB); + if (ec != 0) { + return ec; + } + return regexec(&re, str.c_str(), 0, NULL, 0) ? -1 : 0; +} + diff --git a/cmake/posix_regex.cpp b/cmake/posix_regex.cpp new file mode 100644 index 00000000..1f7fe07e --- /dev/null +++ b/cmake/posix_regex.cpp @@ -0,0 +1,12 @@ +#include +#include +int main() { + std::string str = "test0159"; + regex_t re; + int ec = regcomp(&re, "^[a-z]+[0-9]+$", REG_EXTENDED | REG_NOSUB); + if (ec != 0) { + return ec; + } + return regexec(&re, str.c_str(), 0, NULL, 0) ? -1 : 0; +} + diff --git a/cmake/std_regex.cpp b/cmake/std_regex.cpp new file mode 100644 index 00000000..4f227d44 --- /dev/null +++ b/cmake/std_regex.cpp @@ -0,0 +1,8 @@ +#include +#include +int main() { + const std::string str = "test0159"; + const std::regex re("^[a-z]+[0-9]+$", std::regex_constants::extended | std::regex_constants::nosubs); + return std::regex_search(str, re) ? 0 : -1; +} + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a2afb0cb..fd3bfc73 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,12 +1,25 @@ +# Define the source files set(SOURCE_FILES "benchmark.cc" "colorprint.cc" "commandlineflags.cc" "sleep.cc" "sysinfo.cc" "walltime.cc") -set(RE_FILES "re.cc") +# Determine the correct regular expression engine to use +if(HAVE_STD_REGEX) + set(RE_FILES "re_std.cc") +elseif(HAVE_GNU_POSIX_REGEX) + set(RE_FILES "re_posix.cc") +elseif(HAVE_POSIX_REGEX) + set(RE_FILES "re_posix.cc") +else() + message(FATAL_ERROR "Failed to determine the source files for the regular expression backend") +endif() + +# Build a regular expression library add_library(benchmark_re ${RE_FILES}) set_target_properties(benchmark_re PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION ${GENERIC_LIB_SOVERSION} ) +# Build the benchmark library add_library(benchmark ${SOURCE_FILES} ${RE_FILES}) set_target_properties(benchmark PROPERTIES VERSION ${GENERIC_LIB_VERSION} diff --git a/src/re.h b/src/re.h index b179bb2a..a2e9fdfd 100644 --- a/src/re.h +++ b/src/re.h @@ -15,10 +15,14 @@ #ifndef BENCHMARK_RE_H_ #define BENCHMARK_RE_H_ -#if defined OS_FREEBSD +#if defined(HAVE_STD_REGEX) +#include +#elif defined(HAVE_GNU_POSIX_REGEX) #include -#else +#elif defined(HAVE_POSIX_REGEX) #include +#else +#error No regular expression backend was found! #endif #include @@ -42,7 +46,13 @@ class Regex { private: bool init_; // Underlying regular expression object +#if defined(HAVE_STD_REGEX) + std::regex re_; +#elif defined(HAVE_POSIX_REGEX) || defined(HAVE_GNU_POSIX_REGEX) regex_t re_; +#else +# error No regular expression backend implementation available +#endif }; } // end namespace benchmark diff --git a/src/re.cc b/src/re_posix.cc similarity index 100% rename from src/re.cc rename to src/re_posix.cc diff --git a/src/re_std.cc b/src/re_std.cc new file mode 100644 index 00000000..30883fda --- /dev/null +++ b/src/re_std.cc @@ -0,0 +1,45 @@ +// Copyright 2014 Google Inc. 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. + +#include +#include "re.h" + +namespace benchmark { + +Regex::Regex() : init_(false) { } + +bool Regex::Init(const std::string& spec, std::string* error) { + try { + re_ = std::regex(spec, std::regex_constants::extended); + + init_ = true; + } catch (const std::regex_error& e) { + if (error) { + *error = e.what(); + } + } + return init_; +} + +Regex::~Regex() { } + +bool Regex::Match(const std::string& str) { + if (!init_) { + return false; + } + + return std::regex_search(str, re_); +} + +} // end namespace benchmark diff --git a/test/re_test.cc b/test/re_test.cc index c5ff9aa6..3bfac830 100644 --- a/test/re_test.cc +++ b/test/re_test.cc @@ -22,9 +22,49 @@ TEST(Regex, RegexSimple) { EXPECT_FALSE(re.Match("")); EXPECT_TRUE(re.Match("a")); EXPECT_TRUE(re.Match("aa")); + EXPECT_TRUE(re.Match("baa")); EXPECT_FALSE(re.Match("b")); } +TEST(Regex, RegexWildcard) { + benchmark::Regex re; + EXPECT_TRUE(re.Init("^a*$", NULL)); + + EXPECT_TRUE(re.Match("")); + EXPECT_TRUE(re.Match("a")); + EXPECT_TRUE(re.Match("aa")); + EXPECT_FALSE(re.Match("baa")); + EXPECT_FALSE(re.Match("b")); +} + +TEST(Regex, RegexAny) { + benchmark::Regex re; + EXPECT_TRUE(re.Init(".", NULL)); + + EXPECT_FALSE(re.Match("")); + EXPECT_TRUE(re.Match("a")); + EXPECT_TRUE(re.Match("aa")); +} + +TEST(Regex, RegexExact) { + benchmark::Regex re; + EXPECT_TRUE(re.Init("^.$", NULL)); + + EXPECT_FALSE(re.Match("")); + EXPECT_TRUE(re.Match("a")); + EXPECT_FALSE(re.Match("aa")); +} + +TEST(Regex, RegexComplicated) { + benchmark::Regex re; + EXPECT_TRUE(re.Init("([0-9]+ )?(mon|low)key(s)?", NULL)); + + EXPECT_TRUE(re.Match("something monkey hands")); + EXPECT_TRUE(re.Match("1 lowkey")); + EXPECT_TRUE(re.Match("19 monkeys")); + EXPECT_FALSE(re.Match("09 a")); +} + TEST(Regex, InvalidNoErrorMessage) { benchmark::Regex re; EXPECT_FALSE(re.Init("[", NULL));