diff --git a/CMakeLists.txt b/CMakeLists.txt index 6c7e374..c46ddde 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,16 +13,16 @@ INCLUDE_DIRECTORIES(lib/headers) FILE(GLOB_RECURSE SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/lib/sources/*.cpp") FILE(GLOB_RECURSE TESTS CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/tests/*.cc") -ADD_LIBRARY(expressions STATIC ${SOURCES}) +ADD_LIBRARY(zen_algorithms_expressions STATIC ${SOURCES}) -TARGET_INCLUDE_DIRECTORIES(expressions PUBLIC +TARGET_INCLUDE_DIRECTORIES(zen_algorithms_expressions PUBLIC $ $ ) INSTALL(DIRECTORY lib/headers/ DESTINATION include) -INSTALL(TARGETS expressions +INSTALL(TARGETS zen_algorithms_expressions EXPORT ExpressionsTargets LIBRARY DESTINATION lib ARCHIVE DESTINATION lib @@ -32,22 +32,30 @@ INSTALL(TARGETS expressions INSTALL(EXPORT ExpressionsTargets FILE ExpressionsTargets.cmake - NAMESPACE expressions:: - DESTINATION lib/cmake/Expressions + NAMESPACE zen_algorithms:: + DESTINATION lib/cmake/ZenAlgorithms ) INCLUDE(CMakePackageConfigHelpers) CONFIGURE_PACKAGE_CONFIG_FILE( cmake/ExpressionsConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/ExpressionsConfig.cmake - INSTALL_DESTINATION lib/cmake/Expressions + INSTALL_DESTINATION lib/cmake/ZenAlgorithms ) INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/ExpressionsConfig.cmake - DESTINATION lib/cmake/Expressions + DESTINATION lib/cmake/ZenAlgorithms ) +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif() + +set(CMAKE_CXX_FLAGS "-Wall -Wextra") +set(CMAKE_CXX_FLAGS_DEBUG "-g") +set(CMAKE_CXX_FLAGS_RELEASE "-O3") + SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin) if (BUILD_TESTS) @@ -59,7 +67,7 @@ if (BUILD_TESTS) FETCHCONTENT_MAKEAVAILABLE(googletest) ENABLE_TESTING() ADD_EXECUTABLE(tests ${TESTS} ${SOURCES}) - TARGET_LINK_LIBRARIES(tests GTest::gtest_main) + TARGET_LINK_LIBRARIES(tests GTest::gtest_main zen_algorithms_expressions) INCLUDE(GoogleTest) GTEST_DISCOVER_TESTS(tests) endif() diff --git a/about.png b/about.png index b1dc22c..b66301a 100644 Binary files a/about.png and b/about.png differ diff --git a/lib/headers/expressions/container.hpp b/lib/headers/expressions/container.hpp deleted file mode 100644 index e555821..0000000 --- a/lib/headers/expressions/container.hpp +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include - -namespace expressions { - struct container { - std::string regex_; - std::vector arguments_{}; - - /** - * Get the regex - * - * @return std::string - */ - std::string - get_regex() const; - - /** - * Get the arguments - * - * @return std::vector - */ - std::vector - get_arguments() const; - - /** - * Query the expression - * - * @param input - * @return - */ - result - query(const std::string &input) const; - - /** - * Creates a expression from strings - * - * @param input - * @return std::shared_ptr - */ - static container - from_string(const std::string &input); - }; -} diff --git a/lib/headers/expressions/result.hpp b/lib/headers/expressions/result.hpp deleted file mode 100644 index e62711a..0000000 --- a/lib/headers/expressions/result.hpp +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace expressions { - struct result { - bool _matches = false; - std::unordered_map _bindings; - - /** - * Get matches - * - * @return - */ - bool - matches() const; - - /** - * Get bindings - * - * @return - */ - std::unordered_map - bindings() const; - - /** - * Get parameter - * - * @param name - * @return - */ - std::string - get(const std::string & name) const; - }; -} diff --git a/lib/headers/zen_algorithms/expressions.hpp b/lib/headers/zen_algorithms/expressions.hpp new file mode 100644 index 0000000..9f28c6b --- /dev/null +++ b/lib/headers/zen_algorithms/expressions.hpp @@ -0,0 +1,90 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace zen_algorithms::expressions { + + class expression_result : public std::enable_shared_from_this { + bool matches_; + std::unordered_map bindings_; + + public: + expression_result(const bool matches, const std::unordered_map & bindings) : matches_(matches), bindings_(bindings) {} + + bool matches() const { return matches_; } + std::unordered_map get_bindings() const { return bindings_; } + + std::string get(const std::string &name) const { + if (bindings_.contains(name)) + return bindings_.at(name); + throw std::runtime_error("The provided argument doesn't exists"); + } + }; + + class expression : public std::enable_shared_from_this { + std::string regex_; + std::vector arguments_; + + public: + + expression(std::string regex, const std::vector & arguments) : regex_(std::move(regex)), arguments_(arguments) {} + + std::vector get_arguments() const { return arguments_; } + std::string get_regex() const { return regex_; } + + std::shared_ptr query(const std::string &input) const { + std::unordered_map _bindings; + const std::regex _pattern(regex_); + bool _matches = false; + if (std::smatch _match; std::regex_match(input, _match, _pattern)) { + _matches = true; + auto _iterator = _match.begin(); + ++_iterator; + for (auto &_key: arguments_) { + _bindings[_key] = *_iterator; + ++_iterator; + } + } + return std::make_shared(_matches, _bindings); + } + }; + + static std::shared_ptr from_string(const std::string &input) { + std::size_t _open = input.find('{'); + std::size_t _close = input.find('}'); + std::size_t _position = 0; + + std::vector _arguments; + std::string _regex; + + if (_open == std::string::npos && _close == std::string::npos) + return std::make_shared(input, _arguments); + + while (_open != std::string::npos && _close != std::string::npos) { + _regex.append(input.substr(_position, _open - _position)); + std::string _value{input.substr(_open + 1, _close - _open - 1)}; + + if (std::find(_arguments.begin(), _arguments.end(), _value) != _arguments.end()) + throw std::runtime_error("The provided input contains repeated arguments."); + + _regex.append(R"(([a-zA-Z0-9\-_]+))"); + _arguments.emplace_back(_value); + + _position = _close + 1; + _open = input.find('{', _close); + _close = input.find('}', _open); + } + + if (_position != input.size()) + _regex.append(input.substr(_position, input.size() - _position)); + + + return std::make_shared(_regex, _arguments); + } + +} \ No newline at end of file diff --git a/lib/sources/container.cpp b/lib/sources/container.cpp deleted file mode 100644 index c8fcb80..0000000 --- a/lib/sources/container.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include - -namespace expressions { - std::string container::get_regex() const { - return regex_; - } - - std::vector container::get_arguments() const { - return arguments_; - } - - result container::query(const std::string &input) const { - std::unordered_map _bindings; - const std::regex _pattern(regex_); - bool _matches = false; - if (std::smatch _match; std::regex_match(input, _match, _pattern)) { - _matches = true; - auto _iterator = _match.begin(); - ++_iterator; - for (auto &_key: arguments_) { - _bindings[_key] = *_iterator; - ++_iterator; - } - } - return { ._matches = _matches, ._bindings = _bindings }; - } - - container container::from_string(const std::string &input) { - std::size_t _open = input.find('{'); - std::size_t _close = input.find('}'); - std::size_t _position = 0; - - std::vector _arguments; - std::string _regex; - - if (_open == std::string::npos && _close == std::string::npos) - return { .regex_ = std::string{ input }, .arguments_ = _arguments }; - - while (_open != std::string::npos && _close != std::string::npos) { - _regex.append(input.substr(_position, _open - _position)); - std::string _value{input.substr(_open + 1, _close - _open - 1)}; - - if (std::find(_arguments.begin(), _arguments.end(), _value) != _arguments.end()) - throw std::runtime_error("The provided input contains repeated arguments."); - - _regex.append(R"(([a-zA-Z0-9\-_]+))"); - _arguments.emplace_back(_value); - - _position = _close + 1; - _open = input.find('{', _close); - _close = input.find('}', _open); - } - - if (_position != input.size()) - _regex.append(input.substr(_position, input.size() - _position)); - - return { .regex_ = _regex , .arguments_ = _arguments }; - } -} diff --git a/lib/sources/expressions.cpp b/lib/sources/expressions.cpp new file mode 100644 index 0000000..eb568eb --- /dev/null +++ b/lib/sources/expressions.cpp @@ -0,0 +1,3 @@ +#include + +namespace zen_algorithms::expressions { } diff --git a/lib/sources/result.cpp b/lib/sources/result.cpp deleted file mode 100644 index 752148a..0000000 --- a/lib/sources/result.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include - -namespace expressions { - bool result::matches() const { - return _matches; - } - - std::unordered_map result::bindings() const { - return _bindings; - } - - std::string - result::get(const std::string &name) const { - if (_bindings.contains(name)) - return _bindings.at(name); - throw std::runtime_error("The provided argument doesn't exists"); - } -} diff --git a/tests/implementation_test.cc b/tests/implementation_test.cc index d9cc5dc..02f5f07 100644 --- a/tests/implementation_test.cc +++ b/tests/implementation_test.cc @@ -1,27 +1,28 @@ #include -#include +#include TEST(Expressions, Assertions) { - using namespace expressions; + using namespace zen_algorithms; - const auto _non_empty_expression = container::from_string("/users/{user}/details"); + const auto _expression = expressions::from_string("/users/{user}/details"); - ASSERT_FALSE(_non_empty_expression.get_arguments().empty()); - ASSERT_EQ(_non_empty_expression.get_arguments().size(), 1); - ASSERT_EQ(_non_empty_expression.get_arguments().at(0), "user"); + ASSERT_FALSE(_expression->get_arguments().empty()); + ASSERT_EQ(_expression->get_arguments().size(), 1); + ASSERT_EQ(_expression->get_arguments().at(0), "user"); - const auto _empty_expression = container::from_string("/ping"); - ASSERT_TRUE(_empty_expression.get_arguments().empty()); - ASSERT_EQ(_empty_expression.get_regex(), "/ping"); - const auto _non_empty_string_expression_result = _non_empty_expression.query("/users/80bdc6d1-524e-411a-b316-976a65a3ed3c/details"); + const auto _empty_expression = expressions::from_string("/ping"); + ASSERT_TRUE(_empty_expression->get_arguments().empty()); + ASSERT_EQ(_empty_expression->get_regex(), "/ping"); - ASSERT_TRUE(_non_empty_string_expression_result.matches()); - ASSERT_FALSE(_non_empty_string_expression_result.bindings().empty()); - ASSERT_EQ(_non_empty_string_expression_result.get("user"), "80bdc6d1-524e-411a-b316-976a65a3ed3c"); + const auto _non_empty_string_expression_result = _expression->query("/users/80bdc6d1-524e-411a-b316-976a65a3ed3c/details"); - const auto _non_empty_integer_expression_result = _non_empty_expression.query("/users/1337/details"); - ASSERT_TRUE(_non_empty_integer_expression_result.matches()); - ASSERT_FALSE(_non_empty_integer_expression_result.bindings().empty()); - ASSERT_EQ(_non_empty_integer_expression_result.get("user"), "1337"); + ASSERT_TRUE(_non_empty_string_expression_result->matches()); + ASSERT_FALSE(_non_empty_string_expression_result->get_bindings().empty()); + ASSERT_EQ(_non_empty_string_expression_result->get("user"), "80bdc6d1-524e-411a-b316-976a65a3ed3c"); + + const auto _non_empty_integer_expression_result = _expression->query("/users/1337/details"); + ASSERT_TRUE(_non_empty_integer_expression_result->matches()); + ASSERT_FALSE(_non_empty_integer_expression_result->get_bindings().empty()); + ASSERT_EQ(_non_empty_integer_expression_result->get("user"), "1337"); }