├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── cmake └── modules │ └── Findasio.cmake ├── include └── tip │ └── db │ ├── CMakeLists.txt │ ├── pg.hpp │ └── pg │ ├── asio_config.hpp │ ├── common.hpp │ ├── database.hpp │ ├── datatype_mapping.hpp │ ├── detail │ ├── array_tokenizer.hpp │ ├── data_iterator.hpp │ ├── protocol_parsers.hpp │ └── tokenizer_base.hpp │ ├── error.hpp │ ├── future_config.hpp │ ├── io │ ├── array.hpp │ ├── boost_date_time.hpp │ ├── bytea.hpp │ ├── container_to_array.hpp │ ├── ip_address.hpp │ ├── set.hpp │ ├── uuid.hpp │ └── vector.hpp │ ├── pg_types.hpp │ ├── protocol_io_traits.hpp │ ├── protocol_io_traits.inl │ ├── query.hpp │ ├── query.inl │ ├── resultset.hpp │ ├── resultset.inl │ ├── sqlstates.hpp │ └── transaction.hpp ├── lib ├── afsm │ ├── .gitignore │ ├── CMakeLists.txt │ ├── LICENSE │ ├── README.md │ ├── benchmark │ │ ├── CMakeLists.txt │ │ ├── defer_benchmark.cpp │ │ ├── vending_benchmark.cpp │ │ ├── vending_machine_msm.hpp │ │ ├── vending_msm_benchmark.cpp │ │ └── vending_msm_test.cpp │ ├── cmake │ │ ├── CMakeLists.txt │ │ ├── FindAFSM.cmake │ │ └── modules │ │ │ └── FindGBenchmark.cmake │ ├── examples │ │ ├── CMakeLists.txt │ │ ├── minimal.cpp │ │ ├── minimal_actions.cpp │ │ ├── minimal_entry_exit.cpp │ │ ├── pausing.cpp │ │ ├── vending.cpp │ │ ├── vending_machine.hpp │ │ ├── vending_nested_sm.cpp │ │ └── vending_starter.cpp │ ├── include │ │ ├── CMakeLists.txt │ │ └── afsm │ │ │ ├── definition.hpp │ │ │ ├── definition_fwd.hpp │ │ │ ├── detail │ │ │ ├── actions.hpp │ │ │ ├── base_states.hpp │ │ │ ├── debug_io.hpp │ │ │ ├── def_traits.hpp │ │ │ ├── event_identity.hpp │ │ │ ├── exception_safety_guarantees.hpp │ │ │ ├── helpers.hpp │ │ │ ├── observer.hpp │ │ │ ├── orthogonal_regions.hpp │ │ │ ├── reject_policies.hpp │ │ │ ├── tags.hpp │ │ │ └── transitions.hpp │ │ │ ├── fsm.hpp │ │ │ └── fsm_fwd.hpp │ ├── lib │ │ ├── ansi-colors │ │ │ ├── .gitignore │ │ │ ├── CMakeLists.txt │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── example │ │ │ │ ├── CMakeLists.txt │ │ │ │ └── ansi_colors_example.cpp │ │ │ ├── include │ │ │ │ └── pushkin │ │ │ │ │ └── ansi_colors.hpp │ │ │ └── src │ │ │ │ ├── CMakeLists.txt │ │ │ │ └── ansi_colors.cpp │ │ └── meta │ │ │ ├── .gitignore │ │ │ ├── CMakeLists.txt │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── cmake │ │ │ ├── CMakeLists.txt │ │ │ └── FindMetaPushkin.cmake │ │ │ ├── include │ │ │ ├── CMakeLists.txt │ │ │ └── pushkin │ │ │ │ ├── meta.hpp │ │ │ │ ├── meta │ │ │ │ ├── algorithm.hpp │ │ │ │ ├── callable.hpp │ │ │ │ ├── function_traits.hpp │ │ │ │ ├── functions.hpp │ │ │ │ ├── index_tuple.hpp │ │ │ │ ├── nth_type.hpp │ │ │ │ ├── type_map.hpp │ │ │ │ └── type_tuple.hpp │ │ │ │ └── util │ │ │ │ └── demangle.hpp │ │ │ └── test │ │ │ ├── CMakeLists.txt │ │ │ ├── cmake │ │ │ └── CMakeLists.txt │ │ │ └── static_tests.cpp │ └── test │ │ ├── CMakeLists.txt │ │ ├── cmake │ │ └── CMakeLists.txt │ │ ├── common_base_test.cpp │ │ ├── fsm_parts_test.cpp │ │ ├── orthogonal_states_test.cpp │ │ ├── pushdown_tests.cpp │ │ ├── state_machine_with_internal_transitions.cpp │ │ ├── static_tests.cpp │ │ ├── test_observer.hpp │ │ ├── transaction_common.hpp │ │ ├── transaction_fsm.cpp │ │ ├── transaction_priority_fsm.cpp │ │ └── vending_machine_test.cpp ├── asio-fiber │ ├── .gitignore │ ├── CMakeLists.txt │ ├── LICENSE │ ├── README.md │ └── include │ │ └── pushkin │ │ └── asio │ │ ├── asio_config.hpp │ │ ├── async_ops.hpp │ │ ├── async_ssl_ops.hpp │ │ ├── fiber │ │ ├── detail │ │ │ └── yield.hpp │ │ ├── round_robin.hpp │ │ ├── shared_work.hpp │ │ └── yield.hpp │ │ ├── fibers.hpp │ │ └── wait.hpp ├── log │ ├── .gitignore │ ├── CMakeLists.txt │ ├── LICENSE │ ├── README.md │ ├── include │ │ └── pushkin │ │ │ ├── CMakeLists.txt │ │ │ ├── log.hpp │ │ │ └── log │ │ │ ├── ansi_colors.hpp │ │ │ └── stream_redirect.hpp │ └── src │ │ ├── CMakeLists.txt │ │ ├── ansi_colors.cpp │ │ └── log.cpp └── util │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ └── include │ └── tip │ └── util │ ├── CMakeLists.txt │ ├── endian.hpp │ ├── meta_helpers.hpp │ └── streambuf.hpp ├── pg_async.doxyfile ├── src └── tip │ └── db │ └── pg │ ├── CMakeLists.txt │ ├── common.cpp │ ├── database.cpp │ ├── detail │ ├── basic_connection.cpp │ ├── basic_connection.hpp │ ├── connection_fsm.hpp │ ├── connection_observer.hpp │ ├── connection_pool.cpp │ ├── connection_pool.hpp │ ├── database_impl.cpp │ ├── database_impl.hpp │ ├── md5.cpp │ ├── md5.hpp │ ├── protocol.cpp │ ├── protocol.hpp │ ├── protocol_parsers.cpp │ ├── result_impl.cpp │ ├── result_impl.hpp │ ├── transport.cpp │ └── transport.hpp │ ├── error.cpp │ ├── log.hpp │ ├── log_config.in.hpp │ ├── null_logger.hpp │ ├── pg_types.cpp │ ├── protocol_io_traits.cpp │ ├── query.cpp │ ├── resultset.cpp │ ├── sqlstates.cpp │ ├── transaction.cpp │ └── version.in.hpp └── test ├── CMakeLists.txt └── db ├── CMakeLists.txt ├── array_support_test.cpp ├── config.in.hpp ├── db_io_tests.cpp ├── errors_tests.cpp ├── extended_query_mode.cpp ├── fiber_query_test.cpp ├── fsm_tests.cpp ├── internals_tests.cpp ├── query_tests.cpp ├── results-parse-test.sql ├── test-environment.cpp ├── test-environment.hpp ├── test_main.cpp ├── timestamp_io_test.cpp └── uuid_io_test.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | 30 | # Build trees 31 | *build 32 | 33 | # Eclipse files 34 | *.settings 35 | .project 36 | .cproject 37 | 38 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMakeLists.txt for pg_async library 2 | # 3 | # @author zmij 4 | # @date Jul 18, 2015 5 | 6 | cmake_minimum_required(VERSION 2.6) 7 | 8 | if (NOT PROJECT_PREFIX) 9 | set(PROJECT_PREFIX tip) 10 | endif() 11 | 12 | if (PROJECT_VERSION) 13 | # Built as a subproject 14 | set(_pversion ${PROJECT_VERSION}) 15 | else() 16 | set(_pversion 1.0.0) 17 | endif() 18 | 19 | set(_pname ${PROJECT_PREFIX}-pg-async) 20 | 21 | if (${CMAKE_VERSION} VERSION_GREATER "3.0") 22 | cmake_policy(SET CMP0048 NEW) 23 | project(${_pname} VERSION ${_pversion}) 24 | else() 25 | project(${_pname}) 26 | set(PROJECT_VERSION ${_pversion}) 27 | endif() 28 | 29 | option(USE_TIP_LOG "Use tip::log logger library" OFF) 30 | option(BUILD_TESTS "Build tests for the library" OFF) 31 | option(USE_BOOST_ASIO "Use Boost.Asio instead of Standalone Asio library" ON) 32 | option(WITH_BOOST_FIBER "Build wire with boost::fiber support" OFF) 33 | 34 | # Dependencies 35 | set( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} 36 | "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules" 37 | "${CMAKE_CURRENT_SOURCE_DIR}/lib/afsm/cmake" 38 | "${CMAKE_CURRENT_SOURCE_DIR}/lib/afsm/lib/meta/cmake") 39 | 40 | set(BOOST_COMPONENTS 41 | system 42 | thread 43 | ) 44 | set(BOOST_VERSION 1.58) 45 | if (WITH_BOOST_FIBER) 46 | set(BOOST_VERSION 1.61) # Boost.Fiber was introduced in version 1.61 47 | list(APPEND BOOST_COMPONENTS context fiber) 48 | endif() 49 | 50 | find_package(Boost ${BOOST_VERSION} COMPONENTS ${BOOST_COMPONENTS} REQUIRED) 51 | set( 52 | ASIO_LIBRARIES 53 | ${Boost_SYSTEM_LIBRARIES} 54 | ${Boost_THREAD_LIBRARIES} 55 | ) 56 | add_definitions(-DWITH_BOOST_ASIO) 57 | 58 | if(WITH_BOOST_FIBER) 59 | set(FIBER_LIBS 60 | ${Boost_CONTEXT_LIBRARIES} 61 | ${Boost_FIBER_LIBRARIES} 62 | ) 63 | endif() 64 | 65 | find_package(Threads REQUIRED) 66 | find_package(AFSM) 67 | 68 | add_definitions("-std=c++11") 69 | 70 | if(USE_TIP_LOG) 71 | if(NOT TIP_LOG_INCLUDE_DIRS) 72 | set(_LOG_SUBTREE ON) 73 | endif() 74 | endif() 75 | 76 | if(NOT TIP_UTIL_INCLUDE_DIRS) 77 | set(TIP_UTIL_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/lib/util/include) 78 | endif() 79 | 80 | if (_LOG_SUBTREE) 81 | add_subdirectory(lib/log) 82 | link_directories(${TIP_LOG_LINK_DIR}) 83 | endif() 84 | 85 | if(NOT AFSM_FOUND) 86 | add_subdirectory(lib/afsm) 87 | endif() 88 | 89 | if (NOT PUSHKIN_ASIO_FIBERS_INCLUDE_DIRECTORIES) 90 | set(_PUSHKIN_ASIO_FIBERS_SUBTREE ON) 91 | endif() 92 | 93 | if (_PUSHKIN_ASIO_FIBERS_SUBTREE) 94 | add_subdirectory(lib/asio-fiber) 95 | endif() 96 | 97 | include_directories( 98 | SYSTEM 99 | ${Boost_INCLUDE_DIRS} 100 | ) 101 | 102 | include_directories( 103 | ${CMAKE_CURRENT_SOURCE_DIR}/include 104 | ${CMAKE_CURRENT_SOURCE_DIR}/src 105 | ${CMAKE_CURRENT_BINARY_DIR}/include 106 | ${CMAKE_CURRENT_BINARY_DIR}/src 107 | ${METAPUSHKIN_INCLUDE_DIRS} 108 | ${AFSM_INCLUDE_DIRS} 109 | ${TIP_UTIL_INCLUDE_DIRS} 110 | ${TIP_LOG_INCLUDE_DIRS} 111 | ${PUSHKIN_ASIO_FIBERS_INCLUDE_DIRECTORIES} 112 | ) 113 | 114 | if (USE_TIP_LOG) 115 | add_definitions(-DWITH_TIP_LOG) 116 | endif() 117 | 118 | set(PGASYNC_LIB_NAME ${PROJECT_PREFIX}-psql) 119 | if(WITH_BOOST_FIBER) 120 | set(PGFIBER_LIB_NAME ${PROJECT_PREFIX}-psql-fiber) 121 | endif() 122 | 123 | add_subdirectory(src/tip/db/pg) 124 | add_subdirectory(include/tip/db) 125 | 126 | if (BUILD_TESTS) 127 | enable_testing() 128 | add_subdirectory(test) 129 | endif() 130 | 131 | get_directory_property(has_parent PARENT_DIRECTORY) 132 | if (has_parent) 133 | set(TIP_DB_LIB ${PGASYNC_LIB_NAME} CACHE INTERNAL "Name of tip psql library target") 134 | set(TIP_DB_FIBER_LIB ${PGFIBER_LIB_NAME} CACHE INTERNAL "Name of tip psql fiber library target") 135 | set(TIP_DB_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include ${TIP_LOG_INCLUDE_DIRS} CACHE INTERNAL "Paths to tip psql library includes") 136 | endif() 137 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pg_async 2 | Asynchronous client library for PostgreSQL, protocol v3. 3 | 4 | ## Motivation 5 | 6 | When developing software we deal a lot with external network resources. Most of them can be accessed through an asynchronous interface, so we don't have to block to wait for a request to finish. The lack of modern C++ asynchronous interface was the reason for writing this library. 7 | 8 | ## Overview 9 | 10 | pg_async is an unofficial PostreSQL database asynchronous client library written in modern C++ (std=c++11) on top of boost::asio library used for asynchronous network input-output. 11 | 12 | ### Features 13 | 14 | * Asynchronous operations 15 | * Connection pooling 16 | * Database aliases 17 | * Standard container-compliant resultset interface 18 | * Execution of prepared statements 19 | * Multiple result sets for simple query mode 20 | * Data row extraction to tuples 21 | * Flexible datatype conversion 22 | * Compile-time statement parameter types binding and checking 23 | * Extensible datatypes input-output system 24 | * TCP or UNIX socket connection 25 | 26 | ### Usage 27 | 28 | ```c++ 29 | #include 30 | 31 | using namespace tip::db::pg; 32 | 33 | // Register conntions 34 | db_service::add_connection("main=user@localhost:5432[the_database]"); 35 | db_service::add_connection("logs=user@localhost:5432[logs_db]"); 36 | 37 | // Run the service 38 | db_service::run(); // Will block the thread 39 | 40 | // Execute queries 41 | db_service::begin( // Start a transaction 42 | "main"_db, // Database alias 43 | [](transaction_ptr tran) // Function to be run inside a transaction 44 | { 45 | query( 46 | tran, // Transaction handle 47 | "select * from pg_catalog.pg_type" // SQL statement 48 | ) 49 | ([](transaction_ptr tran, resultset res, bool complete) // Query results handler 50 | { 51 | for (auto field_desc : 52 | res.row_description()) { // Iterate the field descriptions 53 | std::cout << field_desc.name << "\t"; 54 | } 55 | std::cout << "\n"; 56 | for (auto row : res) { // Iterate the resultset 57 | int a, b; 58 | row.to(std::tie(a, b)); // Extract query result row to a tuple 59 | for (auto field : row) { // Iterate the fields of the row 60 | std::cout << field.coalesce( "null" ) 61 | << "\t"; 62 | } 63 | } 64 | }, 65 | [](db_error const& error) // Query error handler 66 | { 67 | }); 68 | }, 69 | [](db_error cosnt& error) // Function to be called in case of a transaction error 70 | { 71 | } 72 | ); 73 | ``` 74 | 75 | For more information please see accompanying doxygen documentation. 76 | 77 | ## Installation 78 | 79 | ```bash 80 | git clone git@github.com:zmij/pg_async.git 81 | cd pg_async 82 | mkdir build 83 | cd build 84 | cmake .. 85 | make install 86 | ``` 87 | -------------------------------------------------------------------------------- /cmake/modules/Findasio.cmake: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2015 Sergei A. Fedorov 2 | 3 | find_path( asio_INCLUDE asio.hpp HINTS "${CMAKE_SOURCE_DIR}/dependency/asio/asio/include" "/usr/include" "/usr/local/include" "/opt/local/include" ) 4 | 5 | if ( asio_INCLUDE ) 6 | set( ASIO_FOUND TRUE ) 7 | 8 | if ( NOT asio_FIND_QUIETLY ) 9 | message( STATUS "Found asio source: ${asio_INCLUDE}" ) 10 | endif ( ) 11 | else ( ) 12 | if ( asio_FIND_REQUIRED ) 13 | message( FATAL_ERROR "Failed to locate asio!" ) 14 | endif ( ) 15 | endif ( ) 16 | -------------------------------------------------------------------------------- /include/tip/db/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMakeLists.txt 2 | # 3 | # @author zmij 4 | # @date Aug 3, 2015 5 | 6 | cmake_minimum_required(VERSION 2.6) 7 | 8 | set( 9 | pg_async_root_HDRS 10 | pg.hpp 11 | ) 12 | 13 | set( 14 | pg_async_HDRS 15 | pg/common.hpp 16 | pg/database.hpp 17 | pg/datatype_mapping.hpp 18 | pg/error.hpp 19 | pg/pg_types.hpp 20 | pg/protocol_io_traits.hpp 21 | pg/protocol_io_traits.inl 22 | pg/query.hpp 23 | pg/query.inl 24 | pg/resultset.hpp 25 | pg/resultset.inl 26 | pg/sqlstates.hpp 27 | pg/transaction.hpp 28 | ) 29 | 30 | set( 31 | pg_async_detail_HDRS 32 | pg/detail/protocol_parsers.hpp 33 | ) 34 | 35 | set( 36 | pg_async_io_DHRS 37 | pg/io/bytea.hpp 38 | ) 39 | 40 | install( 41 | FILES ${pg_async_root_HDRS} 42 | DESTINATION include/tip/db 43 | ) 44 | 45 | install( 46 | FILES ${pg_async_HDRS} 47 | DESTINATION include/tip/db/pg 48 | ) 49 | 50 | install( 51 | FILES ${pg_async_detail_HDRS} 52 | DESTINATION include/tip/db/pg/detail 53 | ) 54 | 55 | install( 56 | FILES ${pg_async_io_HDRS} 57 | DESTINATION include/tip/db/pg/io 58 | ) 59 | -------------------------------------------------------------------------------- /include/tip/db/pg/asio_config.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * config.hpp 3 | * 4 | * Created on: Aug 5, 2015 5 | * Author: zmij 6 | */ 7 | 8 | #ifndef LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_ASIO_CONFIG_HPP_ 9 | #define LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_ASIO_CONFIG_HPP_ 10 | 11 | 12 | #ifdef WITH_BOOST_ASIO 13 | #include 14 | #define ASIO_NAMESPACE ::boost::asio 15 | #else 16 | #include 17 | #define ASIO_NAMESPACE ::asio 18 | #endif 19 | #include 20 | 21 | namespace tip { 22 | namespace db { 23 | namespace pg { 24 | namespace asio_config { 25 | 26 | typedef ASIO_NAMESPACE::io_service io_service; 27 | typedef std::shared_ptr< io_service > io_service_ptr; 28 | typedef ASIO_NAMESPACE::ip::tcp tcp; 29 | typedef ASIO_NAMESPACE::local::stream_protocol stream_protocol; 30 | 31 | #ifdef WITH_BOOST_ASIO 32 | typedef boost::system::error_code error_code; 33 | #else 34 | typedef ::asio::error_code error_code; 35 | #endif 36 | 37 | } // namespace asio 38 | } // namespace pg 39 | } // namespace db 40 | } // namespace tip 41 | 42 | #endif /* LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_ASIO_CONFIG_HPP_ */ 43 | -------------------------------------------------------------------------------- /include/tip/db/pg/datatype_mapping.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * datatype_mapping.hpp 3 | * 4 | * Created on: Jul 24, 2015 5 | * Author: zmij 6 | */ 7 | 8 | #ifndef LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_DATATYPE_MAPPING_HPP_ 9 | #define LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_DATATYPE_MAPPING_HPP_ 10 | 11 | #include 12 | 13 | namespace tip { 14 | namespace db { 15 | namespace pg { 16 | namespace io { 17 | 18 | namespace traits { 19 | 20 | template < > 21 | struct cpppg_data_mapping< std::string > : detail::data_mapping_base< oids::type::text, std::string > {}; 22 | 23 | //@{ 24 | template < > 25 | struct pgcpp_data_mapping < oids::type::boolean > : detail::data_mapping_base< oids::type::boolean, bool > {}; 26 | template < > 27 | struct cpppg_data_mapping < bool > : detail::data_mapping_base< oids::type::boolean, bool > {}; 28 | //@} 29 | 30 | //@{ 31 | /** @name Integral types */ 32 | template < > 33 | struct pgcpp_data_mapping < oids::type::int2 > : detail::data_mapping_base< oids::type::int2, smallint > {}; 34 | template < > 35 | struct cpppg_data_mapping < smallint > : detail::data_mapping_base< oids::type::int2, smallint > {}; 36 | 37 | template < > 38 | struct pgcpp_data_mapping < oids::type::int4 > : detail::data_mapping_base< oids::type::int4, integer > {}; 39 | template < > 40 | struct cpppg_data_mapping < integer > : detail::data_mapping_base< oids::type::int4, integer > {}; 41 | 42 | template < > 43 | struct pgcpp_data_mapping < oids::type::int8 > : detail::data_mapping_base< oids::type::int8, bigint > {}; 44 | template < > 45 | struct cpppg_data_mapping < bigint > : detail::data_mapping_base< oids::type::int8, bigint > {}; 46 | //@} 47 | 48 | //@{ 49 | /** @name OID types */ 50 | template < > 51 | struct pgcpp_data_mapping < oids::type::oid > : detail::data_mapping_base< oids::type::oid, integer > {}; 52 | template < > 53 | struct pgcpp_data_mapping < oids::type::tid > : detail::data_mapping_base< oids::type::tid, integer > {}; 54 | template < > 55 | struct pgcpp_data_mapping < oids::type::xid > : detail::data_mapping_base< oids::type::xid, integer > {}; 56 | template < > 57 | struct pgcpp_data_mapping < oids::type::cid > : detail::data_mapping_base< oids::type::cid, integer > {}; 58 | //@} 59 | 60 | //@{ 61 | /** @name Floating-point types */ 62 | template < > 63 | struct pgcpp_data_mapping < oids::type::float4 > : detail::data_mapping_base< oids::type::float4, float > {}; 64 | template < > 65 | struct cpppg_data_mapping < float > : detail::data_mapping_base< oids::type::float4, float > {}; 66 | 67 | template < > 68 | struct pgcpp_data_mapping < oids::type::float8 > : detail::data_mapping_base< oids::type::float8, double > {}; 69 | template < > 70 | struct cpppg_data_mapping < double > : detail::data_mapping_base< oids::type::float8, double > {}; 71 | //@} 72 | 73 | } // namespace traits 74 | } // namespace io 75 | } // namespace pg 76 | } // namespace db 77 | } // namespace tip 78 | 79 | #endif /* LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_DATATYPE_MAPPING_HPP_ */ 80 | -------------------------------------------------------------------------------- /include/tip/db/pg/detail/array_tokenizer.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * arraytokenizer.hpp 3 | * 4 | * Created on: Sep 28, 2015 5 | * Author: zmij 6 | */ 7 | 8 | #ifndef LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_DETAIL_ARRAY_TOKENIZER_HPP_ 9 | #define LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_DETAIL_ARRAY_TOKENIZER_HPP_ 10 | 11 | #include 12 | 13 | namespace tip { 14 | namespace db { 15 | namespace pg { 16 | namespace io { 17 | namespace detail { 18 | 19 | template < typename InputIterator > 20 | class array_tokenizer { 21 | public: 22 | typedef InputIterator iterator_type; 23 | typedef tokenizer_base< InputIterator, '{', '}' > tokenizer_type; 24 | public: 25 | template< typename OutputIterator > 26 | array_tokenizer(iterator_type& begin, iterator_type end, OutputIterator out) 27 | { 28 | tokenizer_type(begin, end, out); 29 | } 30 | }; 31 | 32 | } /* namespace detail */ 33 | } // namespace io 34 | } /* namespace pg */ 35 | } /* namespace db */ 36 | } /* namespace tip */ 37 | 38 | #endif /* LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_DETAIL_ARRAY_TOKENIZER_HPP_ */ 39 | -------------------------------------------------------------------------------- /include/tip/db/pg/detail/data_iterator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TIP_DB_PG_DETAIL_DATA_ITERATOR_HPP_ 2 | #define TIP_DB_PG_DETAIL_DATA_ITERATOR_HPP_ 3 | 4 | #include 5 | 6 | namespace tip { 7 | namespace db { 8 | namespace pg { 9 | namespace detail { 10 | 11 | template < typename FinalType, typename DataType > 12 | class data_iterator : public DataType { 13 | public: 14 | using iterator_type = FinalType; 15 | 16 | //@{ 17 | /** @iterator Concept */ 18 | using value_type = DataType; 19 | using difference_type = int; 20 | using reference = value_type; 21 | using pointer = value_type const*; 22 | using iterator_category = std::random_access_iterator_tag; 23 | //@} 24 | public: 25 | //@{ 26 | /** @name Iterator dereferencing */ 27 | reference operator*() const { return reference{*this}; } 28 | pointer operator->() const { return this; } 29 | //@} 30 | 31 | //@{ 32 | operator bool() const 33 | { 34 | return rebind().valid(); 35 | } 36 | bool 37 | operator! () const 38 | { 39 | return !rebind().valid(); 40 | } 41 | 42 | //@} 43 | 44 | //@{ 45 | /** @name Iterator movement */ 46 | iterator_type& operator++() { return do_advance(1); } 47 | iterator_type operator++(int) { 48 | iterator_type prev{rebind()}; 49 | do_advance(1); 50 | return prev; 51 | } 52 | 53 | iterator_type& operator--() { return do_advance(-1); } 54 | iterator_type operator--(int) { 55 | iterator_type prev{rebind()}; 56 | do_advance(-1); 57 | return prev; 58 | } 59 | 60 | iterator_type& operator += (difference_type distance) { return do_advance(distance); } 61 | iterator_type& operator -= (difference_type distance) { return do_advance(-distance); } 62 | //@} 63 | 64 | //@{ 65 | /** @name Iterator comparison */ 66 | bool operator ==(iterator_type const& rhs) const { 67 | return do_compare(rhs) == 0; 68 | } 69 | 70 | bool operator !=(iterator_type const& rhs) const { 71 | return !(*this == rhs); 72 | } 73 | 74 | bool operator <(iterator_type const& rhs) const { 75 | return do_compare(rhs) < 0; 76 | } 77 | bool operator <=(iterator_type const& rhs) const { 78 | return do_compare(rhs) <= 0; 79 | } 80 | bool operator >(iterator_type const& rhs) const { 81 | return do_compare(rhs) > 0; 82 | } 83 | bool operator >=(iterator_type const& rhs) const { 84 | return do_compare(rhs) >= 0; 85 | } 86 | //@} 87 | protected: 88 | template < typename ... T > 89 | data_iterator(T ... args) : value_type(::std::forward(args)...) {} 90 | private: 91 | iterator_type& 92 | rebind() 93 | { return static_cast(*this); } 94 | 95 | iterator_type const& 96 | rebind() const 97 | { return static_cast(*this); } 98 | 99 | iterator_type& 100 | do_advance(difference_type distance) 101 | { return rebind().advance(distance); } 102 | 103 | int 104 | do_compare(iterator_type const& lhs) const 105 | { return rebind().compare(lhs); } 106 | }; 107 | 108 | } // namespace detail 109 | } // namespace pg 110 | } // namespace db 111 | } // namespace tip 112 | 113 | #endif /* TIP_DB_PG_DETAIL_DATA_ITERATOR_HPP_ */ 114 | 115 | 116 | -------------------------------------------------------------------------------- /include/tip/db/pg/detail/protocol_parsers.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * protocol_parsers.hpp 3 | * 4 | * Created on: Jul 19, 2015 5 | * Author: zmij 6 | */ 7 | 8 | #ifndef LIB_PG_ASYNC_SRC_TIP_DB_PG_DETAIL_PROTOCOL_PARSERS_HPP_ 9 | #define LIB_PG_ASYNC_SRC_TIP_DB_PG_DETAIL_PROTOCOL_PARSERS_HPP_ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | namespace tip { 16 | namespace db { 17 | namespace pg { 18 | namespace io { 19 | namespace detail { 20 | 21 | class bytea_parser { 22 | 23 | enum state { 24 | expecting_backslash, 25 | expecting_x, 26 | nibble_one, 27 | nibble_two 28 | } state_; 29 | char most_sighificant_nibble_; 30 | public: 31 | bytea_parser() : state_(expecting_backslash), most_sighificant_nibble_(0) {} 32 | 33 | template < typename InputIterator, typename OutputIterator > 34 | std::pair< boost::tribool, InputIterator > 35 | parse(InputIterator begin, InputIterator end, OutputIterator data) 36 | { 37 | boost::tribool result = boost::indeterminate; 38 | while (begin != end) { 39 | result = consume(data, *begin++); 40 | } 41 | return std::make_pair(result, begin); 42 | } 43 | 44 | void 45 | reset() 46 | { 47 | state_ = expecting_backslash; 48 | most_sighificant_nibble_ = 0; 49 | } 50 | private: 51 | template < typename OutputIterator > 52 | boost::tribool 53 | consume( OutputIterator data, char input ) 54 | { 55 | switch (state_) { 56 | case expecting_backslash: 57 | if (input == '\\') { 58 | state_ = expecting_x; 59 | return boost::indeterminate; 60 | } else { 61 | return false; 62 | } 63 | case expecting_x: 64 | if (input == 'x') { 65 | state_ = nibble_one; 66 | return true; 67 | } else { 68 | return false; 69 | } 70 | case nibble_one: 71 | if (std::isxdigit(input)) { 72 | most_sighificant_nibble_ = hex_to_byte(input); 73 | state_ = nibble_two; 74 | return boost::indeterminate; 75 | } else { 76 | return false; 77 | } 78 | case nibble_two: 79 | if (std::isxdigit(input)) { 80 | *data++ = (hex_to_byte(input) << 4) | most_sighificant_nibble_; 81 | state_ = nibble_one; 82 | return true; 83 | } else { 84 | return false; 85 | } 86 | default: 87 | break; 88 | } 89 | return false; 90 | } 91 | 92 | static char 93 | hex_to_byte(char); 94 | }; 95 | 96 | } // namespace detail 97 | } // namespace io 98 | } // namespace pg 99 | } // namespace db 100 | } // namespace tip 101 | 102 | 103 | #endif /* LIB_PG_ASYNC_SRC_TIP_DB_PG_DETAIL_PROTOCOL_PARSERS_HPP_ */ 104 | -------------------------------------------------------------------------------- /include/tip/db/pg/error.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * error.hpp 3 | * 4 | * Created on: 16 июля 2015 г. 5 | * @author: zmij 6 | */ 7 | 8 | #ifndef TIP_DB_PG_ERROR_HPP_ 9 | #define TIP_DB_PG_ERROR_HPP_ 10 | 11 | #include 12 | #include 13 | 14 | namespace tip { 15 | namespace db { 16 | namespace pg { 17 | namespace error { 18 | 19 | /** 20 | * @brief Base class for exceptions generated by the library 21 | */ 22 | class db_error : public std::runtime_error { 23 | public: 24 | explicit db_error( std::string const& what_arg ); 25 | explicit db_error( char const* what_arg ); 26 | db_error(std::string const& message, 27 | std::string severity, 28 | std::string code, 29 | std::string detail); 30 | std::string severity; 31 | std::string code; 32 | std::string detail; 33 | sqlstate::code sqlstate; 34 | }; 35 | 36 | /** 37 | * @brief Connection with the database server failure. 38 | * Includes network and authentication failures. 39 | */ 40 | class connection_error : public db_error { 41 | public: 42 | explicit connection_error( std::string const&); 43 | explicit connection_error( char const* what_arg ); 44 | }; 45 | 46 | /** 47 | * @brief An error generated by the PostgreSQL server when executing a query. 48 | */ 49 | class query_error : public db_error { 50 | public: 51 | explicit query_error( std::string const&); 52 | explicit query_error( char const* what_arg ); 53 | 54 | query_error(std::string const& message, 55 | std::string severity, 56 | std::string code, 57 | std::string detail 58 | ); 59 | }; 60 | 61 | class transaction_closed : public query_error { 62 | public: 63 | transaction_closed() : query_error("Transaction already closed") {} 64 | }; 65 | 66 | /** 67 | * @brief An exception was caught in a callback. 68 | * @see @ref errors 69 | * @see @ref callbacks 70 | */ 71 | class client_error : public db_error { 72 | public: 73 | explicit client_error( std::string const& ); 74 | explicit client_error( char const*); 75 | explicit client_error( std::exception const&); 76 | }; 77 | 78 | /** 79 | * @brief An attempt to extract a value from a null field was made. 80 | */ 81 | class value_is_null : public db_error { 82 | public: 83 | explicit value_is_null(std::string const& field_name); 84 | }; 85 | 86 | } // namespace error 87 | } // namespace pg 88 | } // namespace db 89 | } // namespace tip 90 | 91 | 92 | 93 | #endif /* TIP_DB_PG_ERROR_HPP_ */ 94 | -------------------------------------------------------------------------------- /include/tip/db/pg/future_config.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * future_config.hpp 3 | * 4 | * Created on: Mar 29, 2017 5 | * Author: zmij 6 | */ 7 | 8 | #ifndef TIP_DB_PG_FUTURE_CONFIG_HPP_ 9 | #define TIP_DB_PG_FUTURE_CONFIG_HPP_ 10 | 11 | #ifdef WITH_BOOST_FIBERS 12 | #include 13 | #include 14 | #else 15 | #include 16 | #endif 17 | 18 | namespace tip { 19 | namespace db { 20 | namespace pg { 21 | 22 | #ifdef WITH_BOOST_FIBERS 23 | template < typename _Res > 24 | using promise = ::boost::fibers::promise< _Res >; 25 | using fiber = ::boost::fibers::fiber; 26 | #else 27 | template < typename _Res > 28 | using promise = ::std::promise< _Res >; 29 | #endif 30 | 31 | } /* namespace pg */ 32 | } /* namespace db */ 33 | } /* namespace tip */ 34 | 35 | 36 | #endif /* TIP_DB_PG_FUTURE_CONFIG_HPP_ */ 37 | -------------------------------------------------------------------------------- /include/tip/db/pg/io/array.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * array.hpp 3 | * 4 | * Created on: Sep 29, 2015 5 | * Author: zmij 6 | */ 7 | 8 | #ifndef LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_IO_ARRAY_HPP_ 9 | #define LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_IO_ARRAY_HPP_ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | namespace tip { 18 | namespace db { 19 | namespace pg { 20 | namespace io { 21 | 22 | template < typename T, std::size_t Sz > 23 | struct protocol_formatter< std::array< T, Sz >, TEXT_DATA_FORMAT > : 24 | detail::text_container_formatter< std::array< T, Sz > > { 25 | typedef detail::text_container_formatter< std::array< T, Sz > > base_type; 26 | typedef typename base_type::value_type value_type; 27 | 28 | protocol_formatter(value_type const& v) : base_type(v) {} 29 | }; 30 | 31 | template < typename T, std::size_t Sz > 32 | struct protocol_parser< std::array< T, Sz >, TEXT_DATA_FORMAT > : 33 | detail::text_container_parser< 34 | protocol_parser< std::array< T, Sz >, TEXT_DATA_FORMAT >, 35 | std::array< T, Sz > > { 36 | 37 | enum { 38 | array_size = Sz 39 | }; 40 | 41 | typedef detail::text_container_parser< 42 | protocol_parser< std::array< T, Sz >, TEXT_DATA_FORMAT >, 43 | std::array< T, Sz > > base_type; 44 | typedef typename base_type::value_type value_type; 45 | protocol_parser(value_type& v) : base_type(v) {} 46 | 47 | typename base_type::token_iterator 48 | tokens_end(typename base_type::tokens_list const& tokens) 49 | { 50 | if (tokens.size() <= array_size) 51 | return tokens.end(); 52 | return tokens.begin() + array_size; 53 | } 54 | 55 | template < typename InputIterator > 56 | InputIterator 57 | operator()(InputIterator begin, InputIterator end) 58 | { 59 | return base_type::parse(begin, end, base_type::value.begin()); 60 | } 61 | }; 62 | 63 | namespace traits { 64 | 65 | template < typename T, std::size_t Sz > 66 | struct has_formatter< std::array< T, Sz >, TEXT_DATA_FORMAT > : std::true_type {}; 67 | template < typename T, std::size_t Sz > 68 | struct has_parser< std::array< T, Sz >, TEXT_DATA_FORMAT > : std::true_type {}; 69 | 70 | template < typename T, std::size_t Sz > 71 | struct cpppg_data_mapping< std::array< T, Sz > > : 72 | detail::data_mapping_base < oids::type::text, std::array< T, Sz > > {}; 73 | 74 | } // namespace traits 75 | 76 | } // namespace io 77 | } // namespace pg 78 | } // namespace db 79 | } // namespace tip 80 | 81 | 82 | #endif /* LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_IO_ARRAY_HPP_ */ 83 | -------------------------------------------------------------------------------- /include/tip/db/pg/io/bytea.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * bytea.hpp 3 | * 4 | * Created on: Aug 7, 2015 5 | * Author: zmij 6 | */ 7 | 8 | #ifndef LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_IO_BYTEA_HPP_ 9 | #define LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_IO_BYTEA_HPP_ 10 | 11 | #include 12 | 13 | namespace tip { 14 | namespace db { 15 | namespace pg { 16 | namespace io { 17 | 18 | /** 19 | * @brief Protocol parser specialization for bytea (binary string), text data format 20 | */ 21 | template <> 22 | struct protocol_parser< bytea, TEXT_DATA_FORMAT > : 23 | detail::parser_base< bytea > { 24 | typedef detail::parser_base< bytea > base_type; 25 | typedef base_type::value_type value_type; 26 | typedef tip::util::input_iterator_buffer buffer_type; 27 | 28 | protocol_parser(value_type& v) : base_type(v) {} 29 | 30 | size_t 31 | size() const 32 | { 33 | return base_type::value.size(); 34 | } 35 | bool 36 | operator() (std::istream& in); 37 | 38 | bool 39 | operator() (buffer_type& buffer); 40 | 41 | template < typename InputIterator > 42 | InputIterator 43 | operator()( InputIterator begin, InputIterator end ); 44 | }; 45 | 46 | /** 47 | * @brief Protocol parser specialization for bytea (binary string), binary data format 48 | */ 49 | template <> 50 | struct protocol_parser< bytea, BINARY_DATA_FORMAT > : 51 | detail::parser_base< bytea > { 52 | typedef detail::parser_base< bytea > base_type; 53 | typedef base_type::value_type value_type; 54 | 55 | protocol_parser(value_type& val) : base_type(val) {} 56 | size_t 57 | size() const 58 | { 59 | return base_type::value.size(); 60 | } 61 | template < typename InputIterator > 62 | InputIterator 63 | operator()( InputIterator begin, InputIterator end ); 64 | }; 65 | 66 | template <> 67 | struct protocol_formatter< bytea, BINARY_DATA_FORMAT > : 68 | detail::formatter_base< bytea > { 69 | 70 | typedef detail::formatter_base< bytea > base_type; 71 | typedef base_type::value_type value_type; 72 | 73 | protocol_formatter(bytea const& val) : base_type(val) {} 74 | size_t 75 | size() const 76 | { 77 | return base_type::value.size(); 78 | } 79 | 80 | bool 81 | operator() (std::vector& buffer) 82 | { 83 | if (buffer.capacity() - buffer.size() < size()) { 84 | buffer.reserve(buffer.size() + size()); 85 | } 86 | std::copy(base_type::value.begin(), base_type::value.end(), 87 | std::back_inserter(buffer)); 88 | return true; 89 | } 90 | }; 91 | 92 | namespace traits { 93 | 94 | template <> struct has_parser< bytea, TEXT_DATA_FORMAT > : std::true_type {}; 95 | template <> struct has_parser< bytea, BINARY_DATA_FORMAT > : std::true_type {}; 96 | template <> struct has_formatter < bytea, BINARY_DATA_FORMAT > : std::true_type {}; 97 | 98 | //@{ 99 | template < > 100 | struct pgcpp_data_mapping < oids::type::bytea > : 101 | detail::data_mapping_base< oids::type::bytea, bytea > {}; 102 | template < > 103 | struct cpppg_data_mapping < bytea > : 104 | detail::data_mapping_base< oids::type::bytea, bytea > {}; 105 | //@} 106 | 107 | static_assert(has_parser::value, 108 | "Binary data parser for bool"); 109 | static_assert(best_parser::value == BINARY_DATA_FORMAT, 110 | "Best parser for bool is binary"); 111 | 112 | } // namespace traits 113 | 114 | template < typename InputIterator > 115 | InputIterator 116 | protocol_parser< bytea, TEXT_DATA_FORMAT >::operator () 117 | (InputIterator begin, InputIterator end) 118 | { 119 | typedef InputIterator iterator_type; 120 | typedef std::iterator_traits< iterator_type > iter_traits; 121 | typedef typename iter_traits::value_type iter_value_type; 122 | static_assert(std::is_same< iter_value_type, byte >::type::value, 123 | "Input iterator must be over a char container"); 124 | std::vector data; 125 | 126 | auto result = detail::bytea_parser().parse(begin, end, std::back_inserter(data)); 127 | if (result.first) { 128 | base_type::value.swap(data); 129 | return result.second; 130 | } 131 | return begin; 132 | } 133 | 134 | template < typename InputIterator > 135 | InputIterator 136 | protocol_parser< bytea, BINARY_DATA_FORMAT >::operator () 137 | (InputIterator begin, InputIterator end) 138 | { 139 | typedef InputIterator iterator_type; 140 | typedef std::iterator_traits< iterator_type > iter_traits; 141 | typedef typename iter_traits::value_type iter_value_type; 142 | static_assert(std::is_same< iter_value_type, byte >::type::value, 143 | "Input iterator must be over a char container"); 144 | 145 | bytea tmp(begin, end); 146 | std::swap(base_type::value, tmp); 147 | 148 | return end; 149 | } 150 | 151 | } // namespace io 152 | } // namespace pg 153 | } // namespace db 154 | } // namespace tip 155 | 156 | #endif /* LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_IO_BYTEA_HPP_ */ 157 | -------------------------------------------------------------------------------- /include/tip/db/pg/io/container_to_array.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * container_to_array.hpp 3 | * 4 | * Created on: Sep 29, 2015 5 | * Author: zmij 6 | */ 7 | 8 | #ifndef LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_IO_CONTAINER_TO_ARRAY_HPP_ 9 | #define LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_IO_CONTAINER_TO_ARRAY_HPP_ 10 | 11 | #include 12 | #include 13 | 14 | namespace tip { 15 | namespace db { 16 | namespace pg { 17 | namespace io { 18 | namespace detail { 19 | 20 | template < typename Container > 21 | struct text_container_formatter : formatter_base< Container > { 22 | typedef formatter_base< Container > base_type; 23 | typedef typename base_type::value_type value_type; 24 | typedef typename value_type::const_iterator element_iterator; 25 | 26 | text_container_formatter(value_type const& v) : base_type(v) {} 27 | 28 | size_t 29 | size() const 30 | { return 0; } 31 | 32 | bool 33 | operator() ( std::vector& buffer) 34 | { 35 | buffer.push_back('{'); 36 | element_iterator elem = base_type::value.begin(); 37 | element_iterator end = base_type::value.end(); 38 | while (elem != end) { 39 | quoted_write(buffer, *elem); 40 | ++elem; 41 | if (elem != end) 42 | buffer.push_back(','); 43 | } 44 | buffer.push_back('}'); 45 | return true; 46 | } 47 | }; 48 | 49 | template < typename Parser, typename Container > 50 | struct text_container_parser : 51 | detail::parser_base< Container > { 52 | 53 | typedef Parser parser_type; 54 | typedef detail::parser_base< Container > base_type; 55 | typedef typename base_type::value_type value_type; 56 | typedef typename value_type::value_type element_type; 57 | typedef std::vector< std::string > tokens_list; 58 | typedef tokens_list::const_iterator token_iterator; 59 | 60 | text_container_parser(value_type& v) : base_type(v) {} 61 | 62 | template < typename InputIterator, typename OutputIterator > 63 | InputIterator 64 | parse(InputIterator begin, InputIterator end, OutputIterator out) 65 | { 66 | typedef std::iterator_traits< InputIterator > iter_traits; 67 | typedef typename iter_traits::value_type iter_value_type; 68 | static_assert(std::is_same< iter_value_type, byte >::type::value, 69 | "Input iterator must be over a char container"); 70 | 71 | typedef detail::array_tokenizer< InputIterator > array_tokenizer; 72 | 73 | tokens_list tokens; 74 | array_tokenizer(begin, end, std::back_inserter(tokens)); 75 | 76 | token_iterator tok = tokens.begin(); 77 | token_iterator tok_end = parser().tokens_end(tokens); 78 | 79 | for (; tok != tok_end; ++tok) { 80 | element_type tmp; 81 | protocol_read< TEXT_DATA_FORMAT >(tok->begin(), tok->end(), tmp); 82 | *out++ = std::move(tmp); 83 | } 84 | return begin; 85 | } 86 | 87 | parser_type& 88 | parser() 89 | { 90 | return static_cast< parser_type& >(*this); 91 | } 92 | }; 93 | 94 | } // namespace detail 95 | } // namespace io 96 | } // namespace pg 97 | } // namespace db 98 | } // namespace tip 99 | 100 | #endif /* LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_IO_CONTAINER_TO_ARRAY_HPP_ */ 101 | -------------------------------------------------------------------------------- /include/tip/db/pg/io/ip_address.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * ip_address.hpp 3 | * 4 | * Created on: Sep 2, 2015 5 | * Author: zmij 6 | */ 7 | 8 | #ifndef LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_IO_IP_ADDRESS_HPP_ 9 | #define LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_IO_IP_ADDRESS_HPP_ 10 | 11 | #include 12 | #include 13 | 14 | #ifdef WITH_BOOST_ASIO 15 | #include 16 | #else 17 | #include 18 | #endif 19 | 20 | namespace tip { 21 | namespace db { 22 | namespace pg { 23 | namespace io { 24 | 25 | template < > 26 | struct protocol_parser< ASIO_NAMESPACE::ip::address, TEXT_DATA_FORMAT > : 27 | detail::parser_base< ASIO_NAMESPACE::ip::address > { 28 | typedef detail::parser_base< ASIO_NAMESPACE::ip::address > base_type; 29 | typedef base_type::value_type value_type; 30 | 31 | protocol_parser(value_type& v) : base_type(v) {} 32 | 33 | size_t 34 | size() const 35 | { 36 | return base_type::value.to_string().size(); 37 | } 38 | 39 | template < typename InputIterator > 40 | InputIterator 41 | operator()(InputIterator begin, InputIterator end) 42 | { 43 | typedef InputIterator iterator_type; 44 | typedef std::iterator_traits< iterator_type > iter_traits; 45 | typedef typename iter_traits::value_type iter_value_type; 46 | static_assert(std::is_same< iter_value_type, byte >::type::value, 47 | "Input iterator must be over a char container"); 48 | std::string s(begin, end); 49 | asio_config::error_code ec; 50 | value_type tmp = value_type::from_string(s, ec); 51 | if (!ec) { 52 | base_type::value = tmp; 53 | return end; 54 | } 55 | return begin; 56 | } 57 | }; 58 | 59 | namespace traits { 60 | 61 | template < > 62 | struct has_parser< ASIO_NAMESPACE::ip::address, TEXT_DATA_FORMAT > : std::true_type {}; 63 | //@{ 64 | template < > 65 | struct pgcpp_data_mapping< oids::type::inet > : 66 | detail::data_mapping_base< oids::type::inet, boost::asio::ip::address > {}; 67 | template < > 68 | struct cpppg_data_mapping< boost::asio::ip::address > : 69 | detail::data_mapping_base< oids::type::inet, boost::asio::ip::address > {}; 70 | //@} 71 | 72 | } // namespace traits 73 | 74 | } // namespace io 75 | } // namespace pg 76 | } // namespace db 77 | } // namespace tip 78 | 79 | #endif /* LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_IO_IP_ADDRESS_HPP_ */ 80 | -------------------------------------------------------------------------------- /include/tip/db/pg/io/set.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by zmij on 19.10.15. 3 | // 4 | 5 | #ifndef LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_IO_SET_HPP 6 | #define LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_IO_SET_HPP 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | namespace tip { 14 | namespace db { 15 | namespace pg { 16 | namespace io { 17 | 18 | template < typename T > 19 | struct protocol_formatter< std::set< T >, TEXT_DATA_FORMAT > : 20 | detail::text_container_formatter< std::set< T > > { 21 | 22 | typedef detail::text_container_formatter< std::set< T > > base_type; 23 | typedef typename base_type::value_type value_type; 24 | 25 | protocol_formatter(value_type const& v) : base_type(v) {} 26 | }; 27 | 28 | template < typename T > 29 | struct protocol_parser< std::set< T >, TEXT_DATA_FORMAT > : 30 | detail::text_container_parser< 31 | protocol_parser< std::set< T >, TEXT_DATA_FORMAT >, 32 | std::set< T > > { 33 | 34 | typedef detail::text_container_parser< 35 | protocol_parser< std::set< T >, TEXT_DATA_FORMAT >, 36 | std::set< T > > base_type; 37 | typedef typename base_type::value_type value_type; 38 | 39 | protocol_parser(value_type& v) : base_type(v) {} 40 | 41 | typename base_type::token_iterator 42 | tokens_end(typename base_type::tokens_list const& tokens) 43 | { 44 | return tokens.end(); 45 | } 46 | 47 | template < typename InputIterator > 48 | InputIterator 49 | operator()(InputIterator begin, InputIterator end) 50 | { 51 | base_type::value.clear(); 52 | return base_type::parse(begin, end, std::inserter(base_type::value, 53 | base_type::value.begin())); 54 | } 55 | }; 56 | 57 | namespace traits { 58 | 59 | template < typename T > 60 | struct has_formatter< std::set< T >, TEXT_DATA_FORMAT > : std::true_type {}; 61 | template < typename T > 62 | struct has_parser< std::set< T >, TEXT_DATA_FORMAT > : std::true_type {}; 63 | 64 | template < typename T > 65 | struct cpppg_data_mapping< std::set< T > > : 66 | detail::data_mapping_base < oids::type::text, std::set< T > > {}; 67 | 68 | } // namespace traits 69 | 70 | 71 | } // namespace io 72 | } // namespace pg 73 | } // namespace db 74 | } // namespace tip 75 | 76 | #endif //LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_IO_SET_HPP 77 | -------------------------------------------------------------------------------- /include/tip/db/pg/io/uuid.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * uuid.hpp 3 | * 4 | * Created on: Aug 10, 2015 5 | * Author: zmij 6 | */ 7 | 8 | #ifndef LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_IO_UUID_HPP_ 9 | #define LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_IO_UUID_HPP_ 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | namespace tip { 17 | namespace db { 18 | namespace pg { 19 | namespace io { 20 | 21 | template <> 22 | struct protocol_parser< ::boost::uuids::uuid, BINARY_DATA_FORMAT >: 23 | detail::parser_base< ::boost::uuids::uuid > { 24 | 25 | using uuid = ::boost::uuids::uuid; 26 | using base_type = detail::parser_base; 27 | using value_type = base_type::value_type; 28 | 29 | protocol_parser(value_type& v) : base_type(v) {} 30 | 31 | size_t 32 | size() const 33 | { 34 | return uuid::static_size(); 35 | } 36 | 37 | template < typename InputIterator > 38 | InputIterator 39 | operator()( InputIterator begin, InputIterator end) 40 | { 41 | typedef std::iterator_traits< InputIterator > iter_traits; 42 | typedef typename iter_traits::value_type iter_value_type; 43 | static_assert(std::is_same< iter_value_type, byte >::type::value, 44 | "Input iterator must be over a char container"); 45 | assert( (end - begin) >= (decltype (end - begin))size() && "Buffer size is insufficient" ); 46 | end = begin + size(); 47 | ::std::copy(begin, end, base_type::value.begin()); 48 | return begin; 49 | } 50 | }; 51 | 52 | template < > 53 | struct protocol_formatter< ::boost::uuids::uuid, BINARY_DATA_FORMAT > : 54 | detail::formatter_base< ::boost::uuids::uuid > { 55 | 56 | using uuid = ::boost::uuids::uuid; 57 | using base_type = detail::formatter_base; 58 | using value_type = base_type::value_type; 59 | 60 | protocol_formatter(value_type const& val) : base_type(val) {} 61 | 62 | size_t 63 | size() const 64 | { 65 | return uuid::static_size(); 66 | } 67 | 68 | bool 69 | operator() (::std::vector& buffer) 70 | { 71 | if (buffer.capacity() - buffer.size() < size()) { 72 | buffer.reserve(buffer.size() + size()); 73 | } 74 | 75 | ::std::copy(base_type::value.begin(), 76 | base_type::value.end(), ::std::back_inserter(buffer)); 77 | return true; 78 | } 79 | }; 80 | 81 | namespace traits { 82 | 83 | template <> 84 | struct has_parser < ::boost::uuids::uuid, BINARY_DATA_FORMAT > : std::true_type {}; 85 | template <> 86 | struct has_formatter < ::boost::uuids::uuid, BINARY_DATA_FORMAT > : std::true_type {}; 87 | 88 | //@{ 89 | template < > 90 | struct pgcpp_data_mapping < oids::type::uuid > : 91 | detail::data_mapping_base< oids::type::uuid, boost::uuids::uuid > {}; 92 | template < > 93 | struct cpppg_data_mapping < boost::uuids::uuid > : 94 | detail::data_mapping_base< oids::type::uuid, boost::uuids::uuid > {}; 95 | //@} 96 | 97 | template <> 98 | struct is_nullable< ::boost::uuids::uuid > : ::std::true_type {}; 99 | 100 | template <> 101 | struct nullable_traits< ::boost::uuids::uuid > { 102 | using uuid = ::boost::uuids::uuid; 103 | inline static bool 104 | is_null(uuid const& val) 105 | { 106 | return val.is_nil(); 107 | } 108 | inline static void 109 | set_null(uuid& val) 110 | { 111 | val = uuid{{0}}; 112 | } 113 | }; 114 | 115 | } // namespace traits 116 | } // namespace io 117 | } // namespace pg 118 | } // namespace db 119 | } // namespace tip 120 | 121 | #endif /* LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_IO_UUID_HPP_ */ 122 | -------------------------------------------------------------------------------- /include/tip/db/pg/io/vector.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * vector.hpp 3 | * 4 | * Created on: Sep 28, 2015 5 | * Author: zmij 6 | */ 7 | 8 | #ifndef LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_IO_VECTOR_HPP_ 9 | #define LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_IO_VECTOR_HPP_ 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | namespace tip { 17 | namespace db { 18 | namespace pg { 19 | namespace io { 20 | 21 | /** 22 | * @brief Protocol format specialization for std::vector, mapping to postgre array 23 | */ 24 | template < typename T > 25 | struct protocol_formatter< std::vector< T >, TEXT_DATA_FORMAT > : 26 | detail::text_container_formatter< std::vector< T > > { 27 | 28 | typedef detail::text_container_formatter< std::vector< T > > base_type; 29 | typedef typename base_type::value_type value_type; 30 | 31 | protocol_formatter(value_type const& v) : base_type(v) {} 32 | }; 33 | 34 | template < typename T > 35 | struct protocol_parser< std::vector< T >, TEXT_DATA_FORMAT > : 36 | detail::text_container_parser< 37 | protocol_parser< std::vector< T >, TEXT_DATA_FORMAT >, 38 | std::vector< T > > { 39 | 40 | typedef detail::text_container_parser< 41 | protocol_parser< std::vector< T >, TEXT_DATA_FORMAT >, 42 | std::vector< T > > base_type; 43 | typedef typename base_type::value_type value_type; 44 | 45 | protocol_parser(value_type& v) : base_type(v) {} 46 | 47 | typename base_type::token_iterator 48 | tokens_end(typename base_type::tokens_list const& tokens) 49 | { 50 | return tokens.end(); 51 | } 52 | 53 | template < typename InputIterator > 54 | InputIterator 55 | operator()(InputIterator begin, InputIterator end) 56 | { 57 | base_type::value.clear(); 58 | return base_type::parse(begin, end, std::back_inserter(base_type::value)); 59 | } 60 | }; 61 | 62 | namespace traits { 63 | 64 | template < typename T > 65 | struct has_formatter< std::vector< T >, TEXT_DATA_FORMAT > : std::true_type {}; 66 | template < typename T > 67 | struct has_parser< std::vector< T >, TEXT_DATA_FORMAT > : std::true_type {}; 68 | 69 | template < typename T > 70 | struct cpppg_data_mapping< std::vector< T > > : 71 | detail::data_mapping_base < oids::type::text, std::vector< T > > {}; 72 | 73 | } // namespace traits 74 | 75 | } // namespace io 76 | } // namespace pg 77 | } // namespace db 78 | } // namespace tip 79 | 80 | 81 | #endif /* LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_IO_VECTOR_HPP_ */ 82 | -------------------------------------------------------------------------------- /include/tip/db/pg/pg_types.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * pg_types.hpp 3 | * 4 | * Created on: Jul 24, 2015 5 | * Author: zmij 6 | */ 7 | 8 | #ifndef LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_PG_TYPES_HPP_ 9 | #define LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_PG_TYPES_HPP_ 10 | 11 | #include 12 | 13 | namespace tip { 14 | namespace db { 15 | namespace pg { 16 | 17 | namespace oids { 18 | 19 | namespace type { 20 | enum oid_type { 21 | boolean = 16, 22 | bytea = 17, 23 | char_ = 18, 24 | name = 19, 25 | int8 = 20, 26 | int2 = 21, 27 | int2_vector = 22, 28 | int4 = 23, 29 | regproc = 24, 30 | text = 25, 31 | oid = 26, 32 | tid = 27, 33 | xid = 28, 34 | cid = 29, 35 | oid_vector = 30, 36 | json = 114, 37 | xml = 142, 38 | pg_node_tree = 194, 39 | pg_ddl_command = 32, 40 | point = 600, 41 | lseg = 601, 42 | path = 602, 43 | box = 603, 44 | polygon = 604, 45 | line = 628, 46 | float4 = 700, 47 | float8 = 701, 48 | abstime = 702, 49 | reltime = 703, 50 | tinterval = 704, 51 | unknown = 705, 52 | circle = 718, 53 | cash = 790, 54 | macaddr = 829, 55 | inet = 869, 56 | cidr = 650, 57 | int2_array = 1005, 58 | int4_array = 1007, 59 | text_array = 1009, 60 | oid_array = 1028, 61 | float4_array = 1021, 62 | acl_item = 1033, 63 | cstring_array = 1263, 64 | bpchar = 1042, 65 | varchar = 1043, 66 | date = 1082, 67 | time = 1083, 68 | timestamp = 1114, 69 | timestamptz = 1184, 70 | interval = 1186, 71 | timetz = 1266, 72 | bit = 1560, 73 | varbit = 1562, 74 | numeric = 1700, 75 | refcursor = 1790, 76 | regprocedure = 2202, 77 | regoper = 2203, 78 | regoperator = 2204, 79 | regclass = 2205, 80 | regtype = 2206, 81 | regrole = 4096, 82 | regtypearray = 2211, 83 | uuid = 2950, 84 | lsn = 3220, 85 | tsvector = 3614, 86 | gtsvector = 3642, 87 | tsquery = 3615, 88 | regconfig = 3734, 89 | regdictionary = 3769, 90 | jsonb = 3802, 91 | int4_range = 3904, 92 | record = 2249, 93 | record_array = 2287, 94 | cstring = 2275, 95 | any = 2276, 96 | any_array = 2277, 97 | void_ = 2278, 98 | trigger = 2279, 99 | evttrigger = 3838, 100 | language_handler = 2280, 101 | internal = 2281, 102 | opaque = 2282, 103 | any_element = 2283, 104 | any_non_array = 2776, 105 | any_enum = 3500, 106 | fdw_handler = 3115, 107 | any_range = 3831 108 | }; 109 | 110 | std::ostream& 111 | operator << (std::ostream& out, oid_type val); 112 | std::istream& 113 | operator >> (std::ostream& in, oid_type& val); 114 | 115 | 116 | } // namespace type 117 | namespace type_class { 118 | enum code { 119 | base = 'b', 120 | composite = 'c', 121 | domain = 'd', 122 | enumerated = 'e', 123 | pseudo = 'p', 124 | range = 'r' 125 | }; 126 | } // namespace type_class 127 | namespace type_category { 128 | enum code { 129 | invalid = 0, 130 | array = 'A', 131 | boolean = 'B', 132 | composite = 'C', 133 | datetime = 'D', 134 | enumeration = 'E', 135 | geometric = 'G', 136 | network = 'I', 137 | numeric = 'N', 138 | pseudotype = 'P', 139 | range_category = 'R', 140 | string = 'S', 141 | timespan = 'T', 142 | user = 'U', 143 | bitstring = 'V', 144 | unknown = 'X' 145 | }; 146 | } // type_category 147 | 148 | } // namespace oids 149 | 150 | } // namespace pg 151 | } // namespace db 152 | } // namespace tip 153 | 154 | 155 | #endif /* LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_PG_TYPES_HPP_ */ 156 | -------------------------------------------------------------------------------- /include/tip/db/pg/resultset.inl: -------------------------------------------------------------------------------- 1 | /* 2 | * resultset.inl 3 | * 4 | * Created on: Jul 16, 2015 5 | * Author: zmij 6 | */ 7 | 8 | #ifndef TIP_DB_PG_RESULTSET_INL_ 9 | #define TIP_DB_PG_RESULTSET_INL_ 10 | 11 | #include 12 | #include 13 | 14 | namespace tip { 15 | namespace db { 16 | namespace pg { 17 | 18 | namespace detail { 19 | 20 | 21 | template < size_t Index, typename T > 22 | struct nth_field { 23 | enum { 24 | index = Index 25 | }; 26 | typedef T type; 27 | 28 | nth_field(resultset::row const& r) : row(r) 29 | { 30 | } 31 | 32 | T value() 33 | { 34 | return row[index].template as(); 35 | } 36 | 37 | bool 38 | to(T& val) 39 | { 40 | return row[index].to(val); 41 | } 42 | 43 | resultset::row row; 44 | }; 45 | 46 | template < typename IndexTuple, typename ... T > 47 | struct row_data_extractor_base; 48 | 49 | template < size_t ... Indexes, typename ... T > 50 | struct row_data_extractor_base< util::indexes_tuple< Indexes ... >, T ... > { 51 | static constexpr ::std::size_t size = sizeof ... (T); 52 | 53 | static void 54 | get_tuple( resultset::row const& row, std::tuple< T ... >& val ) 55 | { 56 | std::tuple< T ... > tmp( nth_field< Indexes, T >(row).value() ... ); 57 | tmp.swap(val); 58 | } 59 | 60 | static void 61 | get_values( resultset::row const& row, T& ... val ) 62 | { 63 | util::expand(nth_field< Indexes, T >(row).to(val) ...); 64 | } 65 | }; 66 | 67 | template < typename ... T > 68 | struct row_data_extractor : 69 | row_data_extractor_base < typename util::index_builder< sizeof ... (T) >::type, T ... > { 70 | }; 71 | 72 | template < typename IndexTuple, typename ... T > 73 | struct field_by_name_extractor; 74 | 75 | template < ::std::size_t ... Indexes, typename ... T > 76 | struct field_by_name_extractor< util::indexes_tuple, T... > { 77 | static constexpr ::std::size_t size = sizeof ... (T); 78 | 79 | static void 80 | get_tuple( resultset::row const& row, 81 | ::std::initializer_list<::std::string> const& names, 82 | ::std::tuple< T... >& val ) 83 | { 84 | if (names.size() < size) 85 | throw error::db_error{"Not enough names in row data extraction"}; 86 | ::std::tuple tmp( row[*(names.begin() + Indexes)].template as()... ); 87 | tmp.swap(val); 88 | } 89 | 90 | static void 91 | get_values(resultset::row const& row, 92 | ::std::initializer_list<::std::string> const& names, 93 | T&... val) 94 | { 95 | util::expand{ row[*(names.begin() + Indexes)].to(val)... }; 96 | } 97 | }; 98 | 99 | template < typename ... T > 100 | struct row_data_by_name_extractor 101 | : field_by_name_extractor< typename util::index_builder< sizeof ... (T) >::type, T ... > {}; 102 | 103 | } // namespace detail 104 | 105 | template < typename ... T > 106 | void 107 | resultset::row::to(std::tuple< T ... >& val) const 108 | { 109 | detail::row_data_extractor< T ... >::get_tuple(*this, val); 110 | } 111 | 112 | template < typename ... T > 113 | void 114 | resultset::row::to(std::tuple< T& ... > val) const 115 | { 116 | std::tuple non_ref; 117 | detail::row_data_extractor< T ... >::get_tuple(*this, non_ref); 118 | val = non_ref; 119 | } 120 | 121 | template < typename ... T > 122 | void 123 | resultset::row::to(T& ... val) const 124 | { 125 | detail::row_data_extractor< T ... >::get_values(*this, val ...); 126 | } 127 | 128 | template < typename ... T > 129 | void 130 | resultset::row::to(::std::initializer_list<::std::string> const& names, 131 | ::std::tuple& val) const 132 | { 133 | detail::row_data_by_name_extractor::get_tuple(*this, names, val); 134 | } 135 | 136 | template < typename ... T > 137 | void 138 | resultset::row::to(::std::initializer_list<::std::string> const& names, 139 | ::std::tuple val) const 140 | { 141 | std::tuple non_ref; 142 | detail::row_data_by_name_extractor::get_tuple(*this, names, non_ref); 143 | val = non_ref; 144 | } 145 | 146 | template < typename ... T > 147 | void 148 | resultset::row::to(::std::initializer_list<::std::string> const& names, 149 | T& ... val) const 150 | { 151 | detail::row_data_by_name_extractor::get_values(*this, names, val...); 152 | } 153 | 154 | } // namespace pg 155 | } // namespace db 156 | } // namespace tip 157 | 158 | 159 | #endif /* TIP_DB_PG_RESULTSET_INL_ */ 160 | -------------------------------------------------------------------------------- /lib/afsm/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | 30 | # Build trees 31 | build* 32 | 33 | # Eclipse files 34 | .project 35 | .cproject 36 | .settings* 37 | 38 | # CLion settings 39 | .idea 40 | 41 | -------------------------------------------------------------------------------- /lib/afsm/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMakeLists.txt for afsm library 2 | # 3 | # @author zmij 4 | # @date Nov 30, 2015 5 | 6 | cmake_minimum_required(VERSION 2.6) 7 | 8 | # Set library name here 9 | set(lib_name afsm) 10 | string(TOUPPER ${lib_name} LIB_NAME) 11 | 12 | if (PROJECT_VERSION) 13 | set(_pversion ${PROJECT_VERSION}) 14 | else() 15 | set(_pversion 0.1.0) 16 | endif() 17 | 18 | if (${CMAKE_VERSION} VERSION_GREATER "3.0") 19 | cmake_policy(SET CMP0048 NEW) 20 | project(${lib_name} VERSION ${_pversion}) 21 | else() 22 | project(${lib_name}) 23 | set(PROJECT_VERSION ${_pversion}) 24 | endif() 25 | 26 | option(BUILD_TESTS "Build test programs" ON) 27 | option(BUILD_BENCHMARKS "Build benchmarks" OFF) 28 | option(BUILD_EXAMPLES "Build example programs" OFF) 29 | 30 | # TODO Check for Mac OS X 31 | if(NOT CMAKE_OSX_DEPLOYMENT_TARGET) 32 | set(CMAKE_OSX_DEPLOYMENT_TARGET 10.10) 33 | endif() 34 | 35 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) 36 | 37 | set( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules") 38 | 39 | add_definitions("-std=c++11") 40 | add_definitions(-Wall -Werror -Wextra -pedantic -Weffc++ 41 | -Wno-non-virtual-dtor # I really know what I am exactly doing 42 | ) 43 | 44 | set(${LIB_NAME}_LIB ${lib_name}) 45 | 46 | # Add subdirectories here 47 | 48 | if (NOT METAPUSHKIN_FOUND) 49 | add_subdirectory(lib/meta) 50 | endif() 51 | 52 | message(STATUS "Metapushkin include dir ${METAPUSHKIN_INCLUDE_DIRS}") 53 | include_directories(${METAPUSHKIN_INCLUDE_DIRS}) 54 | 55 | add_subdirectory(include) 56 | add_subdirectory(cmake) 57 | 58 | if (BUILD_TESTS) 59 | enable_testing() 60 | add_subdirectory(test) 61 | endif() 62 | if (BUILD_BENCHMARKS) 63 | add_subdirectory(benchmark) 64 | endif() 65 | 66 | if (BUILD_EXAMPLES) 67 | add_subdirectory(examples) 68 | endif() 69 | 70 | get_directory_property(has_parent PARENT_DIRECTORY) 71 | if (has_parent) 72 | set(${LIB_NAME}_INCLUDE_DIRS 73 | ${CMAKE_CURRENT_SOURCE_DIR}/include 74 | ${METAPUSHKIN_INCLUDE_DIRS} 75 | CACHE INTERNAL "Path to afsm libaray includes" ) 76 | endif() 77 | -------------------------------------------------------------------------------- /lib/afsm/README.md: -------------------------------------------------------------------------------- 1 | # Another Finite State Machine 2 | 3 | `afsm` is a finite state machine C++11 library designed for usage in multithreaded asynchronous environment. 4 | 5 | ## Inspiration and Motivation 6 | 7 | The `afsm` library was inspired by [`::boost::msm`](http://www.boost.org/doc/libs/1_62_0/libs/msm/doc/HTML/index.html) library and implemented so that the migration from `::boost::msm` was a bunch of search and replace operations. The main motivation was to create a thread-safe FSM library and to achieve decent compile times for large and complex state machines not sacrificing performance. A state machine defined with `afms` library compiles several times faster than same library defined with `::boost::msm` and has similar (or better) performance. You can find some benchmark results [here](https://github.com/zmij/afsm/wiki/Performance-Benchmarks). 8 | 9 | ## Features 10 | 11 | * Statechart features 12 | * Hierarchical states 13 | * [Entry and exit actions](https://github.com/zmij/afsm/wiki/Entry-and-Exit-Actions) 14 | * Internal transitions 15 | * [Transition actions](https://github.com/zmij/afsm/wiki/Transition-Actions) 16 | * [Transition guards (conditions)](https://github.com/zmij/afsm/wiki/Transition-Guards) 17 | * [State history](https://github.com/zmij/afsm/wiki/History) 18 | * [Event deferring](https://github.com/zmij/afsm/wiki/Event-Deferring) 19 | * [Orthogonal regions](https://github.com/zmij/afsm/wiki/Orthogonal-Regions) 20 | * Statechart extensions 21 | * Optional [event priority](https://github.com/zmij/afsm/wiki/Event-Priority) 22 | * Optional [common base](https://github.com/zmij/afsm/wiki/Common-Base) for states and easy definition of dispatching common interface calls to current state 23 | * [Pushdown automaton](https://github.com/zmij/afsm/wiki/Pushdown-Automaton) 24 | * Compile-time checks 25 | * [Thread safety](https://github.com/zmij/afsm/wiki/Thread-Safety) 26 | * Exception safety 27 | * No vtables (unless common base feature is used) 28 | * Header only 29 | * Relatively fast compile time 30 | * No external dependencies except STL 31 | 32 | ### Planned features 33 | 34 | * State machine persistense 35 | 36 | ## Synopsis 37 | 38 | Here is a UML diagram of a trivial state machine and source code that it is mapped to. 39 | ![minimal](https://cloud.githubusercontent.com/assets/2694027/20274791/f352998c-aaa6-11e6-99ec-fc63300766d7.png) 40 | 41 | ```c++ 42 | #include 43 | // Events 44 | struct start {}; 45 | struct stop {}; 46 | 47 | // State machine definition 48 | struct minimal_def : ::afsm::def::state_machine { 49 | //@{ 50 | /** @name States */ 51 | struct initial : state {}; 52 | struct running : state {}; 53 | struct terminated : terminal_state {}; 54 | //@} 55 | 56 | using initial_state = initial; 57 | using transitions = transition_table< 58 | /* State Event Next */ 59 | tr< initial, start, running >, 60 | tr< running, stop, terminated > 61 | >; 62 | }; 63 | 64 | // State machine object 65 | using minimal = ::afsm::state_machine; 66 | 67 | void use() 68 | { 69 | mimimal fsm; 70 | fsm.process_event(start{}); 71 | fsm.process_event(stop{}); 72 | } 73 | ``` 74 | 75 | You can find a tutorial covering most of basic features [here](https://github.com/zmij/afsm/wiki/Tutorial:-Vending-machine-FSM). 76 | 77 | ## Documentation 78 | 79 | Please see [project wiki](https://github.com/zmij/afsm/wiki) for documentation. *TODO* doxygen generated documentation. 80 | 81 | ## Installation 82 | 83 | The library is header only and doesn't requre build or installation. Just add the `afsm/include` and `lib/meta/include` directories under the root of this repository to your include paths. 84 | 85 | ### CMake subproject 86 | 87 | You can add the library to your project as a subtree, e.g. `lib/afsm`, and in your root `CMakeLists.txt` file just do the following: 88 | 89 | ```cmake 90 | add_subdirectory(lib/afsm) 91 | include_directories(${AFSM_INCLUDE_DIRS}) 92 | ``` 93 | 94 | TODO write docs on gitrc subtree commands and link to the repository 95 | 96 | ### Installation to System Directories 97 | 98 | ```bash 99 | git clone git@github.com:zmij/afsm.git 100 | mkdir afsm/build 101 | cd afsm/build 102 | cmake .. 103 | sudo make install 104 | ``` 105 | 106 | ### Finding the AFSM Package 107 | 108 | ```cmake 109 | find_package(AFSM REQUIRED) # Will set AFSM_INCLUDE_DIRS variable 110 | ``` 111 | 112 | ## License 113 | 114 | [The Artistic License 2.0](https://github.com/zmij/afsm/blob/develop/LICENSE) 115 | -------------------------------------------------------------------------------- /lib/afsm/benchmark/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # /afsm/benchmark/CMakeLists.txt 2 | # 3 | # @author zmij 4 | # @date May 26, 2016 5 | 6 | cmake_minimum_required(VERSION 2.6) 7 | 8 | if (NOT TARGET benchmark-afsm) 9 | enable_testing() 10 | 11 | if (NOT GBENCH_FOUND) 12 | find_package(GBenchmark REQUIRED) 13 | endif() 14 | if (NOT CMAKE_THREAD_LIBS_INIT) 15 | find_package(Threads REQUIRED) 16 | endif() 17 | 18 | # Add your package dependencies for test here 19 | 20 | include_directories(${GBENCH_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/../examples) 21 | 22 | set(benchmark_SRCS vending_benchmark.cpp defer_benchmark.cpp) 23 | add_executable(benchmark-afsm ${benchmark_SRCS}) 24 | target_link_libraries(benchmark-afsm 25 | ${GBENCH_LIBRARIES} 26 | ${CMAKE_THREAD_LIBS_INIT}) 27 | 28 | add_test( 29 | NAME benchmark-afsm 30 | COMMAND benchmark-afsm 31 | ) 32 | 33 | # Benchmark MSM 34 | find_package(Boost 1.58) 35 | if (Boost_FOUND) 36 | message(STATUS "Making benchmark with boost::msm library") 37 | include_directories(${Boost_INCLUDE_DIRS}) 38 | 39 | if (NOT GTEST_INCLUDE_DIRS) 40 | find_package(GTest REQUIRED) 41 | endif() 42 | set(test_msm_SRCS vending_msm_test.cpp) 43 | add_executable(test-msm ${test_msm_SRCS}) 44 | target_link_libraries(test-msm 45 | ${GTEST_BOTH_LIBRARIES} 46 | ${CMAKE_THREAD_LIBS_INIT}) 47 | 48 | set(benchmark_msm_SRCS vending_msm_benchmark.cpp) 49 | add_executable(benchmark-msm ${benchmark_msm_SRCS}) 50 | target_link_libraries(benchmark-msm 51 | ${GBENCH_LIBRARIES} 52 | ${CMAKE_THREAD_LIBS_INIT}) 53 | 54 | add_test( 55 | NAME benchmark-msm 56 | COMMAND benchmark-msm 57 | ) 58 | endif() 59 | endif() 60 | -------------------------------------------------------------------------------- /lib/afsm/benchmark/defer_benchmark.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * defer_benchmark.cpp 3 | * 4 | * Created on: Dec 21, 2016 5 | * Author: zmij 6 | */ 7 | 8 | #include 9 | 10 | #include 11 | 12 | 13 | namespace afsm { 14 | namespace bench { 15 | 16 | namespace events { 17 | 18 | struct a_to_b {}; 19 | struct b_to_a {}; 20 | struct b_to_c {}; 21 | struct c_to_a {}; 22 | struct c_to_b {}; 23 | 24 | } /* namespace events */ 25 | 26 | struct defer_fsm_def : ::afsm::def::state_machine_def { 27 | 28 | struct state_a : state {}; 29 | struct state_b : state { 30 | using deferred_events = type_tuple< events::a_to_b >; 31 | }; 32 | struct state_c : state { 33 | using deferred_events = type_tuple< events::a_to_b >; 34 | }; 35 | 36 | using initial_state = state_a; 37 | 38 | using transitions = transition_table< 39 | tr< state_a, events::a_to_b, state_b >, 40 | tr< state_b, events::b_to_c, state_c >, 41 | tr< state_b, events::b_to_a, state_a >, 42 | tr< state_c, events::c_to_a, state_a >, 43 | tr< state_c, events::c_to_b, state_b > 44 | >; 45 | }; 46 | 47 | using defer_fsm = ::afsm::state_machine; 48 | 49 | namespace { 50 | 51 | void 52 | enqueue_events(defer_fsm& fsm, int n) 53 | { 54 | for (int i = 0; i < n; ++i) { 55 | fsm.process_event(events::a_to_b{}); 56 | } 57 | } 58 | 59 | } /* namespace */ 60 | 61 | void 62 | DeferNoDefer(::benchmark::State& state) 63 | { 64 | while(state.KeepRunning()) { 65 | defer_fsm fsm; 66 | fsm.process_event(events::a_to_b{}); 67 | } 68 | } 69 | 70 | void 71 | DeferReject(::benchmark::State& state) 72 | { 73 | while(state.KeepRunning()) { 74 | defer_fsm fsm; 75 | fsm.process_event(events::a_to_b{}); 76 | } 77 | } 78 | 79 | void 80 | DeferEnqueue(::benchmark::State& state) 81 | { 82 | defer_fsm fsm; 83 | 84 | fsm.process_event(events::a_to_b{}); 85 | 86 | while(state.KeepRunning()) { 87 | ::benchmark::DoNotOptimize(fsm.process_event(events::a_to_b{})); 88 | } 89 | } 90 | 91 | void 92 | DeferIgnore(::benchmark::State& state) 93 | { 94 | while(state.KeepRunning()) { 95 | state.PauseTiming(); 96 | defer_fsm fsm; 97 | fsm.process_event(events::a_to_b{}); 98 | // Enqueue N events 99 | enqueue_events(fsm, state.range(0)); 100 | state.ResumeTiming(); 101 | fsm.process_event(events::b_to_c{}); 102 | } 103 | state.SetComplexityN(state.range(0)); 104 | } 105 | 106 | void 107 | DeferProcessOne(::benchmark::State& state) 108 | { 109 | while(state.KeepRunning()) { 110 | state.PauseTiming(); 111 | defer_fsm fsm; 112 | fsm.process_event(events::a_to_b{}); 113 | // Enqueue N events 114 | enqueue_events(fsm, state.range(0)); 115 | state.ResumeTiming(); 116 | fsm.process_event(events::b_to_a{}); 117 | } 118 | state.SetComplexityN(state.range(0)); 119 | } 120 | 121 | BENCHMARK(DeferNoDefer); 122 | BENCHMARK(DeferReject); 123 | BENCHMARK(DeferEnqueue); 124 | BENCHMARK(DeferIgnore)->RangeMultiplier(10)->Range(1, 100000)->Complexity(); 125 | BENCHMARK(DeferProcessOne)->RangeMultiplier(10)->Range(1, 100000)->Complexity(); 126 | 127 | } /* namespace bench */ 128 | } /* namespace afsm */ 129 | 130 | -------------------------------------------------------------------------------- /lib/afsm/benchmark/vending_benchmark.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * vending_benchmark.cpp 3 | * 4 | * Created on: Nov 18, 2016 5 | * Author: zmij 6 | */ 7 | 8 | #include 9 | #include "vending_machine.hpp" 10 | 11 | namespace vending { 12 | 13 | void 14 | AFSM_ConstructDefault(::benchmark::State& state) 15 | { 16 | while (state.KeepRunning()) { 17 | vending_machine vm; 18 | } 19 | } 20 | 21 | void 22 | AFSM_ConstructWithData(::benchmark::State& state) 23 | { 24 | while (state.KeepRunning()) { 25 | vending_machine vm{ goods_storage{ 26 | { 0, { 10, 15.0f } }, 27 | { 1, { 100, 5.0f } } 28 | }}; 29 | } 30 | } 31 | 32 | void 33 | AFSM_ProcessSingleEvent(::benchmark::State& state) 34 | { 35 | vending_machine vm{ goods_storage{ 36 | { 0, { 10, 15.0f } }, 37 | { 1, { 100, 5.0f } } 38 | }}; 39 | vm.process_event(events::power_on{}); 40 | while (state.KeepRunning()) { 41 | vm.process_event(events::money{100}); 42 | } 43 | } 44 | 45 | void 46 | AFSM_OnOffEmpty(::benchmark::State& state) // With a default transition 47 | { 48 | vending_machine vm; 49 | while(state.KeepRunning()) { 50 | vm.process_event(events::power_on{}); 51 | vm.process_event(events::power_off{}); 52 | } 53 | } 54 | 55 | void 56 | AFSM_OnOffLoaded(::benchmark::State& state) // Without a default transition 57 | { 58 | vending_machine vm{ goods_storage{ 59 | { 0, { 10, 15.0f } }, 60 | { 1, { 100, 5.0f } } 61 | }}; 62 | while(state.KeepRunning()) { 63 | vm.process_event(events::power_on{}); 64 | vm.process_event(events::power_off{}); 65 | } 66 | } 67 | 68 | void 69 | AFSM_BuyItem(::benchmark::State& state) 70 | { 71 | vending_machine vm{ goods_storage{ 72 | { 0, { 1000000000, 15.0f } }, 73 | { 1, { 1000000000, 5.0f } } 74 | }}; 75 | vm.process_event(events::power_on{}); 76 | while(state.KeepRunning()) { 77 | vm.process_event(events::money{3}); 78 | vm.process_event(events::money{3}); 79 | vm.process_event(events::select_item{1}); 80 | } 81 | } 82 | 83 | BENCHMARK(AFSM_ConstructDefault); 84 | BENCHMARK(AFSM_ConstructWithData); 85 | BENCHMARK(AFSM_ProcessSingleEvent); 86 | BENCHMARK(AFSM_OnOffEmpty); 87 | BENCHMARK(AFSM_OnOffLoaded); 88 | BENCHMARK(AFSM_BuyItem); 89 | 90 | } /* namespace vending */ 91 | 92 | BENCHMARK_MAIN() 93 | -------------------------------------------------------------------------------- /lib/afsm/benchmark/vending_msm_benchmark.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * vending_msm_benchmark.cpp 3 | * 4 | * Created on: Nov 18, 2016 5 | * Author: zmij 6 | */ 7 | 8 | #include 9 | 10 | #include "vending_machine_msm.hpp" 11 | 12 | namespace vending_msm { 13 | 14 | void 15 | MSM_ConstructDefault(::benchmark::State& state) 16 | { 17 | while (state.KeepRunning()) { 18 | vending_machine vm; 19 | } 20 | } 21 | 22 | void 23 | MSM_ConstructWithData(::benchmark::State& state) 24 | { 25 | while (state.KeepRunning()) { 26 | vending_machine vm{ goods_storage{ 27 | { 0, { 10, 15.0f } }, 28 | { 1, { 100, 5.0f } } 29 | }}; 30 | } 31 | } 32 | 33 | void 34 | MSM_ProcessSingleEvent(::benchmark::State& state) 35 | { 36 | vending_machine vm{ goods_storage{ 37 | { 0, { 10, 15.0f } }, 38 | { 1, { 100, 5.0f } } 39 | }}; 40 | vm.start(); 41 | vm.process_event(events::power_on{}); 42 | while (state.KeepRunning()) { 43 | vm.process_event(events::money{100}); 44 | } 45 | } 46 | 47 | void 48 | MSM_OnOffEmpty(::benchmark::State& state) // With a default transition 49 | { 50 | vending_machine vm; 51 | vm.start(); 52 | while(state.KeepRunning()) { 53 | vm.process_event(events::power_on{}); 54 | vm.process_event(events::power_off{}); 55 | } 56 | } 57 | 58 | void 59 | MSM_OnOffLoaded(::benchmark::State& state) // Without a default transition 60 | { 61 | vending_machine vm{ goods_storage{ 62 | { 0, { 10, 15.0f } }, 63 | { 1, { 100, 5.0f } } 64 | }}; 65 | vm.start(); 66 | while(state.KeepRunning()) { 67 | vm.process_event(events::power_on{}); 68 | vm.process_event(events::power_off{}); 69 | } 70 | } 71 | 72 | void 73 | MSM_BuyItem(::benchmark::State& state) 74 | { 75 | vending_machine vm{ goods_storage{ 76 | { 0, { 1000000000, 15.0f } }, 77 | { 1, { 1000000000, 5.0f } } 78 | }}; 79 | vm.start(); 80 | vm.process_event(events::power_on{}); 81 | while(state.KeepRunning()) { 82 | vm.process_event(events::money{3}); 83 | vm.process_event(events::money{3}); 84 | vm.process_event(events::select_item{1}); 85 | } 86 | } 87 | 88 | BENCHMARK(MSM_ConstructDefault); 89 | BENCHMARK(MSM_ConstructWithData); 90 | BENCHMARK(MSM_ProcessSingleEvent); 91 | BENCHMARK(MSM_OnOffEmpty); 92 | BENCHMARK(MSM_OnOffLoaded); 93 | BENCHMARK(MSM_BuyItem); 94 | 95 | 96 | } /* namespace vending_msm */ 97 | 98 | BENCHMARK_MAIN() 99 | -------------------------------------------------------------------------------- /lib/afsm/cmake/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # /afsm/cmake/CMakeLists.txt 2 | # 3 | # @author zmij 4 | # @date Nov 18, 2016 5 | 6 | cmake_minimum_required(VERSION 2.6) 7 | 8 | if(NOT CMAKE_SCRIPT_INSTALL_DIR) 9 | find_path(CMAKE_SCRIPT_INSTALL_DIR "CheckLanguage.cmake" 10 | PATHS ${CMAKE_ROOT} 11 | PATH_SUFFIXES Modules ) 12 | endif() 13 | 14 | if (CMAKE_SCRIPT_INSTALL_DIR) 15 | file(GLOB find_scripts Find*.cmake) 16 | install( 17 | FILES ${find_scripts} 18 | DESTINATION ${CMAKE_SCRIPT_INSTALL_DIR}) 19 | else() 20 | message(WARNING "Failed to find target directory for installing cmake Find scripts") 21 | endif() 22 | -------------------------------------------------------------------------------- /lib/afsm/cmake/FindAFSM.cmake: -------------------------------------------------------------------------------- 1 | # /afsm/cmake/FindAFSM.cmake 2 | # Try to find afsm library 3 | # 4 | # The following variables are optionally searched for defaults 5 | # AFSM_ROOT_DIR: Base directory where include directory can be found 6 | # 7 | # Once done this will define 8 | # AFSM_FOUND - System has afsm library 9 | # AFSM_INCLUDE_DIRS - The afsm include directories 10 | 11 | # Library requires metapushkin library and will additionally search for it 12 | 13 | find_package(MetaPushkin REQUIRED) 14 | 15 | if(NOT AFSM_FOUND) 16 | 17 | set(AFSM_ROOT_DIR "" CACHE PATH "Folder containing afsm library") 18 | 19 | find_path(AFSM_INCLUDE_DIR "afsm/fsm.hpp" 20 | PATHS ${AFSM_ROOT_DIR} 21 | PATH_SUFFIXES include 22 | NO_DEFAULT_PATH) 23 | 24 | find_path(AFSM_INCLUDE_DIR "afsm/fsm.hpp") 25 | 26 | include(FindPackageHandleStandardArgs) 27 | # handle the QUIETLY and REQUIRED arguments and set benchmark_FOUND to TRUE 28 | # if all listed variables are TRUE 29 | find_package_handle_standard_args(AFSM FOUND_VAR AFSM_FOUND 30 | REQUIRED_VARS AFSM_INCLUDE_DIR) 31 | 32 | if(AFSM_FOUND) 33 | set(AFSM_INCLUDE_DIRS ${AFSM_INCLUDE_DIR}) 34 | endif() 35 | 36 | mark_as_advanced(AFSM_INCLUDE_DIR) 37 | 38 | endif() 39 | -------------------------------------------------------------------------------- /lib/afsm/cmake/modules/FindGBenchmark.cmake: -------------------------------------------------------------------------------- 1 | # Findbenchmark.cmake 2 | # - Try to find benchmark 3 | # 4 | # The following variables are optionally searched for defaults 5 | # GBENCH_ROOT_DIR: Base directory where all benchmark components are found 6 | # 7 | # Once done this will define 8 | # GBENCH_FOUND - System has benchmark 9 | # GBENCH_INCLUDE_DIRS - The benchmark include directories 10 | # GBENCH_LIBRARIES - The libraries needed to use benchmark 11 | 12 | set(GBENCH_ROOT_DIR "" CACHE PATH "Folder containing benchmark") 13 | 14 | find_path(GBENCH_INCLUDE_DIR "benchmark/benchmark.h" 15 | PATHS ${GBENCH_ROOT_DIR} 16 | PATH_SUFFIXES include 17 | NO_DEFAULT_PATH) 18 | find_path(GBENCH_INCLUDE_DIR "benchmark/benchmark.h") 19 | 20 | find_library(GBENCH_LIBRARY NAMES "benchmark" 21 | PATHS ${GBENCH_ROOT_DIR} 22 | PATH_SUFFIXES lib lib64 23 | NO_DEFAULT_PATH) 24 | find_library(GBENCH_LIBRARY NAMES "benchmark") 25 | 26 | include(FindPackageHandleStandardArgs) 27 | # handle the QUIETLY and REQUIRED arguments and set benchmark_FOUND to TRUE 28 | # if all listed variables are TRUE 29 | find_package_handle_standard_args(GBENCH FOUND_VAR GBENCH_FOUND 30 | REQUIRED_VARS GBENCH_LIBRARY 31 | GBENCH_INCLUDE_DIR) 32 | 33 | if(GBENCH_FOUND) 34 | set(GBENCH_LIBRARIES ${GBENCH_LIBRARY}) 35 | set(GBENCH_INCLUDE_DIRS ${GBENCH_INCLUDE_DIR}) 36 | endif() 37 | 38 | mark_as_advanced(GBENCH_INCLUDE_DIR GBENCH_LIBRARY) 39 | -------------------------------------------------------------------------------- /lib/afsm/examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # /afsm/examples/CMakeLists.txt 2 | # 3 | # @author zmij 4 | # @date Nov 14, 2016 5 | 6 | cmake_minimum_required(VERSION 2.6) 7 | 8 | file(GLOB examples *.cpp) 9 | foreach(file ${examples}) 10 | get_filename_component(tgt_name ${file} NAME_WE) 11 | add_executable(${tgt_name} ${file}) 12 | endforeach() 13 | -------------------------------------------------------------------------------- /lib/afsm/examples/minimal.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * minimal.cpp 3 | * 4 | * Created on: Nov 14, 2016 5 | * Author: zmij 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | namespace minimal { 12 | 13 | // Events 14 | struct start {}; 15 | struct stop {}; 16 | 17 | // State machine definition 18 | struct minimal_def : ::afsm::def::state_machine { 19 | struct initial : state {}; 20 | struct running : state {}; 21 | struct terminated : terminal_state {}; 22 | 23 | using initial_state = initial; 24 | using transitions = transition_table< 25 | /* State Event Next */ 26 | tr< initial, start, running >, 27 | tr< running, stop, terminated > 28 | >; 29 | }; 30 | 31 | // State machine object 32 | using minimal = ::afsm::state_machine; 33 | 34 | void 35 | use() 36 | { 37 | minimal fsm; 38 | fsm.process_event(start{}); 39 | fsm.process_event(stop{}); 40 | } 41 | 42 | } /* namespace minimal */ 43 | 44 | int 45 | main(int, char*[]) 46 | try { 47 | minimal::use(); 48 | return 0; 49 | } catch (::std::exception const& e) { 50 | ::std::cerr << "Exception: " << e.what() << "\n"; 51 | return 1; 52 | } catch (...) { 53 | ::std::cerr << "Unexpected exception\n"; 54 | return 2; 55 | } 56 | -------------------------------------------------------------------------------- /lib/afsm/examples/minimal_actions.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * minimal.cpp 3 | * 4 | * Created on: Nov 14, 2016 5 | * Author: zmij 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | namespace minimal { 12 | 13 | // Events 14 | struct start {}; 15 | struct stop {}; 16 | 17 | // Actions 18 | struct do_start{ 19 | template < typename Event, typename FSM, typename SourceState, typename TargetState > 20 | void 21 | operator()(Event const&, FSM&, SourceState&, TargetState&) const 22 | { 23 | ::std::cout << "do start\n"; 24 | } 25 | }; 26 | struct do_stop { 27 | template < typename Event, typename FSM, typename SourceState, typename TargetState > 28 | void 29 | operator()(Event const&, FSM&, SourceState&, TargetState&) const 30 | { 31 | ::std::cout << "do stop\n"; 32 | } 33 | }; 34 | 35 | // State machine definition 36 | struct minimal_def : ::afsm::def::state_machine { 37 | struct initial : state {}; 38 | struct running : state {}; 39 | struct terminated : terminal_state {}; 40 | 41 | using initial_state = initial; 42 | using transitions = transition_table< 43 | /* State Event Next Action */ 44 | tr< initial, start, running, do_start >, 45 | tr< running, stop, terminated, do_stop > 46 | >; 47 | }; 48 | 49 | // State machine object 50 | using minimal = ::afsm::state_machine; 51 | 52 | void 53 | use() 54 | { 55 | minimal fsm; 56 | fsm.process_event(start{}); 57 | fsm.process_event(stop{}); 58 | } 59 | 60 | } /* namespace minimal */ 61 | 62 | int 63 | main(int, char*[]) 64 | try { 65 | minimal::use(); 66 | return 0; 67 | } catch (::std::exception const& e) { 68 | ::std::cerr << "Exception: " << e.what() << "\n"; 69 | return 1; 70 | } catch (...) { 71 | ::std::cerr << "Unexpected exception\n"; 72 | return 2; 73 | } 74 | -------------------------------------------------------------------------------- /lib/afsm/examples/minimal_entry_exit.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * minimal.cpp 3 | * 4 | * Created on: Nov 14, 2016 5 | * Author: zmij 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | namespace minimal { 12 | 13 | // Events 14 | struct start {}; 15 | struct stop {}; 16 | 17 | // State machine definition 18 | struct minimal_def : ::afsm::def::state_machine { 19 | struct initial : state { 20 | template < typename Event, typename FSM > 21 | void 22 | on_exit(Event const&, FSM&) 23 | { 24 | ::std::cout << "exit initial\n"; 25 | } 26 | }; 27 | struct running : state { 28 | template < typename Event, typename FSM > 29 | void 30 | on_enter(Event const&, FSM&) 31 | { 32 | ::std::cout << "enter running\n"; 33 | } 34 | template < typename Event, typename FSM > 35 | void 36 | on_exit(Event const&, FSM&) 37 | { 38 | ::std::cout << "exit running\n"; 39 | } 40 | }; 41 | struct terminated : terminal_state { 42 | template < typename Event, typename FSM > 43 | void 44 | on_enter(Event const&, FSM&) 45 | { 46 | ::std::cout << "enter terminated\n"; 47 | } 48 | }; 49 | 50 | using initial_state = initial; 51 | using transitions = transition_table< 52 | /* State Event Next */ 53 | tr< initial, start, running >, 54 | tr< running, stop, terminated > 55 | >; 56 | }; 57 | 58 | // State machine object 59 | using minimal = ::afsm::state_machine; 60 | 61 | void 62 | use() 63 | { 64 | minimal fsm; 65 | fsm.process_event(start{}); 66 | fsm.process_event(stop{}); 67 | } 68 | 69 | } /* namespace minimal */ 70 | 71 | int 72 | main(int, char*[]) 73 | try { 74 | minimal::use(); 75 | return 0; 76 | } catch (::std::exception const& e) { 77 | ::std::cerr << "Exception: " << e.what() << "\n"; 78 | return 1; 79 | } catch (...) { 80 | ::std::cerr << "Unexpected exception\n"; 81 | return 2; 82 | } 83 | -------------------------------------------------------------------------------- /lib/afsm/examples/pausing.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * minimal.cpp 3 | * 4 | * Created on: Nov 14, 2016 5 | * Author: zmij 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | namespace pausing { 12 | 13 | // Events 14 | struct start {}; 15 | struct stop {}; 16 | struct pause {}; 17 | 18 | // State machine definition 19 | struct pausing_def : ::afsm::def::state_machine { 20 | struct initial : state {}; 21 | struct running : state {}; 22 | struct paused : state {}; 23 | struct terminated : terminal_state {}; 24 | 25 | using initial_state = initial; 26 | using transitions = transition_table< 27 | /* State Event Next */ 28 | tr< initial, start, running >, 29 | tr< running, pause, paused >, 30 | tr< paused, stop, terminated >, 31 | tr< running, stop, terminated > 32 | >; 33 | }; 34 | 35 | // State machine object 36 | using pausing = ::afsm::state_machine; 37 | 38 | void 39 | use() 40 | { 41 | pausing fsm; 42 | fsm.process_event(start{}); 43 | fsm.process_event(pause{}); 44 | fsm.process_event(start{}); 45 | fsm.process_event(stop{}); 46 | } 47 | 48 | } /* namespace pausing */ 49 | 50 | int 51 | main(int, char*[]) 52 | try { 53 | pausing::use(); 54 | return 0; 55 | } catch (::std::exception const& e) { 56 | ::std::cerr << "Exception: " << e.what() << "\n"; 57 | return 1; 58 | } catch (...) { 59 | ::std::cerr << "Unexpected exception\n"; 60 | return 2; 61 | } 62 | -------------------------------------------------------------------------------- /lib/afsm/examples/vending.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * vending.cpp 3 | * 4 | * Created on: Nov 15, 2016 5 | * Author: zmij 6 | */ 7 | 8 | #include 9 | #include "vending_machine.hpp" 10 | 11 | using vending_machine = vending::vending_machine; 12 | 13 | int 14 | main(int, char*[]) 15 | try { 16 | vending_machine vm; 17 | return 0; 18 | } catch (::std::exception const& e) { 19 | ::std::cerr << "Exception: " << e.what() << "\n"; 20 | return 1; 21 | } catch (...) { 22 | ::std::cerr << "Unexpected exception\n"; 23 | return 2; 24 | } 25 | -------------------------------------------------------------------------------- /lib/afsm/examples/vending_starter.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * vending_starter.cpp 3 | * 4 | * Created on: Nov 15, 2016 5 | * Author: zmij 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | namespace vending { 12 | 13 | namespace events { 14 | 15 | struct power_on {}; 16 | struct power_off {}; 17 | 18 | } /* namespace events */ 19 | 20 | struct vending_def : ::afsm::def::state_machine { 21 | //@{ 22 | /** @name Substates definition */ 23 | struct off : state {}; 24 | struct on : state {}; 25 | //@} 26 | 27 | /** Initial state machine state */ 28 | using initial_state = off; 29 | 30 | /** State transition table */ 31 | using transitions = transition_table < 32 | /* Start Event Next */ 33 | tr< off, events::power_on, on >, 34 | tr< on, events::power_off, off > 35 | >; 36 | }; 37 | 38 | using vending_sm = ::afsm::state_machine; 39 | 40 | ::std::ostream& 41 | operator << (::std::ostream& os, vending_sm const& val) 42 | { 43 | ::std::ostream::sentry s(os); 44 | if (s) { 45 | os << (val.is_in_state< vending_sm::on >() ? "ON" : "OFF"); 46 | } 47 | return os; 48 | } 49 | 50 | 51 | void 52 | use() 53 | { 54 | vending_sm vm; 55 | ::std::cout << "Machine is " << vm << "\n"; 56 | vm.process_event(events::power_on{}); 57 | ::std::cout << "Machine is " << vm << "\n"; 58 | vm.process_event(events::power_off{}); 59 | ::std::cout << "Machine is " << vm << "\n"; 60 | } 61 | 62 | } /* namespace vending */ 63 | 64 | int 65 | main(int, char*[]) 66 | try { 67 | vending::use(); 68 | return 0; 69 | } catch (::std::exception const& e) { 70 | ::std::cerr << "Exception: " << e.what() << "\n"; 71 | return 1; 72 | } catch (...) { 73 | ::std::cerr << "Unexpected exception\n"; 74 | return 2; 75 | } 76 | -------------------------------------------------------------------------------- /lib/afsm/include/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # /afsm/include/CMakeLists.txt 2 | # 3 | # @author zmij 4 | # @date Nov 18, 2016 5 | 6 | cmake_minimum_required(VERSION 2.6) 7 | 8 | install( 9 | DIRECTORY afsm 10 | DESTINATION include 11 | FILES_MATCHING PATTERN *.hpp PATTERN *.inl 12 | ) 13 | -------------------------------------------------------------------------------- /lib/afsm/include/afsm/definition_fwd.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * definition_fwd.hpp 3 | * 4 | * Created on: 1 июня 2016 г. 5 | * Author: sergey.fedorov 6 | */ 7 | 8 | #ifndef AFSM_DEFINITION_FWD_HPP_ 9 | #define AFSM_DEFINITION_FWD_HPP_ 10 | 11 | namespace afsm { 12 | namespace def { 13 | 14 | template < typename T, typename ... Tags > 15 | struct state_def; 16 | template < typename StateType, typename ... Tags > 17 | using state = state_def< StateType, Tags... >; 18 | 19 | template < typename T, typename ... Tags > 20 | struct terminal_state; 21 | 22 | template < typename T, typename Machine, typename ... Tags > 23 | struct pushdown; 24 | template < typename T, typename Machine, typename ... Tags > 25 | struct popup; 26 | 27 | template < typename T, typename ... Tags > 28 | struct state_machine_def; 29 | template < typename T, typename ... Tags > 30 | using state_machine = state_machine_def; 31 | 32 | template < typename SourceState, typename Event, typename TargetState, 33 | typename Action = none, typename Guard = none > 34 | struct transition; 35 | template < typename Event, typename Action = none, typename Guard = none > 36 | struct internal_transition; 37 | template < typename ... T > 38 | struct transition_table; 39 | 40 | } /* namespace def */ 41 | namespace detail { 42 | 43 | template 44 | struct pushdown_state; 45 | 46 | template 47 | struct popup_state; 48 | } /* namespace detail */ 49 | } /* namespace afsm */ 50 | 51 | #endif /* AFSM_DEFINITION_FWD_HPP_ */ 52 | -------------------------------------------------------------------------------- /lib/afsm/include/afsm/detail/debug_io.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * debug_io.hpp 3 | * 4 | * Created on: 2 июня 2016 г. 5 | * Author: sergey.fedorov 6 | */ 7 | 8 | #ifndef AFSM_DETAIL_DEBUG_IO_HPP_ 9 | #define AFSM_DETAIL_DEBUG_IO_HPP_ 10 | 11 | #include 12 | #include 13 | 14 | namespace afsm { 15 | namespace actions { 16 | 17 | inline ::std::ostream& 18 | operator << (::std::ostream& os, event_process_result const& val) 19 | { 20 | ::std::ostream::sentry s (os); 21 | if (s) { 22 | switch (val) { 23 | case event_process_result::refuse: 24 | os << "refuse"; 25 | break; 26 | case event_process_result::process: 27 | os << "transit"; 28 | break; 29 | case event_process_result::process_in_state: 30 | os << "in-state"; 31 | break; 32 | case event_process_result::defer: 33 | os << "defer"; 34 | break; 35 | default: 36 | break; 37 | } 38 | } 39 | return os; 40 | } 41 | 42 | 43 | } /* namespace actions */ 44 | } /* namespace afsm */ 45 | 46 | #endif /* AFSM_DETAIL_DEBUG_IO_HPP_ */ 47 | -------------------------------------------------------------------------------- /lib/afsm/include/afsm/detail/event_identity.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * event_identity.hpp 3 | * 4 | * Created on: Dec 20, 2016 5 | * Author: zmij 6 | */ 7 | 8 | #ifndef AFSM_DETAIL_EVENT_IDENTITY_HPP_ 9 | #define AFSM_DETAIL_EVENT_IDENTITY_HPP_ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | namespace afsm { 16 | namespace detail { 17 | 18 | struct event_base { 19 | struct id_type {}; 20 | }; 21 | 22 | template < typename T > 23 | struct event : event_base { 24 | static constexpr id_type id{}; 25 | }; 26 | 27 | template < typename T > 28 | constexpr event_base::id_type event::id; 29 | 30 | template < typename T > 31 | struct event_identity { 32 | using event_type = typename ::std::decay::type; 33 | using type = event; 34 | }; 35 | 36 | using event_set = ::std::set< event_base::id_type const* >; 37 | 38 | template < typename ... T > 39 | event_set 40 | make_event_set( ::psst::meta::type_tuple const& ) 41 | { 42 | return event_set{ 43 | &event_identity::type::id... 44 | }; 45 | } 46 | 47 | } /* namespace detail */ 48 | } /* namespace afsm */ 49 | 50 | 51 | 52 | #endif /* AFSM_DETAIL_EVENT_IDENTITY_HPP_ */ 53 | -------------------------------------------------------------------------------- /lib/afsm/include/afsm/detail/exception_safety_guarantees.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * exception_safety_guarantees.hpp 3 | * 4 | * Created on: Nov 30, 2016 5 | * Author: zmij 6 | */ 7 | 8 | #ifndef AFSM_DETAIL_EXCEPTION_SAFETY_GUARANTEES_HPP_ 9 | #define AFSM_DETAIL_EXCEPTION_SAFETY_GUARANTEES_HPP_ 10 | 11 | 12 | namespace afsm { 13 | namespace def { 14 | namespace tags { 15 | 16 | /** 17 | * Default exception safety guarantee 18 | * On an exception caused by 19 | * * a guard check nothing happens 20 | * * state exit action - only data modified by exit action before exception 21 | * * transition action - previous and data modified by the transition action 22 | * * state enter action - previous and data modified by the enter action 23 | * * source state constructor - all of the above 24 | */ 25 | struct basic_exception_safety {}; 26 | /** 27 | * Strong exception safety guarantee 28 | * If an exception is thrown in the course of transition, nothing will be modified. 29 | * 30 | * Requires non-throwing swap operations 31 | * The exception will be thrown. 32 | */ 33 | struct strong_exception_safety {}; 34 | /** 35 | * Same as the strong exception safety, but the exception will be consumed 36 | * The event will be rejected and further behavior is ruled by event rejection 37 | * policies. 38 | */ 39 | struct nothrow_guarantee {}; 40 | 41 | } /* namespace tags */ 42 | } /* namespace def */ 43 | } /* namespace afsm */ 44 | 45 | 46 | #endif /* AFSM_DETAIL_EXCEPTION_SAFETY_GUARANTEES_HPP_ */ 47 | -------------------------------------------------------------------------------- /lib/afsm/include/afsm/detail/reject_policies.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * reject_policies.hpp 3 | * 4 | * Created on: Nov 30, 2016 5 | * Author: zmij 6 | */ 7 | 8 | #ifndef AFSM_DETAIL_REJECT_POLICIES_HPP_ 9 | #define AFSM_DETAIL_REJECT_POLICIES_HPP_ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | namespace afsm { 16 | namespace def { 17 | namespace tags { 18 | 19 | struct reject_throw_event { 20 | template < typename Event, typename FSM > 21 | actions::event_process_result 22 | reject_event(Event&& event, FSM&) 23 | { 24 | throw event; 25 | } 26 | }; 27 | 28 | struct reject_throw { 29 | template < typename Event, typename FSM > 30 | actions::event_process_result 31 | reject_event(Event&&, FSM&) 32 | { 33 | using ::psst::util::demangle; 34 | throw ::std::runtime_error{ 35 | "An instance of " + demangle() + " event was rejected" 36 | }; 37 | } 38 | }; 39 | 40 | } /* namespace tags */ 41 | } /* namespace def */ 42 | } /* namespace afsm */ 43 | 44 | 45 | #endif /* AFSM_DETAIL_REJECT_POLICIES_HPP_ */ 46 | -------------------------------------------------------------------------------- /lib/afsm/include/afsm/detail/tags.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * tags.hpp 3 | * 4 | * Created on: 1 июня 2016 г. 5 | * Author: sergey.fedorov 6 | */ 7 | 8 | #ifndef AFSM_DETAIL_TAGS_HPP_ 9 | #define AFSM_DETAIL_TAGS_HPP_ 10 | 11 | namespace afsm { 12 | namespace def { 13 | namespace tags { 14 | 15 | /** 16 | * Tag for state class. 17 | * For internal use only. 18 | */ 19 | struct state {}; 20 | /** 21 | * Tag for state machine class. 22 | * For internal use only. 23 | */ 24 | struct state_machine{}; 25 | 26 | /** 27 | * Tag for marking states with history. 28 | */ 29 | struct has_history {}; 30 | /** 31 | * Tag for marking states having common base class. 32 | * For internal use. 33 | */ 34 | struct has_common_base {}; 35 | 36 | /** 37 | * Tag for marking state having common base. 38 | */ 39 | template < typename T > 40 | struct common_base : T, has_common_base { 41 | using common_base_type = T; 42 | using common_base_tag_type = common_base; 43 | }; 44 | 45 | template <> 46 | struct common_base { 47 | using common_base_type = void; 48 | using common_base_tag_type = common_base; 49 | }; 50 | 51 | /** 52 | * Tag for marking state having common virtual base. 53 | */ 54 | template < typename T > 55 | struct virtual_common_base : virtual T, has_common_base { 56 | using common_base_type = T; 57 | using common_base_tag_type = virtual_common_base; 58 | }; 59 | 60 | template <> 61 | struct virtual_common_base { 62 | using common_base_type = void; 63 | using common_base_tag_type = virtual_common_base; 64 | }; 65 | 66 | //@{ 67 | /** @name Push/pop tags */ 68 | struct pushdown_state {}; 69 | struct popup_state {}; 70 | 71 | template < typename T > 72 | struct pushdown : pushdown_state { 73 | using pushdown_machine_type = T; 74 | }; 75 | 76 | template < typename T > 77 | struct popup : popup_state { 78 | using pushdown_machine_type = T; 79 | }; 80 | //@} 81 | 82 | struct allow_empty_enter_exit {}; 83 | struct mandatory_empty_enter_exit {}; 84 | 85 | } /* namespace tags */ 86 | } /* namespace def */ 87 | } /* namespace afsm */ 88 | 89 | #endif /* AFSM_DETAIL_TAGS_HPP_ */ 90 | -------------------------------------------------------------------------------- /lib/afsm/include/afsm/fsm_fwd.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * fsm_fwd.hpp 3 | * 4 | * Created on: 28 мая 2016 г. 5 | * Author: sergey.fedorov 6 | */ 7 | 8 | #ifndef AFSM_FSM_FWD_HPP_ 9 | #define AFSM_FSM_FWD_HPP_ 10 | 11 | namespace afsm { 12 | 13 | struct none {}; 14 | 15 | namespace detail { 16 | template < typename Observer > 17 | class observer_wrapper; 18 | 19 | } 20 | 21 | template < typename FSM, typename T > 22 | class state; 23 | template < typename FSM, typename T > 24 | class inner_state_machine; 25 | template < typename T, typename Mutex = none, typename Observer = none, 26 | template class ObserverWrapper = detail::observer_wrapper > 27 | class state_machine; 28 | template < typename T, typename Mutex = none, typename Observer = none, 29 | template class ObserverWrapper = detail::observer_wrapper > 30 | class priority_state_machine; 31 | 32 | } /* namespace afsm */ 33 | 34 | #endif /* AFSM_FSM_FWD_HPP_ */ 35 | -------------------------------------------------------------------------------- /lib/afsm/lib/ansi-colors/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | 30 | # Build trees 31 | build* 32 | 33 | # Eclipse files 34 | .cproject 35 | .project 36 | 37 | -------------------------------------------------------------------------------- /lib/afsm/lib/ansi-colors/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMakeLists.txt for ansi-colors library 2 | # 3 | # @author zmij 4 | # @date Nov 30, 2015 5 | 6 | cmake_minimum_required(VERSION 2.6) 7 | 8 | # Set library name here 9 | set(lib_name ansi-colors) 10 | set(LIB_NAME ANSI_COLORS) 11 | 12 | if (NOT PROJECT_PREFIX) 13 | set(PROJECT_PREFIX psst) 14 | endif() 15 | set(_pname ${PROJECT_PREFIX}-${lib_name}) 16 | if (PROJECT_VERSION) 17 | set(_pversion ${PROJECT_VERSION}) 18 | else() 19 | set(_pversion 0.1.0) 20 | endif() 21 | 22 | if (${CMAKE_VERSION} VERSION_GREATER "3.0") 23 | cmake_policy(SET CMP0048 NEW) 24 | project(${_pname} VERSION ${_pversion}) 25 | else() 26 | project(${_pname}) 27 | set(PROJECT_VERSION ${_pversion}) 28 | endif() 29 | 30 | option(BUILD_EXAMPLE "Build example application" OFF) 31 | 32 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) 33 | add_definitions("-std=c++11") 34 | 35 | set(PSST_${LIB_NAME}_LIB ${PROJECT_PREFIX}-${lib_name}) 36 | 37 | # Add subdirectories here 38 | add_subdirectory(src) 39 | if(BUILD_EXAMPLE) 40 | add_subdirectory(example) 41 | endif() 42 | 43 | get_directory_property(has_parent PARENT_DIRECTORY) 44 | if (has_parent) 45 | set(PSST_${LIB_NAME}_LIB ${PROJECT_PREFIX}-${lib_name} CACHE INTERNAL "Name of ansi-colors library target") 46 | set(PSST_${LIB_NAME}_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include CACHE INTERNAL "Path to ansi-colors library includes" ) 47 | set(PSST_${LIB_NAME}_LINK_DIR ${CMAKE_CURRENT_BINARY_DIR}/src CACHE INTERNAL "Path to ansi-colors library dir") 48 | endif() 49 | -------------------------------------------------------------------------------- /lib/afsm/lib/ansi-colors/README.md: -------------------------------------------------------------------------------- 1 | # ansi-colors 2 | ANSI console colors for C++ iostreams 3 | -------------------------------------------------------------------------------- /lib/afsm/lib/ansi-colors/example/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # /ansi-colors/example/CMakeLists.txt 2 | # 3 | # @author zmij 4 | # @date Jun 2, 2016 5 | 6 | cmake_minimum_required(VERSION 2.6) 7 | 8 | add_executable(psst-ansi-colors-example ansi_colors_example.cpp) 9 | target_link_libraries(psst-ansi-colors-example ${PSST_${LIB_NAME}_LIB}) 10 | -------------------------------------------------------------------------------- /lib/afsm/lib/ansi-colors/example/ansi_colors_example.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * ansi_colors_example.cpp 3 | * 4 | * Created on: Jun 2, 2016 5 | * Author: zmij 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | namespace { 17 | 18 | using psst::ansi_color; 19 | 20 | int const field_width = 20; 21 | 22 | ::std::array<::std::string, 8> const color_names {{ 23 | "Black", 24 | "Red", 25 | "Green", 26 | "Yellow", 27 | "Blue", 28 | "Magenta", 29 | "Cyan", 30 | "White" 31 | }}; 32 | 33 | struct color_data { 34 | ansi_color color; 35 | ansi_color dim_complement; 36 | ansi_color bright_complement; 37 | }; 38 | ::std::array< color_data, 8 > const colors {{ 39 | /* Color Dim complement Bright complement*/ 40 | { ansi_color::black, ansi_color::white, ansi_color::white }, 41 | { ansi_color::red, ansi_color::white, ansi_color::black }, 42 | { ansi_color::green, ansi_color::white, ansi_color::black }, 43 | { ansi_color::yellow, ansi_color::white, ansi_color::black }, 44 | { ansi_color::blue, ansi_color::white, ansi_color::white }, 45 | { ansi_color::magenta, ansi_color::white, ansi_color::black }, 46 | { ansi_color::cyan, ansi_color::white, ansi_color::black }, 47 | { ansi_color::white, ansi_color::black, ansi_color::black }, 48 | }}; 49 | 50 | ::std::string 51 | centered(::std::string const& str, int width) 52 | { 53 | auto lmargin = (width - str.size()) / 2; 54 | auto rmargin = width - str.size() - lmargin; 55 | 56 | ::std::ostringstream os; 57 | os << ::std::setw(lmargin) << " " << str << ::std::setw(rmargin) << " "; 58 | return os.str(); 59 | } 60 | 61 | void 62 | output_color(::std::string const& name, color_data const& data) 63 | { 64 | ::std::cout 65 | << "|" 66 | << (ansi_color::foreground | data.dim_complement) 67 | << (ansi_color::backgound | ansi_color::dim | data.color ) 68 | << centered(name, field_width) << ansi_color::clear 69 | << "|" 70 | << (ansi_color::foreground | data.bright_complement) 71 | << (ansi_color::backgound | ansi_color::bright | data.color) 72 | << centered(name, field_width) << ansi_color::clear 73 | << "|" 74 | << "\n" 75 | ; 76 | } 77 | 78 | } /* namespace */ 79 | 80 | int 81 | main(int argc, char* argv[]) 82 | try { 83 | using psst::ansi_color; 84 | 85 | ::std::cout 86 | << "|" << centered("Dim", field_width) 87 | << "|" << centered("Bright", field_width) 88 | << "|\n"; 89 | 90 | for (int i = 0; i < 8; ++i) { 91 | output_color(color_names[i], colors[i]); 92 | } 93 | 94 | return 0; 95 | } catch (::std::exception const& e) { 96 | ::std::cerr << "Exception: " << e.what() << "\n"; 97 | return 1; 98 | } catch (...) { 99 | ::std::cerr << "Unexpected exception\n"; 100 | return 2; 101 | } 102 | -------------------------------------------------------------------------------- /lib/afsm/lib/ansi-colors/include/pushkin/ansi_colors.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * ansi_colors.hpp 3 | * 4 | * Created on: Jun 2, 2016 5 | * Author: zmij 6 | */ 7 | 8 | #ifndef PUSHKIN_ANSI_COLORS_HPP_ 9 | #define PUSHKIN_ANSI_COLORS_HPP_ 10 | 11 | #include 12 | 13 | namespace psst { 14 | 15 | enum class ansi_color { 16 | // Clear the color 17 | clear = 0x0000, 18 | // Color attributes 19 | bright = 0x0001, 20 | dim = 0x0002, 21 | underline = 0x0004, 22 | 23 | foreground = 0x0008, 24 | backgound = 0x0010, 25 | // Normal colors 26 | black = 0x0020, 27 | red = 0x0040, 28 | green = 0x0080, 29 | yellow = 0x0100, 30 | blue = 0x0200, 31 | magenta = 0x0400, 32 | cyan = 0x0800, 33 | white = 0x1000, 34 | // Color mask 35 | colors = black | red | green | yellow | blue | magenta | cyan | white, 36 | // Attributes mask 37 | attributes = ~colors 38 | }; 39 | 40 | ::std::ostream& 41 | operator << (::std::ostream& os, ansi_color val); 42 | 43 | inline ansi_color 44 | operator | (ansi_color a, ansi_color b) 45 | { 46 | return static_cast( static_cast(a) | static_cast(b) ); 47 | } 48 | 49 | } /* namespace psst */ 50 | 51 | #endif /* PUSHKIN_ANSI_COLORS_HPP_ */ 52 | -------------------------------------------------------------------------------- /lib/afsm/lib/ansi-colors/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # /ansi-colors/src/CMakeLists.txt 2 | # 3 | # @author zmij 4 | # @date Jun 2, 2016 5 | 6 | cmake_minimum_required(VERSION 2.6) 7 | 8 | add_library(${PSST_${LIB_NAME}_LIB} SHARED ansi_colors.cpp) 9 | -------------------------------------------------------------------------------- /lib/afsm/lib/ansi-colors/src/ansi_colors.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * ansi_colors.cpp 3 | * 4 | * Created on: Jun 2, 2016 5 | * Author: zmij 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | namespace psst { 12 | 13 | namespace { 14 | 15 | int const multiply_de_bruijn_bit_position[32] = 16 | { 17 | 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 18 | 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 19 | }; 20 | 21 | int 22 | lowest_bit_set(unsigned int v) 23 | { 24 | return multiply_de_bruijn_bit_position[((unsigned int)((v & -v) * 0x077CB531U)) >> 27]; 25 | } 26 | 27 | char ESC = '\033'; 28 | 29 | } /* namespace */ 30 | 31 | int 32 | operator & (ansi_color a, ansi_color b) 33 | { 34 | return static_cast(a) & static_cast(b); 35 | } 36 | 37 | ::std::ostream& 38 | operator << (::std::ostream& os, ansi_color val) 39 | { 40 | ::std::ostream::sentry s(os); 41 | if (s) { 42 | if (val == ansi_color::clear) { 43 | os << ESC << "[0m"; 44 | } else { 45 | if (val & ansi_color::bright) { 46 | os << ESC << "[1m"; 47 | } else if (val & ansi_color::dim) { 48 | os << ESC << "[2m"; 49 | } 50 | if (val & ansi_color::underline) { 51 | os << ESC << "[4m"; 52 | } 53 | char fg = '3'; 54 | if (val & ansi_color::backgound) { 55 | fg = '4'; 56 | } 57 | // clear attribute bits 58 | val = static_cast(val & ansi_color::colors); 59 | if (val != ansi_color::clear) { 60 | int color_pos = lowest_bit_set(static_cast(val)) - 61 | lowest_bit_set(static_cast(ansi_color::black)); 62 | os << ESC << '[' << fg << (char)('0' + color_pos) << 'm'; 63 | } 64 | } 65 | } 66 | return os; 67 | } 68 | 69 | 70 | } /* namespace psst */ 71 | -------------------------------------------------------------------------------- /lib/afsm/lib/meta/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | -------------------------------------------------------------------------------- /lib/afsm/lib/meta/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMakeLists.txt for afsm library 2 | # 3 | # @author zmij 4 | # @date Nov 30, 2015 5 | 6 | cmake_minimum_required(VERSION 2.6) 7 | 8 | # Set library name here 9 | set(lib_name metapushkin) 10 | string(TOUPPER ${lib_name} LIB_NAME) 11 | 12 | set(_pname ${lib_name}) 13 | if (PROJECT_VERSION) 14 | set(_pversion ${PROJECT_VERSION}) 15 | else() 16 | set(_pversion 0.1.0) 17 | endif() 18 | 19 | if (${CMAKE_VERSION} VERSION_GREATER "3.0") 20 | cmake_policy(SET CMP0048 NEW) 21 | project(${_pname} VERSION ${_pversion}) 22 | else() 23 | project(${_pname}) 24 | set(PROJECT_VERSION ${_pversion}) 25 | endif() 26 | 27 | option(BUILD_TESTS "Build test programs" ON) 28 | 29 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) 30 | add_definitions("-std=c++11") 31 | add_definitions(-Wall -Werror -Wextra -pedantic -Weffc++) 32 | 33 | # Add subdirectories here 34 | 35 | add_subdirectory(include) 36 | add_subdirectory(cmake) 37 | 38 | if (BUILD_TESTS) 39 | enable_testing() 40 | add_subdirectory(test) 41 | endif() 42 | 43 | get_directory_property(has_parent PARENT_DIRECTORY) 44 | if (has_parent) 45 | set(${LIB_NAME}_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include CACHE 46 | INTERNAL "Path to metapushkin libaray includes" ) 47 | endif() 48 | -------------------------------------------------------------------------------- /lib/afsm/lib/meta/README.md: -------------------------------------------------------------------------------- 1 | # metapushkin 2 | Psst! Wanna some variadic template metaprogramming? 3 | -------------------------------------------------------------------------------- /lib/afsm/lib/meta/cmake/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # meta/cmake/CMakeLists.txt 2 | # 3 | # Try to find a directory where to put FindMetaPushkin script 4 | # 5 | # @author zmij 6 | # @date Nov 18, 2016 7 | 8 | cmake_minimum_required(VERSION 2.6) 9 | 10 | if(NOT CMAKE_SCRIPT_INSTALL_DIR) 11 | find_path(CMAKE_SCRIPT_INSTALL_DIR "CheckLanguage.cmake" 12 | PATHS ${CMAKE_ROOT} 13 | PATH_SUFFIXES Modules ) 14 | endif() 15 | 16 | if (CMAKE_SCRIPT_INSTALL_DIR) 17 | file(GLOB find_scripts Find*.cmake) 18 | install( 19 | FILES ${find_scripts} 20 | DESTINATION ${CMAKE_SCRIPT_INSTALL_DIR}) 21 | else() 22 | message(WARNING "Failed to find target directory for installing cmake Find scripts") 23 | endif() 24 | -------------------------------------------------------------------------------- /lib/afsm/lib/meta/cmake/FindMetaPushkin.cmake: -------------------------------------------------------------------------------- 1 | # FindMetaPushkin.cmake 2 | # Try to find metapuskin library 3 | # 4 | # The following variables are optionally searched for defaults 5 | # METAPUSHKIN_ROOT_DIR: Base directory where include directory can be found 6 | # 7 | # Once done this will define 8 | # METAPUSHKIN_FOUND - System has metapushkin 9 | # METAPUSHKIN_INCLUDE_DIRS - The metapushkin include directories 10 | 11 | if(NOT METAPUSHKIN_FOUND) 12 | 13 | set(METAPUSHKIN_ROOT_DIR "" CACHE PATH "Folder containing metapushkin") 14 | 15 | find_path(METAPUSHKIN_INCLUDE_DIR "pushkin/meta.hpp" 16 | PATHS ${METAPUSHKIN_ROOT_DIR} 17 | PATH_SUFFIXES include 18 | NO_DEFAULT_PATH) 19 | 20 | find_path(METAPUSHKIN_INCLUDE_DIR "pushkin/meta.hpp") 21 | 22 | include(FindPackageHandleStandardArgs) 23 | # handle the QUIETLY and REQUIRED arguments and set benchmark_FOUND to TRUE 24 | # if all listed variables are TRUE 25 | find_package_handle_standard_args(METAPUSHKIN FOUND_VAR METAPUSHKIN_FOUND 26 | REQUIRED_VARS METAPUSHKIN_INCLUDE_DIR) 27 | 28 | if(METAPUSHKIN_FOUND) 29 | set(METAPUSHKIN_INCLUDE_DIRS ${METAPUSHKIN_INCLUDE_DIR}) 30 | endif() 31 | 32 | mark_as_advanced(METAPUSHKIN_INCLUDE_DIR) 33 | 34 | endif() 35 | -------------------------------------------------------------------------------- /lib/afsm/lib/meta/include/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # /afsm/lib/meta/include/pushkin/CMakeLists.txt 2 | # 3 | # @author zmij 4 | # @date Nov 18, 2016 5 | 6 | cmake_minimum_required(VERSION 2.6) 7 | 8 | install( 9 | DIRECTORY pushkin 10 | DESTINATION include 11 | FILES_MATCHING PATTERN *.hpp PATTERN *.inl 12 | ) 13 | -------------------------------------------------------------------------------- /lib/afsm/lib/meta/include/pushkin/meta.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * meta.hpp 3 | * 4 | * Created on: 26 мая 2016 г. 5 | * Author: sergey.fedorov 6 | */ 7 | 8 | #ifndef PUSHKIN_META_HPP_ 9 | #define PUSHKIN_META_HPP_ 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #endif /* PUSHKIN_META_HPP_ */ 20 | -------------------------------------------------------------------------------- /lib/afsm/lib/meta/include/pushkin/meta/callable.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * callable.hpp 3 | * 4 | * Created on: 29 мая 2016 г. 5 | * Author: sergey.fedorov 6 | */ 7 | 8 | #ifndef PUSHKIN_META_CALLABLE_HPP_ 9 | #define PUSHKIN_META_CALLABLE_HPP_ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | namespace psst { 16 | namespace meta { 17 | 18 | template 19 | struct is_callable { 20 | private: 21 | using args_tuple = ::std::tuple; 22 | using indexes = typename index_builder< sizeof ... (Args) >::type; 23 | static args_tuple& args; 24 | 25 | template 26 | static ::std::true_type 27 | test(indexes_tuple const&, 28 | decltype( ::std::declval()( ::std::forward(::std::get(args))... ) ) const*); 29 | template 30 | static ::std::false_type 31 | test(...); 32 | public: 33 | static constexpr bool value = decltype( test(indexes{}, nullptr) )::value; 34 | }; 35 | 36 | template < typename Predicate > 37 | struct not_ { 38 | template < typename ... Args > 39 | bool 40 | operator()(Args&& ... args) const 41 | { 42 | return !Predicate{}(::std::forward(args)...); 43 | } 44 | }; 45 | 46 | template < typename ... Predicates > 47 | struct and_; 48 | template < typename ... Predicates > 49 | struct or_; 50 | 51 | template < typename Predicate, typename ... Rest > 52 | struct and_ { 53 | template < typename ... Args > 54 | bool 55 | operator()(Args&& ... args) const 56 | { 57 | return Predicate{}(::std::forward(args)...) 58 | && and_{}(::std::forward(args)...); 59 | } 60 | }; 61 | 62 | template < typename Predicate > 63 | struct and_ { 64 | template < typename ... Args > 65 | bool 66 | operator()(Args&& ... args) const 67 | { 68 | return Predicate{}(::std::forward(args)...); 69 | } 70 | }; 71 | 72 | template <> 73 | struct and_<> { 74 | template < typename ... Args > 75 | bool 76 | operator()(Args&& ...) const 77 | { 78 | return false; 79 | } 80 | }; 81 | 82 | template < typename Predicate, typename ... Rest > 83 | struct or_ { 84 | template < typename ... Args > 85 | bool 86 | operator()(Args&& ... args) const 87 | { 88 | return Predicate{}(::std::forward(args)...) 89 | || and_{}(::std::forward(args)...); 90 | } 91 | }; 92 | 93 | template < typename Predicate > 94 | struct or_ { 95 | template < typename ... Args > 96 | bool 97 | operator()(Args&& ... args) const 98 | { 99 | return Predicate{}(::std::forward(args)...); 100 | } 101 | }; 102 | 103 | template <> 104 | struct or_<> { 105 | template < typename ... Args > 106 | bool 107 | operator()(Args&& ...) const 108 | { 109 | return true; 110 | } 111 | }; 112 | 113 | } /* namespace meta */ 114 | } /* namespace pus */ 115 | 116 | 117 | 118 | #endif /* PUSHKIN_META_CALLABLE_HPP_ */ 119 | -------------------------------------------------------------------------------- /lib/afsm/lib/meta/include/pushkin/meta/functions.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * functions.hpp 3 | * 4 | * Created on: Aug 30, 2016 5 | * Author: zmij 6 | */ 7 | 8 | #ifndef PUSHKIN_META_FUNCTIONS_HPP_ 9 | #define PUSHKIN_META_FUNCTIONS_HPP_ 10 | 11 | namespace psst { 12 | namespace meta { 13 | 14 | inline bool 15 | any_of(::std::initializer_list args) 16 | { 17 | for (auto v : args) { 18 | if (v) 19 | return true; 20 | } 21 | return false; 22 | } 23 | 24 | inline bool 25 | all_of(::std::initializer_list args) 26 | { 27 | for (auto v : args) { 28 | if (!v) 29 | return false; 30 | } 31 | return true; 32 | } 33 | 34 | } /* namespace meta */ 35 | } /* namespace psst */ 36 | 37 | 38 | 39 | #endif /* PUSHKIN_META_FUNCTIONS_HPP_ */ 40 | -------------------------------------------------------------------------------- /lib/afsm/lib/meta/include/pushkin/meta/index_tuple.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * index_tuple.hpp 3 | * 4 | * Created on: 29 мая 2016 г. 5 | * Author: sergey.fedorov 6 | */ 7 | 8 | #ifndef PUSHKIN_META_INDEX_TUPLE_HPP_ 9 | #define PUSHKIN_META_INDEX_TUPLE_HPP_ 10 | 11 | #include 12 | 13 | namespace psst { 14 | namespace meta { 15 | 16 | template < ::std::size_t ... Indexes > 17 | struct indexes_tuple { 18 | static constexpr ::std::size_t size = sizeof ... (Indexes); 19 | }; 20 | 21 | template < ::std::size_t num, typename tp = indexes_tuple <> > 22 | struct index_builder; 23 | 24 | template < ::std::size_t num, ::std::size_t ... Indexes > 25 | struct index_builder< num, indexes_tuple< Indexes ... > > 26 | : index_builder< num - 1, indexes_tuple< Indexes ..., sizeof ... (Indexes) > > { 27 | }; 28 | 29 | template <::std::size_t ... Indexes > 30 | struct index_builder< 0, indexes_tuple< Indexes ... > > { 31 | typedef indexes_tuple < Indexes ... > type; 32 | static constexpr ::std::size_t size = sizeof ... (Indexes); 33 | }; 34 | 35 | } /* namespace meta */ 36 | } /* namespace pus */ 37 | 38 | #endif /* PUSHKIN_META_INDEX_TUPLE_HPP_ */ 39 | -------------------------------------------------------------------------------- /lib/afsm/lib/meta/include/pushkin/meta/nth_type.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * nth_type.hpp 3 | * 4 | * Created on: 28 мая 2016 г. 5 | * Author: sergey.fedorov 6 | */ 7 | 8 | #ifndef PUSHKIN_META_NTH_TYPE_HPP_ 9 | #define PUSHKIN_META_NTH_TYPE_HPP_ 10 | 11 | #include 12 | 13 | namespace psst { 14 | namespace meta { 15 | 16 | template < ::std::size_t N, typename ... T > 17 | struct nth_type; 18 | 19 | template < ::std::size_t N, typename T, typename ... Y > 20 | struct nth_type< N, T, Y ... > : nth_type < N - 1, Y ... > { 21 | static_assert(N <= sizeof ...(Y), "Index type is out of range"); 22 | }; 23 | 24 | template < typename T, typename ... Y > 25 | struct nth_type < 0, T, Y ... > { 26 | using type = T; 27 | }; 28 | 29 | } /* namespace meta */ 30 | } /* namespace pus */ 31 | 32 | 33 | #endif /* PUSHKIN_META_NTH_TYPE_HPP_ */ 34 | -------------------------------------------------------------------------------- /lib/afsm/lib/meta/include/pushkin/meta/type_map.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * type_map.hpp 3 | * 4 | * Created on: May 31, 2016 5 | * Author: zmij 6 | */ 7 | 8 | #ifndef PUSHKIN_META_TYPE_MAP_HPP_ 9 | #define PUSHKIN_META_TYPE_MAP_HPP_ 10 | 11 | #include 12 | 13 | namespace psst { 14 | namespace meta { 15 | 16 | template < typename ... T > 17 | struct type_map_base; 18 | 19 | template < typename ... K, typename ... V > 20 | struct type_map_base< type_tuple, type_tuple > { 21 | using key_types = type_tuple; 22 | using value_types = type_tuple; 23 | }; 24 | 25 | template <> 26 | struct type_map_base< type_tuple<>, type_tuple<> > { 27 | using key_types = type_tuple<>; 28 | using value_type = type_tuple<>; 29 | }; 30 | 31 | template < typename ... T > 32 | struct key_exists; 33 | template < typename T, typename Y > 34 | struct key_exists { 35 | static_assert(!::std::is_same::value, "Key type already exists"); 36 | }; 37 | 38 | 39 | template 40 | struct insert_type_pair; 41 | template < typename K, typename V, typename ... T, typename ... U > 42 | struct insert_type_pair< type_map_base< type_tuple, type_tuple>, K, V > 43 | : ::std::conditional< contains< K, T ... >::value, 44 | key_exists< K, K >, 45 | type_map_base< type_tuple, type_tuple > 46 | >::type {}; 47 | 48 | template 49 | struct type_pair { 50 | using key_type = K; 51 | using value_type = V; 52 | }; 53 | 54 | template 55 | struct type_map; 56 | 57 | template < typename K, typename V, typename ... T, typename ... Y > 58 | struct type_map< type_tuple< K, T... >, type_tuple > { 59 | using unique_keys = 60 | insert_type_pair< 61 | type_map_base< type_tuple, type_tuple >, K, V >; 62 | using key_types = typename unique_keys::key_types; 63 | using value_types = typename unique_keys::value_types; 64 | 65 | static_assert(key_types::size == value_types::size, 66 | "Incorrect size of type_map"); 67 | 68 | static constexpr ::std::size_t size = key_types::size; 69 | 70 | template < ::std::size_t N > 71 | using type = type_pair< 72 | typename key_types::template type, 73 | typename value_types::template type>; 74 | }; 75 | 76 | template <> 77 | struct type_map<> { 78 | using key_types = type_tuple<>; 79 | using value_type = type_tuple<>; 80 | 81 | static constexpr ::std::size_t size = 0; 82 | }; 83 | 84 | template <> 85 | struct type_map< type_tuple<>, type_tuple<> > : type_map<> {}; 86 | 87 | } /* namespace meta */ 88 | } /* namespace psst */ 89 | 90 | #endif /* PUSHKIN_META_TYPE_MAP_HPP_ */ 91 | -------------------------------------------------------------------------------- /lib/afsm/lib/meta/include/pushkin/meta/type_tuple.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * type_tuple.hpp 3 | * 4 | * Created on: 28 мая 2016 г. 5 | * Author: sergey.fedorov 6 | */ 7 | 8 | #ifndef PUSHKIN_META_TYPE_TUPLE_HPP_ 9 | #define PUSHKIN_META_TYPE_TUPLE_HPP_ 10 | 11 | #include 12 | #include 13 | 14 | namespace psst { 15 | namespace meta { 16 | 17 | template < typename ... T > 18 | struct type_tuple { 19 | static constexpr ::std::size_t size = sizeof ... (T); 20 | template < ::std::size_t N > 21 | using type = typename nth_type::type; 22 | }; 23 | 24 | template <> 25 | struct type_tuple<> { 26 | static constexpr ::std::size_t size = 0; 27 | }; 28 | 29 | template < typename T > 30 | struct to_std_tuple { 31 | using type = ::std::tuple< T >; 32 | }; 33 | 34 | template < typename ... T > 35 | struct to_std_tuple< type_tuple > { 36 | using type = ::std::tuple< T... >; 37 | }; 38 | 39 | } /* namespace meta */ 40 | } /* namespace pus */ 41 | 42 | 43 | 44 | #endif /* PUSHKIN_META_TYPE_TUPLE_HPP_ */ 45 | -------------------------------------------------------------------------------- /lib/afsm/lib/meta/include/pushkin/util/demangle.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * demangle.hpp 3 | * 4 | * Created on: Jun 23, 2016 5 | * Author: zmij 6 | */ 7 | 8 | #ifndef PUSHKIN_UTIL_DEMANGLE_HPP_ 9 | #define PUSHKIN_UTIL_DEMANGLE_HPP_ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | namespace psst { 16 | namespace util { 17 | 18 | /** 19 | * Type name demangle function 20 | * Usage: 21 | * @code 22 | * ::std::cout << demangle< ::std::iostream >() << "\n" 23 | * @endcode 24 | * @return Demangled type name 25 | */ 26 | template < typename T > 27 | ::std::string 28 | demangle() 29 | { 30 | int status {0}; 31 | char* ret = abi::__cxa_demangle( typeid(T).name(), nullptr, nullptr, &status ); 32 | ::std::string res{ret}; 33 | if(ret) free(ret); 34 | return res; 35 | } 36 | 37 | /** 38 | * Type name demangle function, io manip interface. Doesn't create a string. 39 | * Usage: 40 | * @code 41 | * ::std::cout << demangle< ::std::iostream > << "\n" 42 | * @endcode 43 | * @param os 44 | */ 45 | template < typename T > 46 | void 47 | demangle(::std::iostream& os) 48 | { 49 | ::std::ostream::sentry s(os); 50 | if (s) { 51 | int status {0}; 52 | char* ret = abi::__cxa_demangle( typeid(T).name(), nullptr, nullptr, &status ); 53 | if (ret) { 54 | os << ret; 55 | free(ret); 56 | } 57 | } 58 | } 59 | 60 | } /* namespace util */ 61 | } /* namespace psst */ 62 | 63 | 64 | #endif /* PUSHKIN_UTIL_DEMANGLE_HPP_ */ 65 | -------------------------------------------------------------------------------- /lib/afsm/lib/meta/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # /afsm/test/CMakeLists.txt 2 | # 3 | # @author zmij 4 | # @date May 26, 2016 5 | 6 | cmake_minimum_required(VERSION 2.6) 7 | 8 | if (NOT TARGET test-metapushkin) 9 | if (NOT GTEST_INCLUDE_DIRS) 10 | find_package(GTest REQUIRED) 11 | endif() 12 | if (NOT CMAKE_THREAD_LIBS_INIT) 13 | find_package(Threads REQUIRED) 14 | endif() 15 | 16 | # Add your package dependencies for test here 17 | 18 | include_directories(${GTEST_INCLUDE_DIRS}) 19 | 20 | set( 21 | test_program_SRCS 22 | # Add your sources here 23 | static_tests.cpp 24 | ) 25 | add_executable(test-metapushkin ${test_program_SRCS}) 26 | target_link_libraries( 27 | test-metapushkin 28 | ${GTEST_BOTH_LIBRARIES} 29 | ${CMAKE_THREAD_LIBS_INIT} 30 | # Add your libraries here 31 | ) 32 | 33 | if (GTEST_XML_OUTPUT) 34 | set ( 35 | TEST_ARGS 36 | --gtest_output=xml:test-utils-detail.xml 37 | ) 38 | endif() 39 | 40 | add_test( 41 | NAME test-metapushkin 42 | COMMAND test-metapushkin ${TEST_ARGS} 43 | ) 44 | endif() 45 | -------------------------------------------------------------------------------- /lib/afsm/lib/meta/test/cmake/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMakeLists.txt for testing FindMetaPushkin.cmake script 2 | # 3 | # @author zmij 4 | # @date Nov 30, 2015 5 | 6 | cmake_minimum_required(VERSION 2.6) 7 | 8 | set(_pname test-find-metapushkin) 9 | if (PROJECT_VERSION) 10 | set(_pversion ${PROJECT_VERSION}) 11 | else() 12 | set(_pversion 0.1.0) 13 | endif() 14 | 15 | if (${CMAKE_VERSION} VERSION_GREATER "3.0") 16 | cmake_policy(SET CMP0048 NEW) 17 | project(${_pname} VERSION ${_pversion}) 18 | else() 19 | project(${_pname}) 20 | set(PROJECT_VERSION ${_pversion}) 21 | endif() 22 | 23 | add_definitions("-std=c++11") 24 | 25 | set( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake" ) 26 | 27 | find_package(MetaPushkin REQUIRED) 28 | -------------------------------------------------------------------------------- /lib/afsm/lib/meta/test/static_tests.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * static_tests.cpp 3 | * 4 | * Created on: May 31, 2016 5 | * Author: zmij 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | namespace psst { 12 | namespace meta { 13 | namespace test { 14 | 15 | static_assert(!contains::value, ""); 16 | 17 | static_assert( ::std::is_same< 18 | combine< int, type_tuple< long, double > >::type, 19 | type_tuple< int, long, double > 20 | >::value, ""); 21 | 22 | static_assert( ::std::is_same< 23 | combine< int, type_tuple< long, double >, float >::type, 24 | type_tuple< int, long, double, float > 25 | >::value, ""); 26 | 27 | static_assert( ::std::is_same< 28 | combine< int, type_tuple< long, double >, float, type_tuple< bool > >::type, 29 | type_tuple< int, long, double, float, bool > 30 | >::value, ""); 31 | 32 | static_assert( all_match< ::std::is_fundamental, int, float, double, long >::value, "" ); 33 | static_assert( !all_match< ::std::is_integral, int, float, double, long >::value, "" ); 34 | 35 | static_assert( find_if< ::std::is_integral, int, float, double, long >::type::size == 2, ""); 36 | static_assert( find_if< ::std::is_integral, int, float, double, long, long double >::type::size == 2, ""); 37 | static_assert( 38 | ::std::is_same< 39 | find_if< ::std::is_integral, int, float, double, long >::type, 40 | type_tuple 41 | >::value, ""); 42 | 43 | static_assert( ::std::is_same::type, 44 | type_tuple>::value, "" ); 45 | static_assert( ::std::is_same::type, 46 | type_tuple>::value, "" ); 47 | 48 | static_assert( ::std::is_same, int>::type, 49 | type_tuple>::value, "" ); 50 | static_assert( ::std::is_same, int>::type, 51 | type_tuple>::value, "" ); 52 | using type_set_1 = unique< int, float, int, double, long, float, double, bool >::type; 53 | static_assert( contains< int, type_set_1 >::value, "" ); 54 | static_assert( contains< float, type_set_1 >::value, "" ); 55 | static_assert( contains< double, type_set_1 >::value, "" ); 56 | static_assert( contains< long, type_set_1 >::value, "" ); 57 | static_assert( contains< bool, type_set_1 >::value, "" ); 58 | 59 | 60 | struct test_callable { 61 | template < typename A, typename B > 62 | void 63 | operator() (A&, B&&); 64 | 65 | void 66 | operator() (int, int) const; 67 | }; 68 | 69 | static_assert(is_callable::value, ""); 70 | static_assert(is_callable::value, ""); 71 | static_assert(!is_callable::value, ""); 72 | 73 | 74 | TEST(Dummy, AllIsDoneStatically) 75 | { 76 | } 77 | 78 | } /* namespace test */ 79 | } /* namespace meta */ 80 | } /* namespace pus */ 81 | -------------------------------------------------------------------------------- /lib/afsm/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # /afsm/test/CMakeLists.txt 2 | # 3 | # @author zmij 4 | # @date May 26, 2016 5 | 6 | cmake_minimum_required(VERSION 2.6) 7 | if (NOT TARGET test-afsm-base) 8 | if (NOT GTEST_INCLUDE_DIRS) 9 | find_package(GTest REQUIRED) 10 | endif() 11 | if (NOT CMAKE_THREAD_LIBS_INIT) 12 | find_package(Threads REQUIRED) 13 | endif() 14 | 15 | # Add your package dependencies for test here 16 | 17 | include_directories(${GTEST_INCLUDE_DIRS} 18 | ${CMAKE_CURRENT_SOURCE_DIR}/../examples 19 | ${CMAKE_CURRENT_SOURCE_DIR}/../lib/ansi-colors/include) 20 | 21 | set( 22 | test_program_SRCS 23 | # Add your sources here 24 | ${CMAKE_CURRENT_SOURCE_DIR}/../lib/ansi-colors/src/ansi_colors.cpp 25 | static_tests.cpp 26 | state_machine_with_internal_transitions.cpp 27 | fsm_parts_test.cpp 28 | orthogonal_states_test.cpp 29 | transaction_fsm.cpp 30 | transaction_priority_fsm.cpp 31 | common_base_test.cpp 32 | vending_machine_test.cpp 33 | pushdown_tests.cpp 34 | ) 35 | add_executable(test-afsm-base ${test_program_SRCS}) 36 | target_link_libraries( 37 | test-afsm-base 38 | ${GTEST_BOTH_LIBRARIES} 39 | ${CMAKE_THREAD_LIBS_INIT} 40 | ) 41 | 42 | if (GTEST_XML_OUTPUT) 43 | set ( 44 | TEST_ARGS 45 | --gtest_output=xml:test-utils-detail.xml 46 | ) 47 | endif() 48 | 49 | add_test( 50 | NAME test-afsm-base 51 | COMMAND test-afsm-base ${TEST_ARGS} 52 | ) 53 | endif() 54 | -------------------------------------------------------------------------------- /lib/afsm/test/cmake/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # /afsm/test/cmake/CMakeLists.txt 2 | # 3 | # @author zmij 4 | # @date Nov 18, 2016 5 | 6 | cmake_minimum_required(VERSION 2.6) 7 | 8 | set(_pname test-find-afsm) 9 | if (PROJECT_VERSION) 10 | set(_pversion ${PROJECT_VERSION}) 11 | else() 12 | set(_pversion 0.1.0) 13 | endif() 14 | 15 | if (${CMAKE_VERSION} VERSION_GREATER "3.0") 16 | cmake_policy(SET CMP0048 NEW) 17 | project(${_pname} VERSION ${_pversion}) 18 | else() 19 | project(${_pname}) 20 | set(PROJECT_VERSION ${_pversion}) 21 | endif() 22 | 23 | add_definitions("-std=c++11") 24 | 25 | set( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} 26 | "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake" 27 | "${CMAKE_CURRENT_SOURCE_DIR}/../../lib/meta/cmake" ) 28 | 29 | find_package(AFSM REQUIRED) 30 | -------------------------------------------------------------------------------- /lib/afsm/test/orthogonal_states_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * orthogonal_states_test.cpp 3 | * 4 | * Created on: Nov 28, 2016 5 | * Author: zmij 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | namespace afsm { 12 | namespace test { 13 | 14 | namespace events { 15 | 16 | struct power_on {}; 17 | struct power_off {}; 18 | 19 | struct do_work {}; 20 | struct error {}; 21 | 22 | } /* namespace events */ 23 | 24 | struct ortho_sm_def : def::state_machine { 25 | struct off : state {}; 26 | struct on : state_machine { 27 | struct work : state_machine { 28 | struct state_a : state {}; 29 | struct state_b : state {}; 30 | using initial_state = state_a; 31 | 32 | using transitions = transition_table< 33 | tr< state_a, events::do_work, state_b >, 34 | tr< state_b, events::do_work, state_a > 35 | >; 36 | }; 37 | struct error : state_machine { 38 | struct no : state {}; 39 | struct yes : state { 40 | using internal_transitions = transition_table< 41 | in 42 | >; 43 | }; 44 | using initial_state = no; 45 | using transitions = transition_table< 46 | tr< no, events::error, yes > 47 | >; 48 | }; 49 | using orthogonal_regions = type_tuple; 50 | }; 51 | 52 | using initial_state = off; 53 | using transitions = transition_table< 54 | tr< off, events::power_on, on >, 55 | tr< on, events::power_off, off > 56 | >; 57 | }; 58 | 59 | static_assert(def::traits::has_orthogonal_regions::value, ""); 60 | static_assert(def::traits::is_state_machine::value, ""); 61 | 62 | using work_fsm = state_machine; 63 | static_assert(!::std::is_same::value, ""); 64 | static_assert(!::std::is_same::value, ""); 65 | static_assert(::psst::meta::contains::value, ""); 66 | static_assert(::psst::meta::contains::value, ""); 67 | 68 | using work_inner_fsm = inner_state_machine>; 69 | static_assert(!::std::is_same::value, ""); 70 | static_assert(!::std::is_same::value, ""); 71 | static_assert(::psst::meta::contains::value, ""); 72 | static_assert(::psst::meta::contains::value, ""); 73 | 74 | using ortho_fsm = state_machine; 75 | static_assert(def::contains_substate::value, ""); 76 | static_assert(def::contains_substate::value, ""); 77 | static_assert(def::contains_substate::value, ""); 78 | 79 | TEST(OrthogonalRegions, Simple) 80 | { 81 | ortho_fsm fsm; 82 | EXPECT_TRUE(done(fsm.process_event(events::power_on{}))); 83 | EXPECT_TRUE(fsm.is_in_state()); 84 | EXPECT_TRUE(fsm.is_in_state()); 85 | EXPECT_TRUE(fsm.is_in_state()); 86 | EXPECT_TRUE(fsm.is_in_state()); 87 | EXPECT_TRUE(fsm.is_in_state()); 88 | 89 | EXPECT_TRUE(done(fsm.process_event(events::do_work{}))); 90 | EXPECT_TRUE(done(fsm.process_event(events::error{}))); 91 | EXPECT_TRUE(fsm.is_in_state()); 92 | EXPECT_TRUE(fsm.is_in_state()); 93 | EXPECT_TRUE(fsm.is_in_state()); 94 | EXPECT_TRUE(fsm.is_in_state()); 95 | EXPECT_TRUE(fsm.is_in_state()); 96 | 97 | EXPECT_TRUE(done(fsm.process_event(events::do_work{}))); 98 | EXPECT_TRUE(done(fsm.process_event(events::error{}))); 99 | EXPECT_TRUE(fsm.is_in_state()); 100 | EXPECT_TRUE(fsm.is_in_state()); 101 | EXPECT_TRUE(fsm.is_in_state()); 102 | EXPECT_TRUE(fsm.is_in_state()); 103 | EXPECT_TRUE(fsm.is_in_state()); 104 | } 105 | 106 | } /* namespace test */ 107 | } /* namespace afsm */ 108 | -------------------------------------------------------------------------------- /lib/asio-fiber/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | *.smod 19 | 20 | # Compiled Static libraries 21 | *.lai 22 | *.la 23 | *.a 24 | *.lib 25 | 26 | # Executables 27 | *.exe 28 | *.out 29 | *.app 30 | -------------------------------------------------------------------------------- /lib/asio-fiber/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMakeLists.txt for pushkin-asio-fibers library 2 | # 3 | # @author zmij 4 | # @date Nov 30, 2015 5 | 6 | cmake_minimum_required(VERSION 2.6) 7 | 8 | # Set library name here 9 | set(lib_name pushkin-asio-fibers) 10 | string(TOUPPER PUSHKIN_ASIO_FIBERS LIB_NAME) 11 | 12 | set(_pname ${lib_name}) 13 | if (PROJECT_VERSION) 14 | set(_pversion ${PROJECT_VERSION}) 15 | else() 16 | set(_pversion 0.1.0) 17 | endif() 18 | 19 | if (${CMAKE_VERSION} VERSION_GREATER "3.0") 20 | cmake_policy(SET CMP0048 NEW) 21 | project(${_pname} VERSION ${_pversion}) 22 | else() 23 | project(${_pname}) 24 | set(PROJECT_VERSION ${_pversion}) 25 | endif() 26 | 27 | option(BUILD_TESTS "Build tests for ${lib_name} library" ON) 28 | # Without fibers only non-fiber utilities can be used 29 | option(WITH_BOOST_FIBER "Build wire with boost::fiber support" OFF) 30 | 31 | set( 32 | BOOST_COMPONENTS 33 | system 34 | thread 35 | ) 36 | set(BOOST_VERSION 1.58) 37 | if (WITH_BOOST_FIBER) 38 | set(BOOST_VERSION 1.61) # Boost.Fiber was introduced in version 1.61 39 | list(APPEND BOOST_COMPONENTS context fiber) 40 | endif() 41 | 42 | find_package(Boost ${BOOST_VERSION} COMPONENTS ${BOOST_COMPONENTS} REQUIRED) 43 | find_package(Threads REQUIRED) 44 | 45 | include_directories( 46 | SYSTEM 47 | ${Boost_INCLUDE_DIRS} 48 | ) 49 | 50 | include_directories( 51 | ${CMAKE_CURRENT_SOURCE_DIR}/include 52 | ) 53 | add_definitions("-std=c++14") 54 | 55 | #set(TIP_${LIB_NAME}_LIB ${PROJECT_PREFIX}-${lib_name}) 56 | 57 | # Add subdirectories here 58 | 59 | get_directory_property(has_parent PARENT_DIRECTORY) 60 | if (has_parent) 61 | set(${LIB_NAME}_INCLUDE_DIRECTORIES 62 | ${CMAKE_CURRENT_SOURCE_DIR}/include 63 | CACHE INTERNAL "Path to pushkin-asio-fibers library includes" ) 64 | endif() 65 | -------------------------------------------------------------------------------- /lib/asio-fiber/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Sergei Fedorov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/asio-fiber/README.md: -------------------------------------------------------------------------------- 1 | # pushkin-asio-fibers 2 | Utilities for boost::asio and boost::fiber interoperability 3 | -------------------------------------------------------------------------------- /lib/asio-fiber/include/pushkin/asio/asio_config.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * asio_config.hpp 3 | * 4 | * Created on: Mar 26, 2017 5 | * Author: zmij 6 | */ 7 | 8 | #ifndef PUSHKIN_ASIO_ASIO_CONFIG_HPP_ 9 | #define PUSHKIN_ASIO_ASIO_CONFIG_HPP_ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #ifdef BOOST_ASIO_HAS_LOCAL_SOCKETS 16 | #include 17 | #endif 18 | 19 | #include 20 | 21 | namespace asio_ns = ::boost::asio; 22 | 23 | namespace psst { 24 | namespace asio { 25 | 26 | using io_service = ::asio_ns::io_service; 27 | using io_service_ptr = ::std::shared_ptr< io_service >; 28 | 29 | using error_code = ::boost::system::error_code; 30 | using system_error = ::boost::system::system_error; 31 | 32 | using tcp = ::asio_ns::ip::tcp; 33 | using udp = ::asio_ns::ip::udp; 34 | 35 | #ifdef BOOST_ASIO_HAS_LOCAL_SOCKETS 36 | using local_socket = ::asio_ns::local::stream_protocol; 37 | #endif 38 | 39 | } /* namespace asio */ 40 | } /* namespace psst */ 41 | 42 | 43 | #endif /* PUSHKIN_ASIO_ASIO_CONFIG_HPP_ */ 44 | -------------------------------------------------------------------------------- /lib/asio-fiber/include/pushkin/asio/async_ssl_ops.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * async_ssl_ops.hpp 3 | * 4 | * Created on: Mar 27, 2017 5 | * Author: zmij 6 | */ 7 | 8 | #ifndef PUSHKIN_ASIO_ASYNC_SSL_OPS_HPP_ 9 | #define PUSHKIN_ASIO_ASYNC_SSL_OPS_HPP_ 10 | 11 | #include 12 | #include 13 | 14 | namespace psst { 15 | namespace asio { 16 | 17 | namespace detail { 18 | 19 | template < typename StreamType > 20 | struct socket_ops<::asio_ns::ssl::stream> { 21 | using socket_type = ::asio_ns::ssl::stream; 22 | 23 | template < typename Handler > 24 | static auto 25 | async_handshake(socket_type& sock, 26 | ::asio_ns::ssl::stream_base::handshake_type t, 27 | Handler handler) 28 | { 29 | return sock.async_handshake(t, ::std::move(handler)); 30 | } 31 | 32 | template < typename Buffer, typename Handler > 33 | static auto 34 | async_write(socket_type& sock, Buffer const& buff, Handler handler) 35 | -> decltype(asio_ns::async_write(sock, buff, handler)) 36 | { 37 | return asio_ns::async_write(sock, buff, ::std::move(handler)); 38 | } 39 | 40 | template < typename Buffer, typename Handler > 41 | static auto 42 | async_read(socket_type& sock, Buffer&& buff, Handler handler) 43 | { 44 | return asio_ns::async_read(sock, ::std::forward(buff), 45 | ::asio_ns::transfer_at_least(1), ::std::move(handler)); 46 | } 47 | }; 48 | 49 | } /* namespace detail */ 50 | 51 | template < typename StreamType, typename Handler > 52 | void 53 | async_handshake(::asio_ns::ssl::stream& sock, 54 | ::asio_ns::ssl::stream_base::handshake_type t, Handler handler) 55 | { 56 | using socket_ops = detail::socket_ops<::asio_ns::ssl::stream>; 57 | socket_ops::async_handshake(sock, t, ::std::move(handler)); 58 | } 59 | 60 | #ifdef WITH_BOOST_FIBERS 61 | 62 | template < typename StreamType, typename Handler > 63 | void 64 | fiber_handshake(::asio_ns::ssl::stream& sock, 65 | ::asio_ns::ssl::stream_base::handshake_type t, Handler handler) 66 | { 67 | using socket_ops = detail::socket_ops<::asio_ns::ssl::stream>; 68 | error_code ec; 69 | socket_ops::async_handshake(sock, t, fiber::yield_t{ec}); 70 | handler(ec); 71 | } 72 | 73 | template < typename StreamType > 74 | void 75 | fiber_handshake(::asio_ns::ssl::stream& sock, 76 | ::asio_ns::ssl::stream_base::handshake_type t) 77 | { 78 | using promise_type = ::boost::fibers::promise; 79 | auto promise = ::std::make_shared(); 80 | 81 | fiber_handshake(sock, t, 82 | [promise](error_code const& ec) 83 | { 84 | if (!ec) { 85 | promise->set_value(); 86 | } else { 87 | promise->set_exception( ::std::make_exception_ptr( system_error{ ec } ) ); 88 | } 89 | }); 90 | 91 | promise->get_future().get(); 92 | } 93 | 94 | #endif /* WITH_BOOST_FIBERS */ 95 | 96 | template < typename StreamType, typename Handler > 97 | void 98 | handshake(::asio_ns::ssl::stream& sock, 99 | ::asio_ns::ssl::stream_base::handshake_type t, Handler handler) 100 | { 101 | #ifdef WITH_BOOST_FIBERS 102 | fiber_handshake(sock, t, ::std::move(handler)); 103 | #else /* NO WITH_BOOST_FIBERS */ 104 | async_handshake(sock, t, ::std::move(handler)); 105 | #endif /* WITH_BOOST_FIBERS */ 106 | } 107 | 108 | } /* namespace asio */ 109 | } /* namespace psst */ 110 | 111 | 112 | #endif /* PUSHKIN_ASIO_ASYNC_SSL_OPS_HPP_ */ 113 | -------------------------------------------------------------------------------- /lib/asio-fiber/include/pushkin/asio/fiber/yield.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * fiber_yeild.hpp 3 | * 4 | * Created on: Mar 26, 2017 5 | * Author: zmij 6 | */ 7 | 8 | #ifndef WIRE_UTIL_FIBER_YIELD_HPP_ 9 | #define WIRE_UTIL_FIBER_YIELD_HPP_ 10 | 11 | #include 12 | 13 | namespace psst { 14 | namespace asio { 15 | namespace fiber { 16 | 17 | struct yield_t { 18 | constexpr yield_t() noexcept = default; 19 | constexpr explicit yield_t(error_code* ec) noexcept : ec_{ec} {} 20 | constexpr explicit yield_t(error_code& ec) noexcept : ec_{&ec} {} 21 | 22 | constexpr yield_t 23 | operator[](error_code& ec) const 24 | { 25 | return yield_t(ec); 26 | } 27 | 28 | error_code* ec_{ nullptr }; 29 | }; 30 | 31 | } /* namespace fiber */ 32 | } /* namespace asio */ 33 | } /* namespace psst */ 34 | 35 | #include 36 | 37 | 38 | #endif /* WIRE_UTIL_FIBER_YIELD_HPP_ */ 39 | -------------------------------------------------------------------------------- /lib/asio-fiber/include/pushkin/asio/fibers.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * fibers.hpp 3 | * 4 | * Created on: Mar 26, 2017 5 | * Author: zmij 6 | */ 7 | 8 | #ifndef PUSHKIN_ASIO_FIBERS_HPP_ 9 | #define PUSHKIN_ASIO_FIBERS_HPP_ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #endif /* PUSHKIN_ASIO_FIBERS_HPP_ */ 16 | -------------------------------------------------------------------------------- /lib/asio-fiber/include/pushkin/asio/wait.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * wait.hpp 3 | * 4 | * Created on: Mar 26, 2017 5 | * Author: zmij 6 | */ 7 | 8 | #ifndef PUSHKIN_ASIO_FIBER_INCLUDE_PUSHKIN_ASIO_WAIT_HPP_ 9 | #define PUSHKIN_ASIO_FIBER_INCLUDE_PUSHKIN_ASIO_WAIT_HPP_ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #ifdef WITH_BOOST_FIBERS 16 | #include 17 | #endif 18 | 19 | namespace psst { 20 | namespace asio { 21 | 22 | namespace detail { 23 | 24 | enum class wait_type { 25 | same_thread, 26 | other_thread, 27 | fiber 28 | }; 29 | 30 | template < wait_type V > 31 | using wait_constant = ::std::integral_constant; 32 | 33 | template < typename Pred > 34 | void 35 | run_while( io_service_ptr svc, Pred pred, wait_constant< wait_type::same_thread > const& ) 36 | { 37 | while(pred()) 38 | svc->poll(); 39 | } 40 | 41 | template < typename Pred > 42 | void 43 | run_while( io_service_ptr svc, Pred pred, wait_constant< wait_type::other_thread > const& ) 44 | { 45 | ::std::thread t{ 46 | [svc, pred](){ 47 | while(pred()) 48 | svc->poll(); 49 | }}; 50 | t.join(); 51 | } 52 | 53 | #ifdef WITH_BOOST_FIBERS 54 | template < typename Pred > 55 | void 56 | run_while( io_service_ptr svc, Pred pred, wait_constant< wait_type::fiber > const& ) 57 | { 58 | namespace this_fiber = ::boost::this_fiber; 59 | fiber f{ 60 | [svc, pred](){ 61 | while(pred()) { 62 | svc->poll(); 63 | this_fiber::yield(); 64 | } 65 | }}; 66 | f.join(); 67 | } 68 | #endif 69 | 70 | template < typename Pred > 71 | void 72 | run_until( io_service_ptr svc, Pred pred, wait_constant< wait_type::same_thread > const& ) 73 | { 74 | while(!pred()) 75 | svc->poll(); 76 | } 77 | 78 | template < typename Pred > 79 | void 80 | run_until( io_service_ptr svc, Pred pred, wait_constant< wait_type::other_thread > const& ) 81 | { 82 | ::std::thread t{ 83 | [svc, pred](){ 84 | while(!pred()) 85 | svc->poll(); 86 | }}; 87 | t.join(); 88 | } 89 | 90 | #ifdef WITH_BOOST_FIBERS 91 | template < typename Pred > 92 | void 93 | run_until( io_service_ptr svc, Pred pred, wait_constant< wait_type::fiber > const& ) 94 | { 95 | namespace this_fiber = ::boost::this_fiber; 96 | fiber f{ 97 | [svc, pred](){ 98 | while(!pred()) { 99 | svc->poll(); 100 | this_fiber::yield(); 101 | } 102 | }}; 103 | f.join(); 104 | } 105 | #endif 106 | 107 | static wait_type constexpr default_wait_type = 108 | #ifdef WITH_BOOST_FIBERS 109 | wait_type::fiber; 110 | #elif ASIO_WAIT_SAME_THREAD 111 | wait_type::same_thread; 112 | #else 113 | wait_type::other_thread; 114 | #endif 115 | 116 | } /* namespace detail */ 117 | 118 | template < typename Pred > 119 | void 120 | wait_while( io_service_ptr svc, Pred pred ) 121 | { 122 | detail::run_while(svc, ::std::move(pred), 123 | detail::wait_constant< detail::default_wait_type >{}); 124 | } 125 | 126 | template < typename Pred > 127 | void 128 | wait_until( io_service_ptr svc, Pred pred ) 129 | { 130 | detail::run_until(svc, ::std::move(pred), 131 | detail::wait_constant< detail::default_wait_type >{}); 132 | } 133 | 134 | } /* namespace asio */ 135 | } /* namespace psst */ 136 | 137 | 138 | #endif /* PUSHKIN_ASIO_FIBER_INCLUDE_PUSHKIN_ASIO_WAIT_HPP_ */ 139 | -------------------------------------------------------------------------------- /lib/log/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | -------------------------------------------------------------------------------- /lib/log/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMakeLists.txt for tip-log library 2 | # 3 | # @author zmij 4 | # @date Nov 30, 2015 5 | 6 | cmake_minimum_required(VERSION 2.6) 7 | 8 | if (NOT PROJECT_PREFIX) 9 | set(PROJECT_PREFIX tip) 10 | endif() 11 | set(_pname ${PROJECT_PREFIX}-log) 12 | if (PROJECT_VERSION) 13 | set(_pversion ${PROJECT_VERSION}) 14 | else() 15 | set(_pversion 0.1.0) 16 | endif() 17 | 18 | if (${CMAKE_VERSION} VERSION_GREATER "3.0") 19 | cmake_policy(SET CMP0048 NEW) 20 | project(${_pname} VERSION ${_pversion}) 21 | else() 22 | project(${_pname}) 23 | set(PROJECT_VERSION ${_pversion}) 24 | endif() 25 | 26 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) 27 | add_definitions("-std=c++11") 28 | 29 | set(TIP_LOG_LIB ${PROJECT_PREFIX}-log) 30 | 31 | add_subdirectory(include/pushkin) 32 | add_subdirectory(src) 33 | 34 | get_directory_property(has_parent PARENT_DIRECTORY) 35 | if (has_parent) 36 | set(TIP_LOG_LIB ${PROJECT_PREFIX}-log CACHE INTERNAL "Name of tip log library target") 37 | set(TIP_LOG_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include CACHE INTERNAL "Path to tip log library includes" ) 38 | set(TIP_LOG_LINK_DIR ${CMAKE_CURRENT_BINARY_DIR}/src CACHE INTERNAL "Path to tip log binary dir") 39 | endif() 40 | -------------------------------------------------------------------------------- /lib/log/README.md: -------------------------------------------------------------------------------- 1 | # tip-log 2 | Simple logging library 3 | -------------------------------------------------------------------------------- /lib/log/include/pushkin/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMakeLists.txt tip-log/include/tip 2 | # 3 | # @author zmij 4 | # @date Nov 30, 2015 5 | 6 | cmake_minimum_required(VERSION 2.6) 7 | 8 | install( 9 | FILES log.hpp 10 | DESTINATION include/tip 11 | ) 12 | 13 | install( 14 | FILES log/ansi_colors.hpp 15 | DESTINATION include/tip/log 16 | ) 17 | -------------------------------------------------------------------------------- /lib/log/include/pushkin/log/ansi_colors.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * ansi_colors.hpp 3 | * 4 | * Created on: Jul 14, 2015 5 | * Author: zmij 6 | */ 7 | 8 | #ifndef PUSHKIN_UTIL_ANSI_COLORS_HPP_ 9 | #define PUSHKIN_UTIL_ANSI_COLORS_HPP_ 10 | 11 | #include 12 | 13 | namespace psst { 14 | namespace util { 15 | 16 | enum ANSI_COLOR { 17 | // clear the color 18 | CLEAR = 0x00, 19 | // attribs 20 | BRIGHT = 0x01, 21 | DIM = BRIGHT * 2, 22 | UNDERLINE = DIM * 2, 23 | 24 | FOREGROUND = UNDERLINE * 2, 25 | BACKGROUND = FOREGROUND * 2, 26 | // normal colors 27 | BLACK = BACKGROUND * 2, 28 | RED = BLACK * 2, 29 | GREEN = RED * 2, 30 | YELLOW = GREEN * 2, 31 | BLUE = YELLOW * 2, 32 | MAGENTA = BLUE * 2, 33 | CYAN = MAGENTA * 2, 34 | WHITE = CYAN * 2, 35 | 36 | // Color mask 37 | COLORS = BLACK | RED | GREEN | YELLOW | 38 | BLUE | MAGENTA | CYAN | WHITE 39 | }; 40 | 41 | std::ostream& 42 | operator << (std::ostream&, ANSI_COLOR); 43 | 44 | inline ANSI_COLOR 45 | operator | (ANSI_COLOR a, ANSI_COLOR b) 46 | { 47 | return (ANSI_COLOR)((int)a | (int)b); 48 | } 49 | 50 | } // namespace util 51 | } // namespace psst 52 | 53 | #endif /* PUSHKIN_UTIL_ANSI_COLORS_HPP_ */ 54 | -------------------------------------------------------------------------------- /lib/log/include/pushkin/log/stream_redirect.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * stream_redirect.hpp 3 | * 4 | * Created on: Jan 15, 2016 5 | * Author: zmij 6 | */ 7 | 8 | #ifndef PUSHKIN_LOG_STREAM_REDIRECT_HPP_ 9 | #define PUSHKIN_LOG_STREAM_REDIRECT_HPP_ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace psst { 18 | namespace log { 19 | 20 | class stream_redirect { 21 | public: 22 | stream_redirect(::std::ostream& stream, 23 | ::std::string const& file_name, 24 | ::std::ios_base::openmode open_mode 25 | = ::std::ios_base::out | ::std::ios_base::app) : 26 | stream_(stream), old_(stream.rdbuf()), 27 | mode_{open_mode}, file_name_{file_name} 28 | { 29 | file_.open(file_name.c_str(), open_mode); 30 | if (!file_.good()) { 31 | std::ostringstream msg; 32 | msg << "Failed to open file " << file_name 33 | << ": " << strerror(errno) << "\n"; 34 | throw std::runtime_error(msg.str()); 35 | } 36 | stream_.rdbuf(file_.rdbuf()); 37 | } 38 | ~stream_redirect() 39 | { 40 | stream_.flush(); 41 | stream_.rdbuf(old_); 42 | } 43 | 44 | ::std::string const& 45 | file_name() const 46 | { return file_name_; } 47 | 48 | void 49 | reopen() 50 | { 51 | stream_.rdbuf(old_); 52 | file_.close(); 53 | file_.clear(); 54 | file_.open(file_name_, mode_); 55 | stream_.rdbuf(file_.rdbuf()); 56 | } 57 | private: 58 | ::std::ostream& stream_; 59 | ::std::streambuf* old_; 60 | ::std::ofstream file_; 61 | ::std::ios_base::openmode mode_; 62 | ::std::string file_name_; 63 | }; 64 | 65 | } // namespace log 66 | } // namespace psst 67 | 68 | 69 | #endif /* PUSHKIN_LOG_STREAM_REDIRECT_HPP_ */ 70 | -------------------------------------------------------------------------------- /lib/log/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # @file /tip-server/src/tip/log/CMakeLists.txt 2 | # @author: zmij 3 | # Created on: Jul 8, 2015 4 | 5 | cmake_minimum_required(VERSION 2.6) 6 | 7 | set(log_lib_SRCS 8 | log.cpp 9 | ansi_colors.cpp 10 | ) 11 | 12 | add_library(${TIP_LOG_LIB} SHARED ${log_lib_SRCS}) 13 | target_link_libraries(${TIP_LOG_LIB} 14 | ${Boost_SYSTEM_LIBRARIES} 15 | ${Boost_THREAD_LIBRARIES} 16 | ${CMAKE_THREAD_LIBS_INIT} 17 | ) 18 | include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) 19 | set_target_properties( 20 | ${TIP_LOG_LIB} PROPERTIES 21 | VERSION ${PROJECT_VERSION} 22 | SOVERSION 0 23 | ) 24 | 25 | install ( 26 | TARGETS ${TIP_LOG_LIB} 27 | LIBRARY DESTINATION lib 28 | ARCHIVE DESTINATION lib 29 | ) 30 | -------------------------------------------------------------------------------- /lib/log/src/ansi_colors.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * ansi_colors.cpp 3 | * 4 | * Created on: Jul 14, 2015 5 | * Author: zmij 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | namespace psst { 12 | namespace util { 13 | 14 | namespace { 15 | 16 | const int multiply_de_bruijn_bit_position[32] = 17 | { 18 | 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 19 | 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 20 | }; 21 | 22 | int 23 | lowest_bit_set(unsigned int v) 24 | { 25 | return multiply_de_bruijn_bit_position[((unsigned int)((v & -v) * 0x077CB531U)) >> 27]; 26 | } 27 | 28 | char ESC = '\033'; 29 | 30 | } // namespace 31 | 32 | std::ostream& 33 | operator << (std::ostream& out, ANSI_COLOR col) 34 | { 35 | std::ostream::sentry s(out); 36 | if (s) { 37 | if (col == CLEAR) { 38 | out << ESC << "[0m"; 39 | } else { 40 | if (col & BRIGHT) { 41 | out << ESC << "[1m"; 42 | } else if (col & DIM) { 43 | out << ESC << "[2m"; 44 | } 45 | if (col & UNDERLINE) { 46 | out << ESC << "[4m"; 47 | } 48 | 49 | char fg = '3'; 50 | if (col & BACKGROUND) { 51 | fg = '4'; 52 | } 53 | // clear attribute bits 54 | col = (ANSI_COLOR)(col & COLORS); 55 | if (col) { 56 | int color_pos = lowest_bit_set(col) - lowest_bit_set(BLACK); 57 | out << ESC << '[' << fg << (char)('0' + color_pos) << 'm'; 58 | } 59 | } 60 | } 61 | return out; 62 | } 63 | 64 | } // namespace util 65 | } // namespace psst 66 | -------------------------------------------------------------------------------- /lib/util/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | -------------------------------------------------------------------------------- /lib/util/README.md: -------------------------------------------------------------------------------- 1 | # tip-util 2 | Utility headers, shared between tip projects 3 | -------------------------------------------------------------------------------- /lib/util/include/tip/util/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMakeLists.txt 2 | # 3 | # @author zmij 4 | # @date Aug 3, 2015 5 | 6 | cmake_minimum_required(VERSION 2.6) 7 | 8 | set( 9 | pg_async_util_HDRS 10 | endian.hpp 11 | meta_helpers.hpp 12 | streambuf.hpp 13 | ) 14 | 15 | install( 16 | FILES ${pg_async_util_HDRS} 17 | DESTINATION include/tip/util 18 | ) 19 | -------------------------------------------------------------------------------- /lib/util/include/tip/util/meta_helpers.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * meta_helpers.hpp 3 | * 4 | * Created on: Jul 21, 2015 5 | * Author: zmij 6 | */ 7 | 8 | #ifndef LIB_PG_ASYNC_INCLUDE_TIP_UTIL_META_HELPERS_HPP_ 9 | #define LIB_PG_ASYNC_INCLUDE_TIP_UTIL_META_HELPERS_HPP_ 10 | 11 | namespace tip { 12 | namespace util { 13 | 14 | /** 15 | * Metafunction for calculating Nth type in variadic template parameters 16 | */ 17 | template < size_t num, typename ... T > 18 | struct nth_type; 19 | 20 | template < size_t num, typename T, typename ... Y > 21 | struct nth_type< num, T, Y ... > : nth_type< num - 1, Y ...> { 22 | }; 23 | 24 | template < typename T, typename ... Y > 25 | struct nth_type < 0, T, Y ... > { 26 | typedef T type; 27 | }; 28 | 29 | template < size_t ... Indexes > 30 | struct indexes_tuple { 31 | enum { 32 | size = sizeof ... (Indexes) 33 | }; 34 | }; 35 | 36 | template < size_t num, typename tp = indexes_tuple <> > 37 | struct index_builder; 38 | 39 | template < size_t num, size_t ... Indexes > 40 | struct index_builder< num, indexes_tuple< Indexes ... > > 41 | : index_builder< num - 1, indexes_tuple< Indexes ..., sizeof ... (Indexes) > > { 42 | }; 43 | 44 | template 45 | struct index_builder< 0, indexes_tuple< Indexes ... > > { 46 | typedef indexes_tuple < Indexes ... > type; 47 | enum { 48 | size = sizeof ... (Indexes) 49 | }; 50 | }; 51 | 52 | struct expand 53 | { 54 | template < typename ... U > 55 | expand(U const& ...) {} 56 | }; 57 | 58 | } // namespace util 59 | } // namespace tip 60 | 61 | #endif /* LIB_PG_ASYNC_INCLUDE_TIP_UTIL_META_HELPERS_HPP_ */ 62 | -------------------------------------------------------------------------------- /lib/util/include/tip/util/streambuf.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * streambuf.hpp 3 | * 4 | * Created on: 12 июля 2015 г. 5 | * Author: brysin 6 | */ 7 | 8 | #ifndef TIP_UTIL_STREAMBUF_HPP_ 9 | #define TIP_UTIL_STREAMBUF_HPP_ 10 | 11 | #include 12 | #include 13 | 14 | namespace tip { 15 | namespace util { 16 | 17 | template , typename traits = std::char_traits > 18 | class basic_input_iterator_buffer : public std::basic_streambuf { 19 | public: 20 | typedef charT char_type; 21 | typedef container container_type; 22 | typedef typename container_type::const_iterator const_iterator; 23 | typedef std::ios_base ios_base; 24 | 25 | typedef std::basic_streambuf base; 26 | typedef typename base::pos_type pos_type; 27 | typedef typename base::off_type off_type; 28 | public: 29 | basic_input_iterator_buffer(const_iterator s, const_iterator e) 30 | : base(), s_(s), start_(const_cast(&*s)), 31 | count_(e - s) 32 | { 33 | base::setg(start_, start_, start_ + count_); 34 | } 35 | basic_input_iterator_buffer(basic_input_iterator_buffer&& rhs) 36 | : base(), start_(rhs.start_), count_(rhs.count_) 37 | { 38 | auto n = rhs.gptr(); 39 | base::setg(start_, n, start_ + count_); 40 | } 41 | const_iterator 42 | begin() const 43 | { 44 | return s_; 45 | } 46 | const_iterator 47 | end() const 48 | { 49 | return s_ + count_; 50 | } 51 | bool 52 | empty() const 53 | { 54 | return count_ == 0; 55 | } 56 | protected: 57 | pos_type 58 | seekoff (off_type off, ios_base::seekdir way, 59 | ios_base::openmode which = ios_base::in | ios_base::out) 60 | { 61 | char_type* tgt(nullptr); 62 | switch (way) { 63 | case ios_base::beg: 64 | tgt = start_ + off; 65 | break; 66 | case ios_base::cur: 67 | tgt = base::gptr() + off; 68 | break; 69 | case ios_base::end: 70 | tgt = start_ + count_ - 1 + off; 71 | break; 72 | default: 73 | break; 74 | } 75 | if (!tgt) 76 | return -1; 77 | if (tgt < start_ || start_ + count_ < tgt) 78 | return -1; 79 | base::setg(start_, tgt, start_ + count_); 80 | return tgt - start_; 81 | } 82 | pos_type 83 | seekpos(pos_type pos, ios_base::openmode which = ios_base::in | ios_base::out) 84 | { 85 | char_type* tgt = start_ + pos; 86 | if (tgt < start_ || start_ + count_ < tgt) 87 | return -1; 88 | base::setg(start_, tgt, start_ + count_); 89 | return tgt - start_; 90 | } 91 | private: 92 | const_iterator s_; 93 | char_type* start_; 94 | size_t count_; 95 | }; 96 | 97 | typedef basic_input_iterator_buffer input_iterator_buffer; 98 | 99 | } // namespace util 100 | } // namespace tip 101 | 102 | #endif /* TIP_UTIL_STREAMBUF_HPP_ */ 103 | -------------------------------------------------------------------------------- /src/tip/db/pg/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # @file /tip-server/src/tip/db/pg/CMakeLists.txt 2 | # @author: zmij 3 | # Created on: Jul 9, 2015 4 | 5 | cmake_minimum_required(VERSION 2.6) 6 | 7 | # Set all log default level 8 | if(NOT PGASYNC_LOG_ALL) 9 | set(PGASYNC_LOG_ALL OFF) 10 | endif() 11 | 12 | set(LOG_CATEGORIES SERVICE CONNECTION QUERY INTERNALS) 13 | 14 | foreach(category ${LOG_CATEGORIES}) 15 | if (NOT PGASYNC_LOG_${category}) 16 | set(PGASYNC_LOG_${category} ${PGASYNC_LOG_ALL}) 17 | endif() 18 | endforeach() 19 | 20 | configure_file(log_config.in.hpp log_config.hpp) 21 | configure_file(version.in.hpp version.hpp) 22 | 23 | set( 24 | pgsql_lib_SRCS 25 | common.cpp 26 | database.cpp 27 | error.cpp 28 | resultset.cpp 29 | query.cpp 30 | sqlstates.cpp 31 | pg_types.cpp 32 | protocol_io_traits.cpp 33 | transaction.cpp 34 | detail/md5.cpp 35 | detail/protocol.cpp 36 | detail/protocol_parsers.cpp 37 | detail/basic_connection.cpp 38 | detail/transport.cpp 39 | detail/result_impl.cpp 40 | detail/database_impl.cpp 41 | detail/connection_pool.cpp 42 | ) 43 | 44 | add_library(${PGASYNC_LIB_NAME} SHARED ${pgsql_lib_SRCS}) 45 | set_target_properties( 46 | ${PGASYNC_LIB_NAME} PROPERTIES 47 | VERSION ${PROJECT_VERSION} 48 | SOVERSION 1 49 | ) 50 | 51 | set(pgsql_lib_LIBRARIES 52 | ${ASIO_LIBRARIES} 53 | ${CMAKE_THREAD_LIBS_INIT} 54 | ${TIP_LOG_LIB} 55 | ) 56 | 57 | target_link_libraries(${PGASYNC_LIB_NAME} ${pgsql_lib_LIBRARIES}) 58 | 59 | install ( 60 | TARGETS ${PGASYNC_LIB_NAME} 61 | LIBRARY DESTINATION lib 62 | ARCHIVE DESTINATION lib 63 | ) 64 | -------------------------------------------------------------------------------- /src/tip/db/pg/database.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * database.cpp 3 | * 4 | * Created on: 11 июля 2015 г. 5 | * @author: zmij 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | namespace tip { 17 | namespace db { 18 | namespace pg { 19 | 20 | LOCAL_LOGGING_FACILITY_CFG(PGSVC, config::SERVICE_LOG); 21 | 22 | typedef std::recursive_mutex mutex_type; 23 | typedef std::lock_guard lock_type; 24 | 25 | namespace { 26 | mutex_type& 27 | db_service_lock() 28 | { 29 | static mutex_type _mtx; 30 | return _mtx; 31 | } 32 | 33 | } // namespace 34 | 35 | db_service::pimpl& 36 | db_service::impl_ptr() 37 | { 38 | static pimpl p; 39 | return p; 40 | } 41 | 42 | db_service::pimpl 43 | db_service::impl(size_t pool_size, connection_params const& defaults) 44 | { 45 | lock_type lock(db_service_lock()); 46 | 47 | auto& pimpl = impl_ptr(); 48 | if (!pimpl) { 49 | pimpl.reset(new detail::database_impl(pool_size, defaults)); 50 | } 51 | return pimpl; 52 | } 53 | 54 | void 55 | db_service::initialize(size_t pool_size, connection_params const& defaults) 56 | { 57 | lock_type lock(db_service_lock()); 58 | 59 | auto& pimpl = impl_ptr(); 60 | if (!pimpl) { 61 | pimpl.reset(new detail::database_impl(pool_size, defaults)); 62 | } else { 63 | pimpl->set_defaults(pool_size, defaults); 64 | } 65 | } 66 | 67 | void 68 | db_service::add_connection(std::string const& connection_string, optional_size pool_size) 69 | { 70 | impl()->add_connection(connection_string, pool_size); 71 | } 72 | 73 | void 74 | db_service::add_connection(connection_options const& co, optional_size pool_size) 75 | { 76 | impl()->add_connection(co, pool_size); 77 | } 78 | 79 | void 80 | db_service::begin(dbalias const& alias, 81 | transaction_callback const& result, 82 | error_callback const& error, 83 | transaction_mode const& mode) 84 | { 85 | // TODO Wrap callbacks in strands 86 | impl()->get_connection(alias, result, error, mode); 87 | } 88 | 89 | void 90 | db_service::run() 91 | { 92 | impl()->run(); 93 | } 94 | 95 | void 96 | db_service::stop() 97 | { 98 | lock_type lock(db_service_lock()); 99 | local_log(logger::INFO) << "Stop db service"; 100 | 101 | auto& pimpl = impl_ptr(); 102 | if (pimpl) { 103 | pimpl->stop(); 104 | } 105 | pimpl.reset(); 106 | } 107 | 108 | asio_config::io_service_ptr 109 | db_service::io_service() 110 | { 111 | return impl()->io_service(); 112 | } 113 | 114 | } // namespace pg 115 | } // namespace db 116 | } // namespace tip 117 | -------------------------------------------------------------------------------- /src/tip/db/pg/detail/basic_connection.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * connection_base.cpp 3 | * 4 | * Created on: 11 июля 2015 г. 5 | * @author: zmij 6 | */ 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | namespace tip { 21 | namespace db { 22 | namespace pg { 23 | 24 | LOCAL_LOGGING_FACILITY_CFG(PGCONN, config::CONNECTION_LOG); 25 | 26 | template < typename TransportType > 27 | std::shared_ptr< detail::concrete_connection< TransportType > > 28 | create_connection(asio_config::io_service_ptr svc, 29 | connection_options const& opts, 30 | client_options_type const& co, 31 | connection_callbacks const& callbacks) 32 | { 33 | typedef detail::concrete_connection< TransportType > connection_type; 34 | typedef std::shared_ptr< connection_type > concrete_connection_ptr; 35 | 36 | concrete_connection_ptr conn(new connection_type(svc, co, callbacks)); 37 | conn->connect(opts); 38 | return conn; 39 | } 40 | 41 | basic_connection_ptr 42 | basic_connection::create(io_service_ptr svc, connection_options const& opts, 43 | client_options_type const& co, connection_callbacks const& callbacks) 44 | { 45 | if (opts.schema == "tcp") { 46 | return create_connection< detail::tcp_transport >(svc, opts, co, callbacks); 47 | } else if (opts.schema == "socket") { 48 | return create_connection< detail::socket_transport >(svc, opts, co, callbacks); 49 | } 50 | std::stringstream os; 51 | os << "Schema " << opts.schema << " is unsupported"; 52 | throw error::connection_error(os.str()); 53 | } 54 | 55 | basic_connection::basic_connection() 56 | { 57 | } 58 | 59 | basic_connection::~basic_connection() 60 | { 61 | local_log() << "*** basic_connection::~basic_connection()"; 62 | } 63 | 64 | void 65 | basic_connection::connect(connection_options const& opts) 66 | { 67 | do_connect(opts); 68 | } 69 | 70 | dbalias const& 71 | basic_connection::alias() const 72 | { 73 | return get_alias(); 74 | } 75 | 76 | void 77 | basic_connection::begin(events::begin&& evt) 78 | { 79 | do_begin(::std::move(evt)); 80 | } 81 | 82 | void 83 | basic_connection::commit(notification_callback cb, error_callback ecb) 84 | { 85 | do_commit(cb, ecb); 86 | } 87 | 88 | void 89 | basic_connection::rollback(notification_callback cb, error_callback ecb) 90 | { 91 | do_rollback(cb, ecb); 92 | } 93 | 94 | bool 95 | basic_connection::in_transaction() const 96 | { 97 | return is_in_transaction(); 98 | } 99 | 100 | void 101 | basic_connection::execute(events::execute&& query) 102 | { 103 | do_execute(::std::move(query)); 104 | } 105 | void 106 | basic_connection::execute(events::execute_prepared&& query) 107 | { 108 | do_execute(::std::move(query)); 109 | } 110 | 111 | 112 | void 113 | basic_connection::terminate() 114 | { 115 | local_log() << "Terminate connection"; 116 | do_terminate(); 117 | } 118 | 119 | } // namespace pg 120 | } // namespace db 121 | } // namespace tip 122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /src/tip/db/pg/detail/basic_connection.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * connection_base.hpp 3 | * 4 | * Created on: 11 июля 2015 г. 5 | * @author: zmij 6 | */ 7 | 8 | #ifndef TIP_DB_PG_DETAIL_CONNECTION_BASE_HPP_ 9 | #define TIP_DB_PG_DETAIL_CONNECTION_BASE_HPP_ 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | namespace boost { 17 | namespace asio { 18 | // forward declaration 19 | class io_service; 20 | } // namespace asio 21 | } // namespace boost 22 | 23 | namespace tip { 24 | namespace db { 25 | namespace pg { 26 | 27 | class resultset; 28 | class transaction; 29 | typedef std::shared_ptr< transaction > transaction_ptr; 30 | 31 | class basic_connection; 32 | typedef std::shared_ptr< basic_connection > basic_connection_ptr; 33 | 34 | typedef std::function < void (basic_connection_ptr) > connection_event_callback; 35 | typedef std::function < void (basic_connection_ptr, error::connection_error) > connection_error_callback; 36 | typedef std::function< void (resultset, bool) > query_internal_callback; 37 | typedef std::function< void() > notification_callback; 38 | 39 | struct connection_callbacks { 40 | connection_event_callback idle; 41 | connection_event_callback terminated; 42 | connection_error_callback error; 43 | }; 44 | 45 | namespace events { 46 | struct commit { 47 | notification_callback callback; 48 | error_callback error; 49 | }; 50 | struct rollback { 51 | notification_callback callback; 52 | error_callback error; 53 | }; 54 | 55 | struct execute { 56 | std::string expression; 57 | query_internal_callback result; 58 | query_error_callback error; 59 | }; 60 | struct execute_prepared { 61 | std::string expression; 62 | type_oid_sequence param_types; 63 | std::vector< byte > params; 64 | query_internal_callback result; 65 | query_error_callback error; 66 | }; 67 | 68 | } 69 | 70 | class basic_connection : public boost::noncopyable { 71 | public: 72 | typedef asio_config::io_service_ptr io_service_ptr; 73 | public: 74 | static basic_connection_ptr 75 | create(io_service_ptr svc, connection_options const&, 76 | client_options_type const&, connection_callbacks const&); 77 | public: 78 | virtual ~basic_connection(); 79 | 80 | void 81 | connect(connection_options const&); 82 | 83 | dbalias const& 84 | alias() const; 85 | 86 | void 87 | begin(events::begin&&); 88 | void 89 | commit(notification_callback = notification_callback(), error_callback = error_callback()); 90 | void 91 | rollback(notification_callback = notification_callback(), error_callback = error_callback()); 92 | 93 | bool 94 | in_transaction() const; 95 | 96 | void 97 | execute(events::execute&&); 98 | void 99 | execute(events::execute_prepared&&); 100 | 101 | void 102 | terminate(); 103 | protected: 104 | basic_connection(); 105 | 106 | private: 107 | virtual void 108 | do_connect(connection_options const& ) = 0; 109 | 110 | virtual dbalias const& 111 | get_alias() const = 0; 112 | 113 | virtual bool 114 | is_in_transaction() const = 0; 115 | 116 | virtual void 117 | do_begin(events::begin&&) = 0; 118 | virtual void 119 | do_commit(notification_callback, error_callback) = 0; 120 | virtual void 121 | do_rollback(notification_callback, error_callback) = 0; 122 | 123 | virtual void 124 | do_execute(events::execute&&) = 0; 125 | virtual void 126 | do_execute(events::execute_prepared&&) = 0; 127 | 128 | virtual void 129 | do_terminate() = 0; 130 | }; 131 | 132 | } // namespace pg 133 | } // namespace db 134 | } // namespace tip 135 | 136 | #endif /* TIP_DB_PG_DETAIL_CONNECTION_BASE_HPP_ */ 137 | -------------------------------------------------------------------------------- /src/tip/db/pg/detail/connection_pool.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * connection_pool.h 3 | * 4 | * Created on: 11 июля 2015 г. 5 | * @author: zmij 6 | */ 7 | 8 | #ifndef TIP_DB_PG_DETAIL_CONNECTION_POOL_H_ 9 | #define TIP_DB_PG_DETAIL_CONNECTION_POOL_H_ 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | namespace tip { 19 | namespace db { 20 | namespace pg { 21 | 22 | namespace detail { 23 | 24 | /** 25 | * Container of connections to the same database 26 | */ 27 | class connection_pool : public ::std::enable_shared_from_this, 28 | private boost::noncopyable { 29 | public: 30 | using io_service_ptr = asio_config::io_service_ptr; 31 | using connection_pool_ptr = ::std::shared_ptr; 32 | public: 33 | static connection_pool_ptr 34 | create(io_service_ptr service, size_t pool_size, 35 | connection_options const& co, 36 | client_options_type const& = client_options_type()); 37 | 38 | ~connection_pool(); 39 | 40 | dbalias const& 41 | alias() const; 42 | 43 | void 44 | get_connection(transaction_callback const&, error_callback const&, 45 | transaction_mode const&); 46 | 47 | void 48 | close(simple_callback); 49 | private: 50 | connection_pool(io_service_ptr service, size_t pool_size, 51 | connection_options const& co, 52 | client_options_type const&); 53 | 54 | void 55 | create_new_connection(); 56 | void 57 | connection_ready(connection_ptr c); 58 | void 59 | connection_terminated(connection_ptr c); 60 | void 61 | connection_error(connection_ptr c, error::connection_error const& ec); 62 | 63 | void 64 | close_connections(); 65 | private: 66 | struct impl; 67 | using pimpl = ::std::unique_ptr; 68 | pimpl pimpl_; 69 | }; 70 | 71 | } /* namespace detail */ 72 | } /* namespace pg */ 73 | } /* namespace db */ 74 | } /* namespace tip */ 75 | 76 | #endif /* TIP_DB_PG_DETAIL_CONNECTION_POOL_H_ */ 77 | -------------------------------------------------------------------------------- /src/tip/db/pg/detail/database_impl.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * database_impl.hpp 3 | * 4 | * Created on: Jul 13, 2015 5 | * Author: zmij 6 | */ 7 | 8 | #ifndef TIP_DB_PG_DETAIL_DATABASE_IMPL_HPP_ 9 | #define TIP_DB_PG_DETAIL_DATABASE_IMPL_HPP_ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | #include 18 | 19 | namespace tip { 20 | namespace db { 21 | namespace pg { 22 | namespace detail { 23 | 24 | struct connection_pool; 25 | 26 | class database_impl : private boost::noncopyable { 27 | typedef std::shared_ptr connection_pool_ptr; 28 | typedef std::map pools_map; 29 | public: 30 | database_impl(size_t pool_size, client_options_type const& defaults); 31 | virtual ~database_impl(); 32 | 33 | void 34 | set_defaults(size_t pool_size, client_options_type const& defaults); 35 | 36 | void 37 | add_connection(std::string const& connection_string, 38 | db_service::optional_size pool_size = db_service::optional_size(), 39 | client_options_type const& params = client_options_type()); 40 | void 41 | add_connection(connection_options options, 42 | db_service::optional_size pool_size = db_service::optional_size(), 43 | client_options_type const& params = client_options_type()); 44 | 45 | void 46 | get_connection(dbalias const&, transaction_callback const&, 47 | error_callback const&, transaction_mode const&); 48 | 49 | void 50 | run(); 51 | 52 | void 53 | stop(); 54 | 55 | asio_config::io_service_ptr 56 | io_service() 57 | { 58 | return service_; 59 | } 60 | private: 61 | connection_pool_ptr 62 | add_pool(connection_options const&, 63 | db_service::optional_size = db_service::optional_size(), 64 | client_options_type const& = {}); 65 | 66 | asio_config::io_service_ptr service_; 67 | size_t pool_size_; 68 | 69 | pools_map connections_; 70 | client_options_type defaults_; 71 | 72 | enum state_type { 73 | running, 74 | closing, 75 | closed 76 | }; 77 | state_type state_; 78 | }; 79 | 80 | } /* namespace detail */ 81 | } /* namespace pg */ 82 | } /* namespace db */ 83 | } /* namespace tip */ 84 | 85 | #endif /* TIP_DB_PG_DETAIL_DATABASE_IMPL_HPP_ */ 86 | -------------------------------------------------------------------------------- /src/tip/db/pg/detail/protocol_parsers.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * protocol_parsers.cpp 3 | * 4 | * Created on: Jul 19, 2015 5 | * Author: zmij 6 | */ 7 | 8 | #include 9 | 10 | namespace tip { 11 | namespace db { 12 | namespace pg { 13 | namespace io { 14 | namespace detail { 15 | 16 | char 17 | bytea_parser::hex_to_byte(char input) 18 | { 19 | if (std::isxdigit(input)) { 20 | if ('0' <= input && input <= '0') { 21 | return input - '0'; 22 | } else if ('a' <= input && input <= 'f') { 23 | return input - 'a' + 10; 24 | } else if ('A' <= input && input <= 'F') { 25 | return input - 'A' + 10; 26 | } 27 | } 28 | return 0; 29 | } 30 | 31 | } // namespace detail 32 | } // namespace io 33 | } // namespace pg 34 | } // namespace db 35 | } // namespace tip 36 | -------------------------------------------------------------------------------- /src/tip/db/pg/detail/result_impl.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * result_impl.cpp 3 | * 4 | * Created on: 12 июля 2015 г. 5 | * @author: zmij 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace tip { 15 | namespace db { 16 | namespace pg { 17 | namespace detail { 18 | 19 | result_impl::result_impl() 20 | { 21 | } 22 | 23 | size_t 24 | result_impl::size() const 25 | { 26 | return rows_.size(); 27 | } 28 | 29 | bool 30 | result_impl::empty() const 31 | { 32 | return rows_.empty(); 33 | } 34 | 35 | void 36 | result_impl::check_row_index(uinteger row) const 37 | { 38 | if (row >= rows_.size()) { 39 | std::ostringstream out; 40 | out << "Row index " << row << " is out of bounds [0.." 41 | << rows_.size() << ")"; 42 | throw std::out_of_range(out.str().c_str()); 43 | } 44 | } 45 | 46 | field_buffer 47 | result_impl::at(uinteger row, usmallint col) const 48 | { 49 | check_row_index(row); 50 | row_data const& rd = rows_[row]; 51 | return rd.field_data(col); 52 | } 53 | 54 | bool 55 | result_impl::is_null(uinteger row, usmallint col) const 56 | { 57 | check_row_index(row); 58 | row_data const& rd = rows_[row]; 59 | return rd.is_null(col); 60 | } 61 | 62 | row_data::data_buffer_bounds 63 | result_impl::buffer_bounds(uinteger row, usmallint col) const 64 | { 65 | check_row_index(row); 66 | row_data const& rd = rows_[row]; 67 | return rd.field_buffer_bounds(col); 68 | } 69 | 70 | } /* namespace detail */ 71 | } /* namespace pg */ 72 | } /* namespace db */ 73 | } /* namespace tip */ 74 | -------------------------------------------------------------------------------- /src/tip/db/pg/detail/result_impl.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * result_impl.hpp 3 | * 4 | * Created on: 12 июля 2015 г. 5 | * @author: zmij 6 | */ 7 | 8 | #ifndef TIP_DB_PG_DETAIL_RESULT_IMPL_HPP_ 9 | #define TIP_DB_PG_DETAIL_RESULT_IMPL_HPP_ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | namespace tip { 16 | namespace db { 17 | namespace pg { 18 | namespace detail { 19 | 20 | class result_impl { 21 | public: 22 | typedef std::vector row_set_type; 23 | public: 24 | result_impl(); 25 | 26 | row_description_type& 27 | row_description() 28 | { return row_description_; } 29 | row_description_type const& 30 | row_description() const 31 | { return row_description_; } 32 | 33 | row_set_type& 34 | rows() 35 | { return rows_; } 36 | 37 | size_t 38 | size() const; 39 | 40 | bool 41 | empty() const; 42 | 43 | field_buffer 44 | at(uinteger row, usmallint col) const; 45 | 46 | row_data::data_buffer_bounds 47 | buffer_bounds(uinteger row, usmallint col) const; 48 | 49 | bool 50 | is_null(uinteger row, usmallint col) const; 51 | private: 52 | void 53 | check_row_index(uinteger row) const; 54 | row_description_type row_description_; 55 | row_set_type rows_; 56 | }; 57 | 58 | } /* namespace detail */ 59 | } /* namespace pg */ 60 | } /* namespace db */ 61 | } /* namespace tip */ 62 | 63 | #endif /* TIP_DB_PG_DETAIL_RESULT_IMPL_HPP_ */ 64 | -------------------------------------------------------------------------------- /src/tip/db/pg/detail/transport.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * transport.cpp 3 | * 4 | * Created on: Jul 30, 2015 5 | * Author: zmij 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | 15 | namespace tip { 16 | namespace db { 17 | namespace pg { 18 | namespace detail { 19 | 20 | LOCAL_LOGGING_FACILITY_CFG(POSTGRE, config::CONNECTION_LOG); 21 | 22 | //**************************************************************************** 23 | // tcp_layer 24 | tcp_transport::tcp_transport(io_service_ptr service) : 25 | resolver_(*service), socket(*service) 26 | { 27 | } 28 | 29 | void 30 | tcp_transport::connect_async(connection_options const& conn, connect_callback cb) 31 | { 32 | if (conn.uri.empty()) { 33 | throw error::connection_error("No connection uri!"); 34 | } 35 | if (conn.schema != "tcp") { 36 | throw error::connection_error("Wrong connection schema for TCP transport"); 37 | } 38 | std::string host = conn.uri; 39 | std::string svc = "5432"; 40 | std::string::size_type pos = conn.uri.find(":"); 41 | if (pos != std::string::npos) { 42 | host = conn.uri.substr(0, pos); 43 | svc = conn.uri.substr(pos + 1); 44 | } 45 | 46 | tcp::resolver::query query (host, svc); 47 | resolver_.async_resolve(query, boost::bind(&tcp_transport::handle_resolve, 48 | this, _1, _2, cb )); 49 | 50 | } 51 | 52 | void 53 | tcp_transport::handle_resolve(error_code const& ec, 54 | tcp::resolver::iterator endpoint_iterator, connect_callback cb) 55 | { 56 | if (!ec) { 57 | ASIO_NAMESPACE::async_connect(socket, endpoint_iterator, 58 | boost::bind( &tcp_transport::handle_connect, 59 | this, _1, cb)); 60 | } else { 61 | cb(ec); 62 | } 63 | } 64 | 65 | void 66 | tcp_transport::handle_connect(error_code const& ec, connect_callback cb) 67 | { 68 | cb(ec); 69 | } 70 | 71 | bool 72 | tcp_transport::connected() const 73 | { 74 | return socket.is_open(); 75 | } 76 | 77 | void 78 | tcp_transport::close() 79 | { 80 | if (socket.is_open()) 81 | socket.close(); 82 | } 83 | 84 | //---------------------------------------------------------------------------- 85 | // socket_transport implementation 86 | //---------------------------------------------------------------------------- 87 | socket_transport::socket_transport(io_service_ptr service) 88 | : socket(*service) 89 | { 90 | } 91 | 92 | void 93 | socket_transport::connect_async(connection_options const& conn, 94 | connect_callback cb) 95 | { 96 | using asio_config::stream_protocol; 97 | if (conn.schema != "socket") { 98 | throw error::connection_error("Wrong connection schema for TCP transport"); 99 | } 100 | std::string uri = conn.uri; 101 | 102 | if (uri.empty()) { 103 | local_log(logger::WARNING) << "Socket name is empty. Trying default"; 104 | uri = "/tmp/.s.PGSQL.5432"; 105 | } 106 | socket.async_connect(stream_protocol::endpoint(uri), 107 | [cb](error_code const& ec) { cb(ec); }); 108 | } 109 | 110 | bool 111 | socket_transport::connected() const 112 | { 113 | return socket.is_open(); 114 | } 115 | 116 | void 117 | socket_transport::close() 118 | { 119 | if (socket.is_open()) 120 | socket.close(); 121 | } 122 | 123 | } // namespace detail 124 | } // namespace pg 125 | } // namespace db 126 | } // namespace tip 127 | 128 | 129 | -------------------------------------------------------------------------------- /src/tip/db/pg/detail/transport.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * transport.hpp 3 | * 4 | * Created on: Jul 30, 2015 5 | * Author: zmij 6 | */ 7 | 8 | #ifndef LIB_PG_ASYNC_SRC_TIP_DB_PG_DETAIL_TRANSPORT_HPP_ 9 | #define LIB_PG_ASYNC_SRC_TIP_DB_PG_DETAIL_TRANSPORT_HPP_ 10 | 11 | #include 12 | #include 13 | 14 | namespace tip { 15 | namespace db { 16 | namespace pg { 17 | namespace detail { 18 | 19 | struct tcp_transport { 20 | typedef asio_config::io_service_ptr io_service_ptr; 21 | typedef asio_config::tcp tcp; 22 | typedef asio_config::error_code error_code; 23 | typedef std::function< void (error_code const&) > connect_callback; 24 | typedef tcp::socket socket_type; 25 | 26 | tcp_transport(io_service_ptr); 27 | 28 | void 29 | connect_async(connection_options const&, connect_callback); 30 | 31 | bool 32 | connected() const; 33 | 34 | void 35 | close(); 36 | 37 | template < typename BufferType, typename HandlerType > 38 | void 39 | async_read(BufferType& buffer, HandlerType handler) 40 | { 41 | ASIO_NAMESPACE::async_read(socket, buffer, 42 | ASIO_NAMESPACE::transfer_at_least(1), handler); 43 | } 44 | 45 | template < typename BufferType, typename HandlerType > 46 | void 47 | async_write(BufferType const& buffer, HandlerType handler) 48 | { 49 | ASIO_NAMESPACE::async_write(socket, buffer, handler); 50 | } 51 | private: 52 | tcp::resolver resolver_; 53 | socket_type socket; 54 | 55 | 56 | void 57 | handle_resolve(error_code const& ec, 58 | tcp::resolver::iterator endpoint_iterator, 59 | connect_callback); 60 | void 61 | handle_connect(error_code const& ec, connect_callback); 62 | }; 63 | 64 | struct socket_transport { 65 | typedef asio_config::io_service_ptr io_service_ptr; 66 | typedef asio_config::stream_protocol::socket socket_type; 67 | typedef asio_config::error_code error_code; 68 | typedef std::function< void (error_code const&) > connect_callback; 69 | 70 | socket_transport(io_service_ptr); 71 | 72 | void 73 | connect_async(connection_options const&, connect_callback); 74 | 75 | bool 76 | connected() const; 77 | 78 | void 79 | close(); 80 | template < typename BufferType, typename HandlerType > 81 | void 82 | async_read(BufferType& buffer, HandlerType handler) 83 | { 84 | ASIO_NAMESPACE::async_read(socket, buffer, 85 | ASIO_NAMESPACE::transfer_at_least(1), handler); 86 | } 87 | 88 | template < typename BufferType, typename HandlerType > 89 | void 90 | async_write(BufferType const& buffer, HandlerType handler) 91 | { 92 | ASIO_NAMESPACE::async_write(socket, buffer, handler); 93 | } 94 | private: 95 | socket_type socket; 96 | }; 97 | 98 | 99 | } // namespace detail 100 | } // namespace pg 101 | } // namespace db 102 | } // namespace tip 103 | 104 | 105 | #endif /* LIB_PG_ASYNC_SRC_TIP_DB_PG_DETAIL_TRANSPORT_HPP_ */ 106 | -------------------------------------------------------------------------------- /src/tip/db/pg/error.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * db_error.cpp 3 | * 4 | * Created on: 16 июля 2015 г. 5 | * @author: zmij 6 | */ 7 | 8 | #include 9 | 10 | namespace tip { 11 | namespace db { 12 | namespace pg { 13 | namespace error { 14 | 15 | db_error::db_error(std::string const& what_arg) 16 | : std::runtime_error(what_arg), sqlstate(sqlstate::unknown_code) 17 | { 18 | } 19 | 20 | db_error::db_error(char const* what_arg) 21 | : std::runtime_error(what_arg), sqlstate(sqlstate::unknown_code) 22 | { 23 | } 24 | 25 | db_error::db_error(std::string const& message, 26 | std::string s, 27 | std::string c, 28 | std::string d) 29 | : std::runtime_error(message), severity(s), code(c), detail(d), 30 | sqlstate(sqlstate::code_to_state(code)) 31 | { 32 | } 33 | 34 | connection_error::connection_error(std::string const& what_arg) 35 | : db_error(what_arg) 36 | { 37 | } 38 | 39 | connection_error::connection_error(char const* what_arg) 40 | : db_error(what_arg) 41 | { 42 | } 43 | 44 | query_error::query_error(std::string const& what_arg) 45 | : db_error(what_arg) 46 | { 47 | } 48 | 49 | query_error::query_error(char const* what_arg) 50 | : db_error(what_arg) 51 | { 52 | } 53 | 54 | query_error::query_error(std::string const& message, 55 | std::string s, std::string c, std::string d) 56 | : db_error(message, s, c, d) 57 | { 58 | } 59 | 60 | client_error::client_error(std::string const& what_arg) 61 | : db_error(what_arg) 62 | { 63 | } 64 | 65 | client_error::client_error(char const* what_arg) 66 | : db_error(what_arg) 67 | { 68 | } 69 | 70 | client_error::client_error(std::exception const& ex) 71 | : db_error(std::string("Client thrown exception: ") + ex.what()) 72 | { 73 | } 74 | 75 | value_is_null::value_is_null(std::string const& field_name) 76 | : db_error("Value in field " + field_name + " is null") 77 | { 78 | } 79 | 80 | } // namespace error 81 | } // namespace pg 82 | } // namespace db 83 | } // namespace tip 84 | -------------------------------------------------------------------------------- /src/tip/db/pg/log.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * log.hpp 3 | * 4 | * Created on: Jul 19, 2015 5 | * Author: zmij 6 | */ 7 | 8 | #ifndef LIB_PG_ASYNC_SRC_TIP_DB_PG_LOG_HPP_ 9 | #define LIB_PG_ASYNC_SRC_TIP_DB_PG_LOG_HPP_ 10 | 11 | #ifdef WITH_TIP_LOG 12 | #include 13 | #else 14 | #include 15 | #endif 16 | 17 | #include 18 | 19 | #endif /* LIB_PG_ASYNC_SRC_TIP_DB_PG_LOG_HPP_ */ 20 | -------------------------------------------------------------------------------- /src/tip/db/pg/log_config.in.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * log_config.in.hpp 3 | * 4 | * Created on: Nov 5, 2015 5 | * Author: zmij 6 | */ 7 | 8 | #ifndef LIB_PG_ASYNC_SRC_TIP_DB_PG_LOG_CONFIG_IN_HPP_ 9 | #define LIB_PG_ASYNC_SRC_TIP_DB_PG_LOG_CONFIG_IN_HPP_ 10 | 11 | #include 12 | 13 | namespace tip { 14 | namespace db { 15 | namespace pg { 16 | namespace config { 17 | 18 | namespace log = ::psst::log; 19 | 20 | const log::logger::event_severity SERVICE_LOG = log::logger::@PGASYNC_LOG_SERVICE@; 21 | const log::logger::event_severity CONNECTION_LOG = log::logger::@PGASYNC_LOG_CONNECTION@; 22 | const log::logger::event_severity QUERY_LOG = log::logger::@PGASYNC_LOG_QUERY@; 23 | const log::logger::event_severity INTERNALS_LOG = log::logger::@PGASYNC_LOG_INTERNALS@; 24 | 25 | 26 | } // namespace config 27 | } // namespace pg 28 | } // namespace db 29 | } // namespace tip 30 | 31 | #endif /* LIB_PG_ASYNC_SRC_TIP_DB_PG_LOG_CONFIG_IN_HPP_ */ 32 | -------------------------------------------------------------------------------- /src/tip/db/pg/protocol_io_traits.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * protocol_io_traits.cpp 3 | * 4 | * Created on: Jul 19, 2015 5 | * Author: zmij 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | namespace tip { 17 | namespace db { 18 | namespace pg { 19 | namespace io { 20 | 21 | LOCAL_LOGGING_FACILITY(PGIO, TRACE); 22 | 23 | namespace traits { 24 | 25 | namespace { 26 | 27 | using namespace oids::type; 28 | 29 | std::set< oid_type > BINARY_PARSERS { 30 | boolean, oids::type::bytea, int2, int4, int8, oid, tid, xid, cid, 31 | timestamp, timestamptz, uuid 32 | }; 33 | } // namespace 34 | 35 | void 36 | register_parser_type(oids::type::oid_type oid) 37 | { 38 | BINARY_PARSERS.insert(oid); 39 | } 40 | 41 | bool 42 | has_binary_parser(oids::type::oid_type oid) 43 | { 44 | return BINARY_PARSERS.count(oid); 45 | } 46 | 47 | } // namespace traits 48 | 49 | namespace { 50 | 51 | const std::set< std::string > TRUE_LITERALS { 52 | "TRUE", 53 | "t", 54 | "true", 55 | "y", 56 | "yes", 57 | "on", 58 | "1" 59 | }; 60 | 61 | const std::set< std::string > FALSE_LITERALS { 62 | "FALSE", 63 | "f", 64 | "false", 65 | "n", 66 | "no", 67 | "off", 68 | "0" 69 | }; 70 | 71 | } // namespace 72 | 73 | bool 74 | protocol_parser< bool, TEXT_DATA_FORMAT >::use_literal(std::string const& l) 75 | { 76 | if (TRUE_LITERALS.count(l)) { 77 | base_type::value = true; 78 | return true; 79 | } else if (FALSE_LITERALS.count(l)) { 80 | base_type::value = false; 81 | return true; 82 | } 83 | return false; 84 | } 85 | 86 | 87 | bool 88 | protocol_parser< bytea, TEXT_DATA_FORMAT >::operator()(std::istream& in) 89 | { 90 | std::vector data; 91 | std::istream_iterator b(in); 92 | std::istream_iterator e; 93 | 94 | auto result = detail::bytea_parser().parse(b, e, std::back_inserter(data)); 95 | if (result.first) { 96 | base_type::value.swap(data); 97 | return true; 98 | } 99 | return false; 100 | } 101 | 102 | bool 103 | protocol_parser< bytea, TEXT_DATA_FORMAT >::operator()(buffer_type& buffer) 104 | { 105 | std::vector data; 106 | auto result = detail::bytea_parser().parse(buffer.begin(), buffer.end(), 107 | std::back_inserter(data)); 108 | if (result.first) { 109 | base_type::value.swap(data); 110 | return true; 111 | } 112 | return false; 113 | } 114 | 115 | using ::boost::posix_time::ptime; 116 | using ::boost::gregorian::date; 117 | 118 | ptime const 119 | protocol_formatter::pg_epoch{ date{2000, boost::gregorian::Jan, 1} }; 120 | 121 | void 122 | protocol_parser::from_int_value(bigint val) 123 | { 124 | using fmt_type = protocol_formatter; 125 | base_type::value = fmt_type::pg_epoch + ::boost::posix_time::microseconds{val}; 126 | } 127 | 128 | bool 129 | protocol_formatter::operator()( ::std::vector& buffer ) 130 | { 131 | if (buffer.capacity() - buffer.size() < size()) { 132 | buffer.reserve(buffer.size() + size()); 133 | } 134 | 135 | bigint delta =(base_type::value - pg_epoch).total_microseconds(); 136 | delta = util::endian::native_to_big(delta); 137 | char const* p = reinterpret_cast(&delta); 138 | char const* e = p + size(); 139 | ::std::copy(p, e, ::std::back_inserter(buffer)); 140 | return true; 141 | } 142 | 143 | } // namespace io 144 | } // namespace pg 145 | } // namespace db 146 | } // namespace tip 147 | -------------------------------------------------------------------------------- /src/tip/db/pg/transaction.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * connection_lock.cpp 3 | * 4 | * Created on: 14 июля 2015 г. 5 | * @author: zmij 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace tip { 14 | namespace db { 15 | namespace pg { 16 | 17 | LOCAL_LOGGING_FACILITY_CFG(PGTRAN, config::QUERY_LOG); 18 | 19 | transaction::transaction(connection_ptr conn) 20 | : connection_(conn), finished_(false) 21 | { 22 | } 23 | 24 | transaction::~transaction() 25 | { 26 | if (connection_->in_transaction() && !finished_.test_and_set()) { 27 | local_log(logger::WARNING) << "Transaction object abandoned, rolling back"; 28 | try { 29 | connection_->rollback(); 30 | } catch (::std::exception const& e) { 31 | local_log(logger::ERROR) << "Exception rolling back: " << e.what(); 32 | } catch (...) { 33 | local_log(logger::ERROR) << "Exception rolling back: unexpected"; 34 | } 35 | } 36 | } 37 | 38 | dbalias const& 39 | transaction::alias() const 40 | { 41 | return connection_->alias(); 42 | } 43 | 44 | bool 45 | transaction::in_transaction() const 46 | { 47 | return connection_->in_transaction(); 48 | } 49 | 50 | void 51 | transaction::commit_async(notification_callback cb, error_callback ecb) 52 | { 53 | if (!finished_.test_and_set()) 54 | connection_->commit(cb); 55 | } 56 | 57 | void 58 | transaction::rollback_async(notification_callback cb, error_callback ecb) 59 | { 60 | if (!finished_.test_and_set()) 61 | connection_->rollback(cb); 62 | } 63 | void 64 | transaction::execute(std::string const& query, query_result_callback result, 65 | query_error_callback error) 66 | { 67 | connection_->execute(events::execute{ 68 | query, 69 | std::bind(&transaction::handle_results, shared_from_this(), 70 | std::placeholders::_1, std::placeholders::_2, result), 71 | std::bind(&transaction::handle_query_error, shared_from_this(), 72 | std::placeholders::_1, error) 73 | }); 74 | } 75 | void 76 | transaction::execute(std::string const& query, type_oid_sequence const& param_types, 77 | std::vector< byte > params_buffer, 78 | query_result_callback result, query_error_callback error) 79 | { 80 | connection_->execute(events::execute_prepared{ 81 | query, param_types, params_buffer, 82 | std::bind(&transaction::handle_results, shared_from_this(), 83 | std::placeholders::_1, std::placeholders::_2, result), 84 | std::bind(&transaction::handle_query_error, shared_from_this(), 85 | std::placeholders::_1, error) 86 | }); 87 | } 88 | 89 | void 90 | transaction::handle_results(resultset r, bool complete, query_result_callback result) 91 | { 92 | if (result) { 93 | result(shared_from_this(), r, complete); 94 | } 95 | } 96 | 97 | void 98 | transaction::handle_query_error(error::query_error const& e, query_error_callback error) 99 | { 100 | if (error) { 101 | error(e); 102 | } 103 | } 104 | 105 | } /* namespace pg */ 106 | } /* namespace db */ 107 | } /* namespace tip */ 108 | -------------------------------------------------------------------------------- /src/tip/db/pg/version.in.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * version.hpp 3 | * 4 | * Created on: Nov 30, 2015 5 | * Author: zmij 6 | */ 7 | 8 | #ifndef PG_ASYNC_SRC_TIP_DB_PG_VERSION_IN_HPP_ 9 | #define PG_ASYNC_SRC_TIP_DB_PG_VERSION_IN_HPP_ 10 | 11 | #ifdef VERSION_FILE 12 | #include VERSION_FILE 13 | #else 14 | #include 15 | 16 | namespace tip { 17 | 18 | /** Version number */ 19 | const std::string VERSION = "@PROJECT_VERSION@"; 20 | /** Git revision */ 21 | const std::string GIT_VERSION = "@GIT_VERSION@"; 22 | /** Git branch of the build */ 23 | const std::string BRANCH = "@GIT_BRANCH@"; 24 | 25 | } // namespace tip 26 | #endif 27 | 28 | 29 | 30 | #endif /* PG_ASYNC_SRC_TIP_DB_PG_VERSION_IN_HPP_ */ 31 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMakeLists.txt 2 | # 3 | # @author zmij 4 | # @date Jul 18, 2015 5 | 6 | cmake_minimum_required(VERSION 2.6) 7 | 8 | include_directories(${CMAKE_CURRENT_BINARY_DIR}) 9 | find_package( Boost COMPONENTS 10 | program_options 11 | REQUIRED ) 12 | find_package(GTest REQUIRED) 13 | include_directories(${GTEST_INCLUDE_DIRS}) 14 | 15 | add_subdirectory(db) 16 | -------------------------------------------------------------------------------- /test/db/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # @file /tip-server/test/db/CMakeLists.txt 2 | # @author: zmij 3 | # Created on: Jul 10, 2015 4 | 5 | cmake_minimum_required(VERSION 2.6) 6 | 7 | option(TEST_PG_ASYNC_FSM "Build test for pg_async FSM" OFF) 8 | 9 | configure_file(config.in.hpp config.hpp) 10 | 11 | # Test SQL script files 12 | set (test_pg_SQL results-parse-test.sql) 13 | 14 | foreach(sql_file ${test_pg_SQL}) 15 | add_custom_command( 16 | OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${sql_file} 17 | DEPENDS ${sql_file} 18 | COMMENT "Copy test SQL script ${sql_file}" 19 | COMMAND cp ${CMAKE_CURRENT_SOURCE_DIR}/${sql_file} ${CMAKE_CURRENT_BINARY_DIR}/${sql_file} 20 | ) 21 | endforeach() 22 | 23 | add_custom_target(test-sql-scripts 24 | DEPENDS ${test_pg_SQL} 25 | COMMENT "Copy test SQL scripts" 26 | ) 27 | 28 | set(test_pg_SRCS 29 | test_main.cpp 30 | test-environment.cpp 31 | internals_tests.cpp 32 | db_io_tests.cpp 33 | query_tests.cpp 34 | errors_tests.cpp 35 | array_support_test.cpp 36 | timestamp_io_test.cpp 37 | uuid_io_test.cpp 38 | ) 39 | 40 | if(TEST_PG_ASYNC_FSM) 41 | list(APPEND test_pg_SRCS fsm_tests.cpp) 42 | endif() 43 | 44 | set(PGTEST test-pg-async) 45 | 46 | add_executable( ${PGTEST} ${test_pg_SRCS}) 47 | 48 | target_link_libraries( 49 | ${PGTEST} 50 | ${Boost_PROGRAM_OPTIONS_LIBRARIES} 51 | ${GTEST_LIBRARIES} 52 | ${PGASYNC_LIB_NAME} 53 | ) 54 | 55 | if (TEST_DATABASE) 56 | set(DB_TEST_ARGS 57 | "-d${TEST_DATABASE}" -s2 -x4 -q10 --run-deadline=1 58 | ) 59 | else() 60 | set(DB_TEST_ARGS) 61 | endif() 62 | 63 | if (GTEST_XML_OUTPUT) 64 | set ( 65 | TEST_ARGS ${TEST_ARGS} 66 | --gtest_output=xml:test-pg-async-detail.xml 67 | ) 68 | endif() 69 | 70 | 71 | add_test( 72 | NAME test-pg-async 73 | COMMAND ${PGTEST} ${DB_TEST_ARGS} ${TEST_ARGS} 74 | ) 75 | 76 | 77 | add_dependencies(${PGTEST} test-sql-scripts) 78 | 79 | if(WITH_BOOST_FIBER) 80 | #----------------------------------------------------------------------------- 81 | # PG fiber test 82 | 83 | set(fiber_test_SRCS 84 | test_main.cpp 85 | test-environment.cpp 86 | fiber_query_test.cpp 87 | ) 88 | add_executable(test-pg-fiber ${fiber_test_SRCS}) 89 | target_link_libraries( 90 | test-pg-fiber 91 | ${Boost_PROGRAM_OPTIONS_LIBRARIES} 92 | ${GTEST_LIBRARIES} 93 | ${PGASYNC_LIB_NAME} 94 | ${FIBER_LIBS} 95 | ) 96 | 97 | if (GTEST_XML_OUTPUT) 98 | set ( 99 | FIBER_TEST_ARGS 100 | --gtest_output=xml:test-pg-fiber-detail.xml 101 | ) 102 | endif() 103 | 104 | 105 | add_test( 106 | NAME test-pg-fiber 107 | COMMAND test-pg-fiber ${DB_TEST_ARGS} ${FIBER_TEST_ARGS} 108 | ) 109 | 110 | 111 | endif() 112 | 113 | -------------------------------------------------------------------------------- /test/db/config.in.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * config.hpp 3 | * 4 | * Created on: Jul 16, 2015 5 | * Author: zmij 6 | */ 7 | 8 | #ifndef DB_CONFIG_HPP_ 9 | #define DB_CONFIG_HPP_ 10 | 11 | #include 12 | 13 | namespace tip { 14 | namespace db { 15 | namespace pg { 16 | namespace test { 17 | 18 | const std::string SCRIPT_SOURCE_DIR = "@CMAKE_CURRENT_BINARY_DIR@/"; 19 | 20 | } // namespace test 21 | } // namespace pg 22 | } // namespace db 23 | } // namespace tip 24 | 25 | 26 | #endif /* DB_CONFIG_HPP_ */ 27 | -------------------------------------------------------------------------------- /test/db/extended_query_mode.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * extended-query-mode.cpp 3 | * 4 | * Created on: Jul 23, 2015 5 | * Author: zmij 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "db/config.hpp" 32 | 33 | LOCAL_LOGGING_FACILITY(PGTEST, TRACE); 34 | 35 | namespace { 36 | 37 | std::string test_database; 38 | 39 | } // namespace 40 | 41 | int 42 | test_execute_prepared() 43 | { 44 | if (!test_database.empty()) { 45 | using namespace tip::db::pg; 46 | connection_options opts = connection_options::parse(test_database); 47 | local_log(logger::INFO) << "Extended query test"; 48 | boost::asio::io_service io_service; 49 | bool transaction_error = false; 50 | int tran_count = 0; 51 | 52 | std::vector< oids::type::oid_type > param_types; 53 | 54 | std::vector params; 55 | tip::db::pg::detail::write_params(param_types, params, 10, 20); 56 | 57 | connection_ptr conn(connection::create(io_service, 58 | [&](connection_ptr c) { 59 | if (!tran_count) { 60 | c->begin_transaction( 61 | [&](transaction_ptr c_lock){ 62 | tran_count++; 63 | (*c_lock)->execute_prepared("select * from pg_catalog.pg_type where typelem > $1 limit $2", 64 | param_types, params, 65 | [&](transaction_ptr c, resultset r, bool complete) { 66 | local_log() << "Received a resultset columns: " << r.columns_size() 67 | << " rows: " << r.size() 68 | << " completed: " << std::boolalpha << complete; 69 | if (complete) 70 | (*c)->terminate(); 71 | }, [](db_error const&) {}, c_lock); 72 | }, 73 | [&](db_error const&){ 74 | transaction_error = true; 75 | }, true); 76 | } 77 | }, [] (connection_ptr c) { 78 | }, [](connection_ptr c, connection_error const& ec) { 79 | ec.what(); 80 | }, opts, { 81 | {"client_encoding", "UTF8"}, 82 | {"application_name", "pg_async"}, 83 | //{"client_min_messages", "debug5"} 84 | })); 85 | io_service.run(); 86 | } 87 | return 0; 88 | } 89 | 90 | int 91 | main(int argc, char* argv[]) 92 | { 93 | try { 94 | logger::min_severity(logger::TRACE); 95 | logger::use_colors(true); 96 | if (argc > 1) { 97 | test_database = argv[1]; 98 | test_execute_prepared(); 99 | } 100 | } catch (std::exception const& e) { 101 | std::cerr << "Exception: " << e.what() << "\n"; 102 | } catch (...) { 103 | std::cerr << "Unexpected exception\n"; 104 | } 105 | return 0; 106 | } 107 | -------------------------------------------------------------------------------- /test/db/fiber_query_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * fiber_query_test.cpp 3 | * 4 | * Created on: Mar 29, 2017 5 | * Author: zmij 6 | */ 7 | 8 | #include 9 | 10 | #ifndef WITH_BOOST_FIBERS 11 | #define WITH_BOOST_FIBERS 12 | #endif 13 | 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | #include "db/config.hpp" 21 | #include "test-environment.hpp" 22 | 23 | namespace tip { 24 | namespace db { 25 | namespace pg { 26 | namespace test { 27 | 28 | LOCAL_LOGGING_FACILITY(PGTEST, TRACE); 29 | 30 | TEST(FiberTest, DISABLED_TheOnly) 31 | { 32 | if (!environment::test_database.empty()) { 33 | auto runner = ::psst::asio::fiber::use_shared_work_algorithm( db_service::io_service() ); 34 | 35 | ASSERT_NO_THROW(db_service::add_connection(environment::test_database, 36 | environment::connection_pool)); 37 | connection_options opts = connection_options::parse(environment::test_database); 38 | 39 | const auto fiber_cnt = environment::num_requests; 40 | const auto thread_cnt = environment::num_threads; 41 | 42 | auto fib_fn = [&](boost::fibers::barrier& barrier) { 43 | try { 44 | auto trx = db_service::begin(opts.alias); 45 | local_log() << "Transaction started"; 46 | EXPECT_TRUE(trx.get()); 47 | 48 | EXPECT_NO_THROW(query(trx, "create temporary table pg_async_test(b bigint)")()); 49 | local_log() << "Query one finished"; 50 | EXPECT_NO_THROW(query(trx, "insert into pg_async_test values(1),(2),(3)")()); 51 | local_log() << "Query two finished"; 52 | auto res = query(trx, "select * from pg_async_test")(); 53 | EXPECT_TRUE(res); 54 | EXPECT_EQ(1, res.columns_size()); 55 | EXPECT_EQ(3, res.size()); 56 | local_log() << "Query tree finished"; 57 | EXPECT_NO_THROW(query(trx, "drop table pg_async_test")()); 58 | local_log() << "Query four finished"; 59 | EXPECT_NO_THROW(trx->commit()); 60 | local_log() << "Transaction committed"; 61 | } catch (::std::exception const& e) { 62 | local_log(logger::ERROR) << "Exception while running test " << e.what(); 63 | } 64 | 65 | if (barrier.wait()) { 66 | db_service::stop(); 67 | } 68 | 69 | local_log() << "Fiber exit"; 70 | }; 71 | 72 | ::std::vector< ::std::thread > threads; 73 | threads.reserve(thread_cnt); 74 | boost::fibers::barrier b(fiber_cnt * thread_cnt); 75 | 76 | for(auto i = 0; i < thread_cnt; ++i) { 77 | threads.emplace_back([&](){ 78 | auto runner = ::psst::asio::fiber::use_shared_work_algorithm( db_service::io_service() ); 79 | for (auto i = 0; i < fiber_cnt; ++i) { 80 | fiber{ fib_fn, ::std::ref(b) }.detach(); 81 | } 82 | runner->run(); 83 | local_log() << "Thread exit"; 84 | }); 85 | } 86 | 87 | for (auto& t : threads) { 88 | t.join(); 89 | } 90 | } 91 | } 92 | 93 | } /* namespace test */ 94 | } /* namespace pg */ 95 | } /* namespace db */ 96 | } /* namespace tip */ 97 | -------------------------------------------------------------------------------- /test/db/results-parse-test.sql: -------------------------------------------------------------------------------- 1 | create temporary table pg_async_test ( 2 | id bigserial primary key, 3 | ctime timestamp default current_timestamp, 4 | ctimetz timestamptz default current_timestamp, 5 | some_text text, 6 | fixed_text char(25), 7 | var_text varchar(25), 8 | float_field float, 9 | json_field json, 10 | bool_field boolean, 11 | money_field money 12 | ); 13 | insert into pg_async_test(some_text, fixed_text, var_text, float_field, json_field, bool_field, money_field) 14 | values 15 | ('text 1', 'fixed text 1', 'var text 1', 1.0, '{}', true, 1.998), 16 | ('text 2', 'fixed text 1', 'var text 1', 2.0, '{}', false, 10.5), 17 | ('text 3', 'fixed text 1', 'var text 1', 3.0, '{}', true, 10005000), 18 | ('text 4', 'fixed text 1', 'var text 1', 4.0, '{}', false, 0.25), 19 | ('text 5', 'fixed text 1', 'var text 1', 5.0, '{}', true, 15), 20 | ('text 6', 'fixed text 1', 'var text 1', 6.0, '{}', false, -19), 21 | ('text 7', 'fixed text 1', 'var text 1', 7.0, '{}', true, 87), 22 | ('text 8', 'fixed text 1', 'var text 1', 8.0, '{}', false, 888), 23 | ('text 9', 'fixed text 1', 'var text 1', 9.0, '{}', true, -0.15), 24 | ('text 10', 'fixed text 1', 'var text 1', 10.0, '{}', false, 908) 25 | returning id, ctime, ctimetz; 26 | select * from pg_async_test; 27 | -------------------------------------------------------------------------------- /test/db/test-environment.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * test-environment.cpp 3 | * 4 | * Created on: Jul 27, 2015 5 | * Author: zmij 6 | */ 7 | 8 | #include "test-environment.hpp" 9 | 10 | namespace tip { 11 | namespace db { 12 | namespace pg { 13 | namespace test { 14 | 15 | std::string environment::test_database = ""; 16 | int environment::deadline = 3; 17 | 18 | int environment::num_requests = 10; 19 | int environment::num_threads = 4; 20 | 21 | int environment::connection_pool = 4; 22 | } /* namespace test */ 23 | } /* namespace pg */ 24 | } /* namespace db */ 25 | } /* namespace tip */ 26 | -------------------------------------------------------------------------------- /test/db/test-environment.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * test-environment.hpp 3 | * 4 | * Created on: Jul 27, 2015 5 | * Author: zmij 6 | */ 7 | 8 | #ifndef LIB_PG_ASYNC_TEST_DB_TEST_ENVIRONMENT_HPP_ 9 | #define LIB_PG_ASYNC_TEST_DB_TEST_ENVIRONMENT_HPP_ 10 | 11 | #include 12 | 13 | namespace tip { 14 | namespace db { 15 | namespace pg { 16 | namespace test { 17 | 18 | class environment { 19 | public: 20 | 21 | static std::string test_database; 22 | static int deadline; 23 | 24 | static int num_requests; 25 | static int num_threads; 26 | 27 | static int connection_pool; 28 | }; 29 | 30 | } /* namespace test */ 31 | } /* namespace pg */ 32 | } /* namespace db */ 33 | } /* namespace tip */ 34 | 35 | #endif /* LIB_PG_ASYNC_TEST_DB_TEST_ENVIRONMENT_HPP_ */ 36 | -------------------------------------------------------------------------------- /test/db/test_main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * test_main.cpp 3 | * 4 | * Created on: Jul 27, 2015 5 | * Author: zmij 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "test-environment.hpp" 13 | 14 | #pragma GCC diagnostic push 15 | #pragma GCC diagnostic ignored "-Wunused-function" 16 | LOCAL_LOGGING_FACILITY(PGTEST, DEBUG); 17 | #pragma GCC diagnostic pop 18 | 19 | namespace { 20 | 21 | #ifdef WITH_TIP_LOG 22 | logger::event_severity log_level = logger::DEBUG; 23 | #endif 24 | 25 | } // namespace 26 | 27 | // Initialize the test suite 28 | int 29 | main( int argc, char* argv[] ) 30 | { 31 | try { 32 | ::testing::InitGoogleTest(&argc, argv); 33 | 34 | using namespace tip::db::pg; 35 | namespace po = boost::program_options; 36 | #ifdef WITH_TIP_LOG 37 | logger::set_proc_name(argv[0]); 38 | logger::set_stream(std::clog); 39 | logger::flush_stream(false); 40 | #endif 41 | 42 | po::options_description desc("Test options"); 43 | 44 | desc.add_options() 45 | ("database,d", po::value(&test::environment::test_database), 46 | "database connection string") 47 | ("pool-size,s", po::value(&test::environment::connection_pool)->default_value(4), 48 | "connection pool size") 49 | ("threads,x", po::value(&test::environment::num_threads)->default_value(10), 50 | "requests threads number") 51 | ("requests,q", po::value(&test::environment::num_requests)->default_value(10), 52 | "number of requests per thread") 53 | #ifdef WITH_TIP_LOG 54 | ("tip-log-level,v", po::value(&log_level)->default_value(logger::INFO), 55 | "log level (TRACE, DEBUG, INFO, WARNING, ERROR)") 56 | #endif 57 | ("run-deadline", po::value(&test::environment::deadline)->default_value(5), 58 | "Maximum time to execute requests") 59 | ("log-colors", "output colored log") 60 | ("help,h", "show options description") 61 | ; 62 | 63 | po::variables_map vm; 64 | po::store(po::parse_command_line(argc, argv, desc), vm); 65 | po::notify(vm); 66 | 67 | if (vm.count("help")) { 68 | std::cout << desc << "\n"; 69 | return 0; 70 | } 71 | 72 | if (test::environment::num_requests < 1) test::environment::num_requests = 1; 73 | if (test::environment::num_threads < 1) test::environment::num_threads = 1; 74 | if (test::environment::connection_pool < 1) test::environment::connection_pool = 1; 75 | 76 | #ifdef WITH_TIP_LOG 77 | logger::min_severity(log_level); 78 | logger::use_colors(vm.count("log-colors")); 79 | #endif 80 | 81 | return RUN_ALL_TESTS(); 82 | } catch (::std::exception const& e) { 83 | std::cerr << "Error running tests " << e.what() << "\n"; 84 | return 1; 85 | } catch (...) { 86 | std::cerr << "Unexpected error running tests\n"; 87 | return 1; 88 | } 89 | } 90 | 91 | -------------------------------------------------------------------------------- /test/db/timestamp_io_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * timestamp_io_test.cpp 3 | * 4 | * Created on: Mar 24, 2016 5 | * Author: zmij 6 | */ 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include "db/config.hpp" 15 | #include "test-environment.hpp" 16 | 17 | using namespace tip::db::pg; 18 | using boost::posix_time::ptime; 19 | using boost::gregorian::date; 20 | using boost::posix_time::time_duration; 21 | 22 | class DateTimeIOTest : public ::testing::TestWithParam< ::std::pair< ::std::string, boost::posix_time::ptime > > { 23 | public: 24 | static ParamType 25 | make_test_data(::std::string const& f, boost::posix_time::ptime const& s) 26 | { 27 | return std::make_pair(f, s); 28 | } 29 | }; 30 | 31 | TEST_P(DateTimeIOTest, Parse) 32 | { 33 | ParamType test_val = GetParam(); 34 | 35 | boost::posix_time::ptime val; 36 | io::protocol_read< TEXT_DATA_FORMAT >(test_val.first.begin(), test_val.first.end(), val); 37 | EXPECT_EQ( test_val.second, val ); 38 | } 39 | 40 | TEST_P(DateTimeIOTest, DBRoundtrip) 41 | { 42 | if (!test::environment::test_database.empty()) { 43 | db_service::initialize(1, 44 | { 45 | { "application_name", "test-pg-async" }, 46 | { "client_encoding", "UTF8" }, 47 | { "TimeZone", "UTC" } 48 | }); 49 | db_service::add_connection(test::environment::test_database); 50 | connection_options opts = connection_options::parse(test::environment::test_database); 51 | 52 | ParamType test_val = GetParam(); 53 | resultset res_txt; 54 | resultset res_bin; 55 | 56 | db_service::begin(opts.alias, 57 | [&](transaction_ptr tran) { 58 | query(tran, 59 | "create temporary table pg_async_ts_test( t timestamp with time zone )")( 60 | [](transaction_ptr, resultset, bool){}, 61 | [](error::db_error const&) {}); 62 | 63 | query(tran, "insert into pg_async_ts_test values($1)", test_val.second)( 64 | [](transaction_ptr, resultset, bool){}, 65 | [](error::db_error const&) {} 66 | ); 67 | query(tran, "select t from pg_async_ts_test")( 68 | [&res_txt](transaction_ptr, resultset r, bool){ 69 | res_txt = r; 70 | }, 71 | [](error::db_error const&) { 72 | }); 73 | query(tran, "select t from pg_async_ts_test limit $1", 1)( 74 | [&res_bin](transaction_ptr, resultset r, bool){ 75 | res_bin = r; 76 | }, 77 | [](error::db_error const&) { 78 | }); 79 | tran->commit_async([](){ 80 | db_service::stop(); 81 | }); 82 | }, 83 | [](error::db_error const&) { 84 | db_service::stop(); 85 | }); 86 | 87 | db_service::run(); 88 | 89 | ASSERT_FALSE(res_txt.empty()); 90 | ASSERT_EQ(1, res_txt.size()); 91 | ASSERT_EQ(1, res_txt.columns_size()); 92 | 93 | boost::posix_time::ptime out_v; 94 | res_txt.front().to(out_v); 95 | EXPECT_EQ(test_val.second, out_v) << "Successfully parsed text protocol"; 96 | 97 | ASSERT_FALSE(res_bin.empty()); 98 | ASSERT_EQ(1, res_bin.size()); 99 | ASSERT_EQ(1, res_bin.columns_size()); 100 | 101 | res_bin.front().to(out_v); 102 | EXPECT_EQ(test_val.second, out_v) << "Successfully parsed binary protocol"; 103 | } 104 | } 105 | 106 | INSTANTIATE_TEST_CASE_P(IOTest, DateTimeIOTest, 107 | ::testing::Values( 108 | DateTimeIOTest::make_test_data("", {}), 109 | DateTimeIOTest::make_test_data( 110 | "2016-03-24 18:00:00.0+03", 111 | { date{ 2016, boost::gregorian::Mar, 24 }, time_duration{ 18, 0, 0 } }), 112 | DateTimeIOTest::make_test_data( 113 | "2000-01-01 00:00:00.0+03", 114 | { date{ 2000, boost::gregorian::Jan, 1 }, time_duration{ 0, 0, 0 } }) 115 | ) 116 | ); 117 | 118 | -------------------------------------------------------------------------------- /test/db/uuid_io_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * uuid_io_test.cpp 3 | * 4 | * Created on: Feb 18, 2017 5 | * Author: sergey.fedorov 6 | */ 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | #include "db/config.hpp" 18 | #include "test-environment.hpp" 19 | 20 | namespace tip { 21 | namespace db { 22 | namespace pg { 23 | namespace test { 24 | 25 | using uuid = ::boost::uuids::uuid; 26 | 27 | namespace { 28 | 29 | ::boost::uuids::string_generator str_gen; 30 | ::boost::uuids::random_generator rand_gen; 31 | 32 | } /* namespace */ 33 | 34 | class UUIDIOTest : public ::testing::TestWithParam< uuid > { 35 | }; 36 | 37 | TEST_P(UUIDIOTest, DBRoundtrip) 38 | { 39 | if (!test::environment::test_database.empty()) { 40 | db_service::add_connection(test::environment::test_database); 41 | connection_options opts = connection_options::parse(test::environment::test_database); 42 | 43 | uuid test_val = GetParam(); 44 | resultset res_txt; 45 | resultset res_bin; 46 | 47 | db_service::begin(opts.alias, 48 | [&](transaction_ptr tran) { 49 | query(tran, 50 | "create temporary table pg_async_ts_test( id uuid)")( 51 | [](transaction_ptr, resultset, bool){}, 52 | [](error::db_error const&) {}); 53 | 54 | query(tran, "insert into pg_async_ts_test values($1)", test_val)( 55 | [](transaction_ptr, resultset, bool){}, 56 | [](error::db_error const&) {} 57 | ); 58 | query(tran, "select id from pg_async_ts_test")( 59 | [&res_txt](transaction_ptr, resultset r, bool){ 60 | res_txt = r; 61 | }, 62 | [](error::db_error const&) { 63 | }); 64 | query(tran, "select id from pg_async_ts_test limit $1", 1)( 65 | [&res_bin](transaction_ptr, resultset r, bool){ 66 | res_bin = r; 67 | }, 68 | [](error::db_error const&) { 69 | }); 70 | tran->commit_async([](){ 71 | db_service::stop(); 72 | }); 73 | }, 74 | [](error::db_error const&) { 75 | db_service::stop(); 76 | }); 77 | 78 | db_service::run(); 79 | 80 | uuid out_v; 81 | ASSERT_FALSE(res_txt.empty()); 82 | ASSERT_EQ(1, res_txt.size()); 83 | ASSERT_EQ(1, res_txt.columns_size()); 84 | 85 | res_txt.front().to(out_v); 86 | EXPECT_EQ(test_val, out_v) << "Successfully parsed text protocol"; 87 | 88 | ASSERT_FALSE(res_bin.empty()); 89 | ASSERT_EQ(1, res_bin.size()); 90 | ASSERT_EQ(1, res_bin.columns_size()); 91 | 92 | res_bin.front().to(out_v); 93 | EXPECT_EQ(test_val, out_v) << "Successfully parsed binary protocol"; 94 | }; 95 | } 96 | 97 | INSTANTIATE_TEST_CASE_P(IOTest, UUIDIOTest, 98 | ::testing::Values( 99 | uuid{{0}}, 100 | str_gen("bd6258b8-45cf-4b65-b327-24d395bbe60b"), 101 | rand_gen() 102 | ) 103 | ); 104 | 105 | } // namespace test 106 | } /* namespace pg */ 107 | } /* namespace db */ 108 | } /* namespace tip */ 109 | --------------------------------------------------------------------------------