Merge branch 'mattyclarkson-regex'

This commit is contained in:
Dominic Hamon 2014-08-22 11:31:03 -07:00
commit cfb34b5957
11 changed files with 205 additions and 26 deletions

View File

@ -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)

View File

@ -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(<FLAG> [<VARIANT>])
# add_cxx_compiler_flag(<FLAG> [<VARIANT>])
#
# - 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()

View File

@ -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(<FLAG> [<VARIANT>])
#
# - 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()

12
cmake/gnu_posix_regex.cpp Normal file
View File

@ -0,0 +1,12 @@
#include <gnuregex.h>
#include <string>
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;
}

12
cmake/posix_regex.cpp Normal file
View File

@ -0,0 +1,12 @@
#include <regex.h>
#include <string>
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;
}

8
cmake/std_regex.cpp Normal file
View File

@ -0,0 +1,8 @@
#include <regex>
#include <string>
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;
}

View File

@ -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}

View File

@ -15,10 +15,14 @@
#ifndef BENCHMARK_RE_H_
#define BENCHMARK_RE_H_
#if defined OS_FREEBSD
#if defined(HAVE_STD_REGEX)
#include <regex>
#elif defined(HAVE_GNU_POSIX_REGEX)
#include <gnuregex.h>
#else
#elif defined(HAVE_POSIX_REGEX)
#include <regex.h>
#else
#error No regular expression backend was found!
#endif
#include <string>
@ -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

45
src/re_std.cc Normal file
View File

@ -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 <benchmark/macros.h>
#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

View File

@ -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));