Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/lib/headers>
$<INSTALL_INTERFACE:include>
)

INSTALL(DIRECTORY lib/headers/ DESTINATION include)

INSTALL(TARGETS expressions
INSTALL(TARGETS zen_algorithms_expressions
EXPORT ExpressionsTargets
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
Expand All @@ -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)
Expand All @@ -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()
Expand Down
Binary file modified about.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
49 changes: 0 additions & 49 deletions lib/headers/expressions/container.hpp

This file was deleted.

37 changes: 0 additions & 37 deletions lib/headers/expressions/result.hpp

This file was deleted.

90 changes: 90 additions & 0 deletions lib/headers/zen_algorithms/expressions.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#pragma once

#include <string>
#include <utility>
#include <vector>
#include <memory>
#include <unordered_map>
#include <regex>

namespace zen_algorithms::expressions {

class expression_result : public std::enable_shared_from_this<expression_result> {
bool matches_;
std::unordered_map<std::string, std::string> bindings_;

public:
expression_result(const bool matches, const std::unordered_map<std::string, std::string> & bindings) : matches_(matches), bindings_(bindings) {}

bool matches() const { return matches_; }
std::unordered_map<std::string, std::string> 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<expression> {
std::string regex_;
std::vector<std::string> arguments_;

public:

expression(std::string regex, const std::vector<std::string> & arguments) : regex_(std::move(regex)), arguments_(arguments) {}

std::vector<std::string> get_arguments() const { return arguments_; }
std::string get_regex() const { return regex_; }

std::shared_ptr<expression_result> query(const std::string &input) const {
std::unordered_map<std::string, std::string> _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<expression_result>(_matches, _bindings);
}
};

static std::shared_ptr<expression> 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<std::string> _arguments;
std::string _regex;

if (_open == std::string::npos && _close == std::string::npos)
return std::make_shared<expression>(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<expression>(_regex, _arguments);
}

}
59 changes: 0 additions & 59 deletions lib/sources/container.cpp

This file was deleted.

3 changes: 3 additions & 0 deletions lib/sources/expressions.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#include <zen_algorithms/expressions.hpp>

namespace zen_algorithms::expressions { }
18 changes: 0 additions & 18 deletions lib/sources/result.cpp

This file was deleted.

35 changes: 18 additions & 17 deletions tests/implementation_test.cc
Original file line number Diff line number Diff line change
@@ -1,27 +1,28 @@
#include <gtest/gtest.h>
#include <expressions/container.hpp>
#include <zen_algorithms/expressions.hpp>

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");
}