diff --git a/benchmark/bm_common.cpp b/benchmark/bm_common.cpp index 41545f6..146e6e8 100644 --- a/benchmark/bm_common.cpp +++ b/benchmark/bm_common.cpp @@ -1,65 +1,89 @@ // this file is a micro-benchmark of the specmicp common libs // It uses the google/benchmark framework #include +#include "utils/range_iterator.hpp" #include "utils/timer.hpp" #include "utils/moving_average.hpp" using namespace specmicp; +// Range iterator +// ============== + +static void BMSimpleLoop(benchmark::State& state) { + while (state.KeepRunning()) { + for (int i=0; i<100; ++i) { + benchmark::DoNotOptimize(i); + } + } +} +BENCHMARK(BMSimpleLoop); + + +static void BMRangeIterator(benchmark::State& state) { + while (state.KeepRunning()) { + for (auto it: RangeIterator(100)) { + benchmark::DoNotOptimize(it); + } + } +} +BENCHMARK(BMRangeIterator); + + // Timer // ===== static void BMTimer(benchmark::State& state) { while (state.KeepRunning()) { Timer timer; timer.stop(); } } BENCHMARK(BMTimer); static void BMTimer_restart(benchmark::State& state) { while (state.KeepRunning()) { Timer timer; timer.start(); timer.stop(); } } BENCHMARK(BMTimer_restart); static void BMTimer_elapsedtime(benchmark::State& state) { while (state.KeepRunning()) { Timer timer; timer.stop(); scalar_t x; benchmark::DoNotOptimize(x = timer.elapsed_time()); } } BENCHMARK(BMTimer_elapsedtime); // Moving Average // ============== static void BMMovingAverage_init(benchmark::State& state) { while (state.KeepRunning()) { utils::ExponentialMovingAverage average(0.2, 1.0); benchmark::DoNotOptimize(average); } } BENCHMARK(BMMovingAverage_init); static void BMMovingAverage_addpoint(benchmark::State& state) { while (state.KeepRunning()) { utils::ExponentialMovingAverage average(0.2, 1.0); scalar_t x; benchmark::DoNotOptimize(x = average.add_point(2.0)); } } BENCHMARK(BMMovingAverage_addpoint); BENCHMARK_MAIN(); diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt index 439728f..886b9b4 100644 --- a/src/utils/CMakeLists.txt +++ b/src/utils/CMakeLists.txt @@ -1,149 +1,154 @@ # headers only module # ------------------- add_custom_target(utils_inc SOURCES #log.hpp # sparse solvers # -------------- sparse_solvers/sparse_solver_base.hpp sparse_solvers/sparse_solver.hpp sparse_solvers/sparse_solver_structs.hpp sparse_solvers/sparse_qr.hpp sparse_solvers/sparse_lu.hpp sparse_solvers/sparse_bicgstab.hpp sparse_solvers/sparse_gmres.hpp + range_iterator.hpp + range_iterator.inl + options_handler.hpp perfs_handler.hpp compat.hpp value_checker.hpp plugins/plugin_api_version.h plugins/plugin_interface.h plugins/plugin_types.hpp ) set(SPECMICP_COMMON_LIBRARY_FILES log.cpp dateandtime.cpp timer.cpp moving_average.cpp plugins/dynamic_library.cpp plugins/plugin_base.cpp plugins/module_base.cpp plugins/plugin_manager.cpp ../physics/laws.cpp ../physics/units.cpp ../physics/io/units.cpp io/format.cpp io/csv_formatter.cpp io/yaml.cpp ) # hdf5 # ----- if (HDF5_FOUND) list(APPEND SPECMICP_COMMON_LIBRARY_FILES io/specmicp_hdf5.cpp ) include_directories(${HDF5_INCLUDE_DIRS}) set_source_files_properties(io/specmicp_hdf5.cpp PROPERTIES COMPILE_DEFINITIONS HDF5_DEFINITIONS) add_custom_target(utils_io_hdf5_inc SOURCES io/hdf5_eigen.hpp io/hdf5_eigen.inl ) endif() set_pgo_flag(${SPECMICP_COMMON_LIBRARY_FILES}) add_library(objspecmicp_common OBJECT ${SPECMICP_COMMON_LIBRARY_FILES}) set_property(TARGET objspecmicp_common PROPERTY POSITION_INDEPENDENT_CODE 1) add_library(specmicp_common SHARED $) if (UNIX) set(SPECMICP_COMMON_LINK dl) else() message(FATAL_ERROR "Plugin system only for POSIX at this time !") endif() if (HDF5_FOUND) set(SPECMICP_COMMON_LINK "${HDF5_LIBRARIES};${SPECMICP_COMMON_LINK}") endif() target_link_libraries(specmicp_common ${SPECMICP_COMMON_LINK}) install(TARGETS specmicp_common LIBRARY DESTINATION ${LIBRARY_INSTALL_DIR} ) set(UTILS_INCLUDE_LIST + range_iterator.hpp + range_iterator.inl log.hpp options_handler.hpp perfs_handler.hpp moving_average.hpp timer.hpp dateandtime.hpp compat.hpp ) set(UTILS_SPARSE_INCLUDE_LIST # sparse solvers # -------------- sparse_solvers/sparse_solver.hpp sparse_solvers/sparse_solver_base.hpp sparse_solvers/sparse_solver_structs.hpp sparse_solvers/sparse_qr.hpp sparse_solvers/sparse_lu.hpp sparse_solvers/sparse_bicgstab.hpp sparse_solvers/sparse_gmres.hpp ) set(UTILS_IO_INCLUDE_LIST io/format.hpp io/csv_formatter.hpp io/yaml.hpp ) install(FILES ${UTILS_INCLUDE_LIST} DESTINATION ${INCLUDE_INSTALL_DIR}/utils ) install(FILES ${UTILS_SPARSE_INCLUDE_LIST} DESTINATION ${INCLUDE_INSTALL_DIR}/utils/sparse_solvers ) install(FILES ${UTILS_IO_INCLUDE_LIST} DESTINATION ${INCLUDE_INSTALL_DIR}/utils/io ) # static libraries # ---------------- if(SPECMICP_BUILD_STATIC) add_library(specmicp_common_static STATIC $ ) install(TARGETS specmicp_common_static ARCHIVE DESTINATION ${STATIC_LIBRARY_INSTALL_DIR} ) else() add_library(specmicp_common_static EXCLUDE_FROM_ALL STATIC $ ) endif() target_link_libraries(specmicp_common_static ${SPECMICP_COMMON_LINK}) set_target_properties(specmicp_common_static PROPERTIES OUTPUT_NAME specmicp_common) diff --git a/src/utils/range_iterator.hpp b/src/utils/range_iterator.hpp new file mode 100644 index 0000000..9c0ec55 --- /dev/null +++ b/src/utils/range_iterator.hpp @@ -0,0 +1,109 @@ +/*------------------------------------------------------------------------------ + +Copyright (c)2015 F. Georget , Princeton University +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------------------------------------------------------------------------------*/ + +#ifndef SPECMICP_UTILS_RANGEITERATOR_HPP +#define SPECMICP_UTILS_RANGEITERATOR_HPP + +// /!\ this file is included in types.hpp + +/*! +\file range_iterator.hpp +\brief Iterator over a range + */ + + +namespace specmicp { + +//! \namespace specmicp::interator_impl +//! \brief Implementation of the iterator +//! \internal +namespace iterator_impl { + +template +class IntegralIterator; + +template +class ConstIntegralIterator; + +} //end namespace iterator_impl + +//! \brief An iterator over a range +//! +//! \tparam T an integral type +template +class RangeIterator +{ +public: + using iterator = iterator_impl::IntegralIterator; + using const_iterator = const iterator_impl::ConstIntegralIterator; + + //! \brief Construct a range iterator + RangeIterator(T start, T end): + m_start(start), + m_end(end) + {} + + //! \brief Construct a range iterator + RangeIterator(T end): + m_start(0), + m_end(end) + {} + + //! \brief Construct a range iterator from two iterators + RangeIterator(const iterator& start, const iterator& end): + m_start(*start), + m_end(*end) + {} + + //! \brief Construct a range iterator from an iterator + RangeIterator(const iterator& end): + m_start(0), + m_end(*end) + {} + + iterator begin() const; + iterator end() const; + + const_iterator cbegin() const; + const_iterator cend() const; + +private: + T m_start; + T m_end; +}; + +} // end namespace specmicp + +// implementation +#include "range_iterator.inl" + +#endif // SPECMICP_UTILS_RANGEITERATOR_HPP diff --git a/src/utils/range_iterator.inl b/src/utils/range_iterator.inl new file mode 100644 index 0000000..6be07d8 --- /dev/null +++ b/src/utils/range_iterator.inl @@ -0,0 +1,147 @@ +/*------------------------------------------------------------------------------ + +Copyright (c)2015 F. Georget , Princeton University +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------------------------------------------------------------------------------*/ + +#include "range_iterator.hpp" // syntaxic coloration only... + +namespace specmicp { + +namespace iterator_impl { + +//! \brief Iterator over a range of integers +//! +//! \internal +template +class IntegralBaseIterator +{ +public: + using value_type = T; + using reference = T&; + + explicit IntegralBaseIterator(T value): + m_value(value) + {} + + bool operator< (const IntegralBaseIterator& other) { + return (m_value < other.m_value); + } + + bool operator<= (const IntegralBaseIterator& other) { + return (m_value <= other.m_value); + } + + bool operator> (const IntegralBaseIterator& other) { + return (m_value > other.m_value); + } + + bool operator>= (const IntegralBaseIterator& other) { + return (m_value >= other.m_value); + } + + bool operator== (const IntegralBaseIterator& other) { + return (m_value == other.m_value); + } + + bool operator!= (const IntegralBaseIterator& other) { + return (m_value != other.m_value); + } + + + value_type operator++ (int) { + T tmp = m_value; + ++m_value; + return tmp; + } + +protected: + value_type m_value; +}; + +template +class IntegralIterator: public IntegralBaseIterator +{ +public: + explicit IntegralIterator(T value): + IntegralBaseIterator(value) + {} + + T& operator* () { + return IntegralBaseIterator::m_value; + } + + IntegralIterator& operator++ () { + ++(IntegralBaseIterator::m_value); + return *this; + } +}; + +template +class ConstIntegralIterator: public IntegralBaseIterator +{ +public: + explicit ConstIntegralIterator(T value): + IntegralBaseIterator(value) + {} + + T operator* () const { + return IntegralBaseIterator::m_value; + } + + ConstIntegralIterator& operator++ () { + ++(IntegralBaseIterator::m_value); + return *this; + } +}; + +} //end namespace iterator_impl + +template +typename RangeIterator::iterator RangeIterator::begin() const { + return RangeIterator::iterator(m_start); +} + +template +typename RangeIterator::iterator RangeIterator::end() const { + return RangeIterator::iterator(m_end); +} + +template +typename RangeIterator::const_iterator RangeIterator::cbegin() const { + return RangeIterator::iterator(m_start); +} + +template +typename RangeIterator::const_iterator RangeIterator::cend() const { + return RangeIterator::iterator(m_end); +} + + +} // end namespace specmicp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index fc6e008..bf18fde 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,102 +1,103 @@ ################## Tests ######################################## include(CatchTest) set(PROJECT_TEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}) include_directories(${PROJECT_TEST_DIR}) add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND}) # make check is also valid # Catch test #=========== #common set( COMMON_TEST_DIR common ) # mock test library add_library(test_to_load SHARED EXCLUDE_FROM_ALL ${COMMON_TEST_DIR}/test_to_load.cpp ) set_target_properties(test_to_load PROPERTIES PREFIX "") add_custom_target(test_pasic_plugin_incl SOURCES ${COMMON_TEST_DIR}/test_basic_plugin_mockobject.hpp ) add_library(test_basic_plugin SHARED EXCLUDE_FROM_ALL ${COMMON_TEST_DIR}/test_basic_plugin.cpp ) set_target_properties(test_basic_plugin PROPERTIES PREFIX "") link_libraries(test_basic_plugin specmicp_common_static ${YAML_LIBRARIES}) set(SPECMICP_COMMON_TEST_FILES ${COMMON_TEST_DIR}/test_common.cpp + ${COMMON_TEST_DIR}/range_iterator.cpp ${COMMON_TEST_DIR}/units.cpp ${COMMON_TEST_DIR}/laws.cpp ${COMMON_TEST_DIR}/misc.cpp ${COMMON_TEST_DIR}/value_checker.cpp ${COMMON_TEST_DIR}/sparse_solvers.cpp ${COMMON_TEST_DIR}/dynamic_loader.cpp ${COMMON_TEST_DIR}/plugin_manager.cpp ) if (HDF5_FOUND) list(APPEND SPECMICP_COMMON_TEST_FILES ${COMMON_TEST_DIR}/hdf5_eigen.cpp ) include_directories(${HDF5_INCLUDE_DIRS}) set_source_files_properties(${COMMON_TEST_DIR}/hdf5_eigen.cpp PROPERTIES COMPILE_DEFINITIONS HDF5_DEFINITIONS) endif() add_catch_test(NAME common SOURCES ${SPECMICP_COMMON_TEST_FILES} LINK_LIBRARIES specmicp_common_static DEPENDS test_to_load test_basic_plugin ) # MiCPSolver # ---------- set(MICPSOLVER_TEST_DIR micpsolver) add_catch_test(NAME micpsolver SOURCES ${MICPSOLVER_TEST_DIR}/test_micpsolver.cpp ${MICPSOLVER_TEST_DIR}/condition_number.cpp ${MICPSOLVER_TEST_DIR}/ncp_functions.cpp ${MICPSOLVER_TEST_DIR}/micpsolver.cpp LINK_LIBRARIES specmicp_common_static ) # ODEInt # ---------- set(ODEINT_TEST_DIR odeint) add_catch_test(NAME odeint SOURCES ${ODEINT_TEST_DIR}/test_odeint.cpp ${ODEINT_TEST_DIR}/butchertableau.cpp ${ODEINT_TEST_DIR}/embeddedrungekutta.cpp ) # Database # -------- add_subdirectory(database) # Specmicp # -------- add_subdirectory( specmicp ) # Reactmicp # --------- add_subdirectory( reactmicp ) diff --git a/tests/common/range_iterator.cpp b/tests/common/range_iterator.cpp new file mode 100644 index 0000000..63d0403 --- /dev/null +++ b/tests/common/range_iterator.cpp @@ -0,0 +1,22 @@ +#include "catch.hpp" + +#include "utils/range_iterator.hpp" + +TEST_CASE("RangeIterator", "[iterator],[types]") { + SECTION("Simple test") { + int current = 0; + auto range = specmicp::RangeIterator(0, 6); + for (auto it=range.begin(); it!=range.end(); ++it) { + CHECK(*it == current); + ++current; + } + CHECK(current == 6); + + current = 0; + for (auto val: specmicp::RangeIterator(0, 6)) { + CHECK(val == current); + ++current; + } + CHECK(current == 6); + } +}