From 0b316c6cfdd119f10635aa5a54c82f5bfc2de9c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Can=20B=C3=B6l=C3=BCk?= Date: Mon, 24 Aug 2020 04:00:44 +0200 Subject: [PATCH] Implemented basic std::fs support, reworked time/iterator helpers. --- VTIL-Architecture/routine/serialization.hpp | 5 +- VTIL-Common/VTIL-Common.vcxproj | 4 +- VTIL-Common/VTIL-Common.vcxproj.filters | 12 +- VTIL-Common/includes/vtil/io | 1 + VTIL-Common/includes/vtil/utility | 13 +- VTIL-Common/io/fileio.hpp | 69 +++++++++ VTIL-Common/io/formatting.hpp | 37 ++--- VTIL-Common/io/logger.hpp | 13 +- .../util/{profiler.hpp => literals.hpp} | 40 +---- VTIL-Common/util/random.hpp | 4 +- VTIL-Common/util/range.hpp | 10 +- VTIL-Common/util/reverse_iterator.hpp | 71 +++++---- VTIL-Common/util/time.hpp | 144 ++++++++++++++++++ VTIL-Common/util/type_helpers.hpp | 53 ++++--- VTIL-Common/util/zip.hpp | 68 ++++----- VTIL-Compiler/common/interface.hpp | 15 +- 16 files changed, 372 insertions(+), 187 deletions(-) create mode 100644 VTIL-Common/io/fileio.hpp rename VTIL-Common/util/{profiler.hpp => literals.hpp} (61%) create mode 100644 VTIL-Common/util/time.hpp diff --git a/VTIL-Architecture/routine/serialization.hpp b/VTIL-Architecture/routine/serialization.hpp index 2777a4e..0c7edf5 100644 --- a/VTIL-Architecture/routine/serialization.hpp +++ b/VTIL-Architecture/routine/serialization.hpp @@ -31,6 +31,7 @@ #include #include #include +#include #include "routine.hpp" #include "basic_block.hpp" #include "instruction.hpp" @@ -218,12 +219,12 @@ namespace vtil // Simple wrappers for serialize / deserialize routine. // - static void save_routine( const routine* rtn, const std::string& path ) + static void save_routine( const routine* rtn, const std::filesystem::path& path ) { std::ofstream fs( path, std::ios::binary ); serialize( fs, rtn ); } - static routine* load_routine( const std::string& path ) + static routine* load_routine( const std::filesystem::path& path ) { routine* rtn; std::ifstream fs( path, std::ios::binary ); diff --git a/VTIL-Common/VTIL-Common.vcxproj b/VTIL-Common/VTIL-Common.vcxproj index a20f49e..e7820b0 100644 --- a/VTIL-Common/VTIL-Common.vcxproj +++ b/VTIL-Common/VTIL-Common.vcxproj @@ -136,6 +136,7 @@ + @@ -147,10 +148,11 @@ + + - diff --git a/VTIL-Common/VTIL-Common.vcxproj.filters b/VTIL-Common/VTIL-Common.vcxproj.filters index b1988af..c8fe832 100644 --- a/VTIL-Common/VTIL-Common.vcxproj.filters +++ b/VTIL-Common/VTIL-Common.vcxproj.filters @@ -145,9 +145,6 @@ Utility - - Utility - Utility @@ -181,6 +178,15 @@ Utility + + I/O + + + Utility + + + Utility + diff --git a/VTIL-Common/includes/vtil/io b/VTIL-Common/includes/vtil/io index a767949..38d9756 100644 --- a/VTIL-Common/includes/vtil/io +++ b/VTIL-Common/includes/vtil/io @@ -3,3 +3,4 @@ #include "../../io/formatting.hpp" #include "../../io/logger.hpp" #include "../../io/enum_name.hpp" +#include "../../io/fileio.hpp" diff --git a/VTIL-Common/includes/vtil/utility b/VTIL-Common/includes/vtil/utility index dd25330..29f6f1c 100644 --- a/VTIL-Common/includes/vtil/utility +++ b/VTIL-Common/includes/vtil/utility @@ -18,7 +18,7 @@ #include "../../util/multivariate.hpp" #include "../../util/static_warning.hpp" #include "../../util/random.hpp" -#include "../../util/profiler.hpp" +#include "../../util/time.hpp" #include "../../util/bitmap.hpp" #include "../../util/type_helpers.hpp" #include "../../util/enumerator.hpp" @@ -27,13 +27,4 @@ #include "../../util/detached_queue.hpp" #include "../../util/relaxed_atomics.hpp" #include "../../util/function_view.hpp" - -// VTIL namespace should be able to use literals by default without having to include it. -// -#include -#include -namespace vtil -{ - using namespace std::literals::string_literals; - using namespace std::literals::chrono_literals; -}; +#include "../../util/literals.hpp" \ No newline at end of file diff --git a/VTIL-Common/io/fileio.hpp b/VTIL-Common/io/fileio.hpp new file mode 100644 index 0000000..0a7a09d --- /dev/null +++ b/VTIL-Common/io/fileio.hpp @@ -0,0 +1,69 @@ +// Copyright (c) 2020 Can Boluk and contributors of the VTIL Project +// 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 VTIL Project 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 OWNER 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. +// +#pragma once +#include +#include +#include +#include +#include +#include "../io/logger.hpp" + +namespace vtil::file +{ + // Declare a simple interface to read/write files for convenience. + // + static std::vector read_raw( const std::filesystem::path& path ) + { + // Try to open file as binary for read. + // + std::ifstream file( path, std::ios::binary ); + if ( !file.good() ) logger::error( "File %s cannot be opened.", path ); + + // Read the whole file and return. + // + return std::vector( std::istreambuf_iterator( file ), {} ); + } + + static void write_raw( const std::filesystem::path& path, void* data, size_t size ) + { + // Try to open file as binary for write. + // + std::ofstream file( path, std::ios::binary ); + if ( !file.good() ) logger::error( "File cannot be opened for write." ); + + // Write the data and return. + // + file.write( ( char* ) data, size ); + } + + template requires ( is_linear_iterable_v && std::is_trivial_v> ) + static void write_raw( const std::filesystem::path& path, T&& container ) + { + write_raw( path, &*std::begin( container ), std::size( container ) * sizeof( iterated_type_t ) ); + } +}; \ No newline at end of file diff --git a/VTIL-Common/io/formatting.hpp b/VTIL-Common/io/formatting.hpp index e800682..e598658 100644 --- a/VTIL-Common/io/formatting.hpp +++ b/VTIL-Common/io/formatting.hpp @@ -33,8 +33,10 @@ #include #include #include +#include #include "../util/lt_typeid.hpp" #include "../util/type_helpers.hpp" +#include "../util/time.hpp" #include "enum_name.hpp" #ifdef __GNUG__ @@ -163,6 +165,10 @@ namespace vtil::format { return enum_name::resolve( x ); } + else if constexpr ( Duration ) + { + return time::to_string( x ); + } else if constexpr ( StdStringConvertible ) { return std::to_string( x ); @@ -176,6 +182,14 @@ namespace vtil::format { return std::string{ x }; } + else if constexpr ( std::is_same_v ) + { + return x.path().string(); + } + else if constexpr ( std::is_same_v ) + { + return x.string(); + } else if constexpr ( std::is_same_v ) { return std::string{ x.begin(), x.end() }; @@ -184,29 +198,6 @@ namespace vtil::format { return std::string{ x, x + wcslen( x ) }; } - else if constexpr ( is_specialization_v ) - { - static constexpr auto flt2str = [ ] ( float f ) -> std::string - { - char buffer[ 32 ]; - snprintf( buffer, 32, "%.2f", f ); - return buffer; - }; - - static constexpr std::tuple durations[] = - { - { std::chrono::duration_cast( std::chrono::hours{ 1 } ), "hrs", false }, - { std::chrono::duration_cast( std::chrono::minutes{ 1 } ), "min", false }, - { std::chrono::duration_cast( std::chrono::seconds{ 1 } ), "sec", false }, - { std::chrono::duration_cast( std::chrono::milliseconds{ 1 } ), "ms", false }, - { std::chrono::duration_cast( std::chrono::nanoseconds{ 1 } ), "ns", true }, - }; - - for ( auto& [dur, name, last] : durations ) - if ( last || x > dur ) - return flt2str( x.count() / float( dur.count() ) ) + name; - unreachable(); - } else if constexpr ( std::is_pointer_v ) { char buffer[ 17 ]; diff --git a/VTIL-Common/io/logger.hpp b/VTIL-Common/io/logger.hpp index c21f362..2a4326c 100644 --- a/VTIL-Common/io/logger.hpp +++ b/VTIL-Common/io/logger.hpp @@ -36,6 +36,7 @@ #include #include "formatting.hpp" #include "../util/intrinsics.hpp" +#include "../util/literals.hpp" // [Configuration] // Determine which file stream we should use for logging/errors and whether to @@ -106,12 +107,12 @@ namespace vtil::logger void lock() { mtx.lock(); } void unlock() { mtx.unlock(); } bool try_lock() { return mtx.try_lock(); } - bool try_lock( uint64_t milliseconds ) + bool try_lock( timeunit_t max_wait ) { bool locked = false; - auto t0 = std::chrono::steady_clock::now(); + auto t0 = time::now(); while ( !( locked = try_lock() ) ) - if ( ( std::chrono::steady_clock::now() - t0 ) > std::chrono::milliseconds( milliseconds ) ) + if ( ( time::now() - t0 ) > max_wait ) break; return locked; } @@ -253,7 +254,7 @@ namespace vtil::logger // Try acquiring the lock. // - bool locked = logger_state.try_lock( 100 ); + bool locked = logger_state.try_lock( 100ms ); // Print the warning. // @@ -288,7 +289,7 @@ namespace vtil::logger // Try acquiring the lock. // - bool locked = logger_state.try_lock( 100 ); + bool locked = logger_state.try_lock( 100ms ); // Print the error message. // @@ -317,7 +318,7 @@ namespace vtil::logger std::string message = format::as_string( e ); set_color( CON_RED ); fprintf( VTIL_LOGGER_ERR_DST, "\n[*] Error: %s\n", message.c_str() ); - std::this_thread::sleep_for( std::chrono::milliseconds( 500 ) ); + sleep_for( 1000ms ); } catch ( ... ) {} diff --git a/VTIL-Common/util/profiler.hpp b/VTIL-Common/util/literals.hpp similarity index 61% rename from VTIL-Common/util/profiler.hpp rename to VTIL-Common/util/literals.hpp index 65baec1..092fec1 100644 --- a/VTIL-Common/util/profiler.hpp +++ b/VTIL-Common/util/literals.hpp @@ -27,44 +27,12 @@ // #pragma once #include -#include +#include namespace vtil { - // Times the callable given and returns pair [result, duration] if it has - // a return value or just [duration]. + // VTIL namespace should be able to use literals by default without having to include it. // - template - static auto profile( T&& f, Tx&&... args ) - { - using result_t = decltype( std::declval()( std::forward( args )... ) ); - - if constexpr ( std::is_same_v ) - { - auto t0 = std::chrono::steady_clock::now(); - f( std::forward( args )... ); - auto t1 = std::chrono::steady_clock::now(); - return t1 - t0; - } - else - { - - auto t0 = std::chrono::steady_clock::now(); - result_t res = f(); - auto t1 = std::chrono::steady_clock::now(); - return std::make_pair( res, t1 - t0 ); - } - } - - // Same as ::profile but ignores the return value and runs N times. - // - template - static auto profile_n( T&& f, Tx&&... args ) - { - auto t0 = std::chrono::steady_clock::now(); - for ( size_t i = 0; i != N; i++ ) - f( args... ); // Not forwarded since we can't move N times. - auto t1 = std::chrono::steady_clock::now(); - return t1 - t0; - } + using namespace std::literals::string_literals; + using namespace std::literals::chrono_literals; }; \ No newline at end of file diff --git a/VTIL-Common/util/random.hpp b/VTIL-Common/util/random.hpp index ee0256c..9fa6d27 100644 --- a/VTIL-Common/util/random.hpp +++ b/VTIL-Common/util/random.hpp @@ -107,7 +107,7 @@ namespace vtil template static decltype( auto ) pick_randomi( T&& source ) { - auto size = dynamic_size( source ); + auto size = std::size( source ); fassert( size != 0 ); return dynamic_get( source, make_random( 0, size - 1 ) ); } @@ -119,7 +119,7 @@ namespace vtil template static constexpr decltype( auto ) pick_crandomi( T& source ) { - auto size = dynamic_size( source ); + auto size = std::size( source ); fassert( size != 0 ); return dynamic_get( source, make_crandom( offset ) % size ); } diff --git a/VTIL-Common/util/range.hpp b/VTIL-Common/util/range.hpp index 46353a0..0dd5d5c 100644 --- a/VTIL-Common/util/range.hpp +++ b/VTIL-Common/util/range.hpp @@ -27,7 +27,7 @@ // #pragma once #include -#include +#include namespace vtil { @@ -39,11 +39,15 @@ namespace vtil constexpr iterator_type begin() const { return ibegin; } constexpr iterator_type end() const { return iend; } + constexpr size_t size() const { return ( size_t ) std::distance( begin(), end() ); } }; template - static constexpr auto make_range( iterator_type begin, iterator_type end ) + static constexpr auto make_range( iterator_type&& begin, iterator_type&& end ) { - return range_t{ std::move( begin ), std::move( end ) }; + return range_t{ + std::forward( begin ), + std::forward( end ) + }; } }; \ No newline at end of file diff --git a/VTIL-Common/util/reverse_iterator.hpp b/VTIL-Common/util/reverse_iterator.hpp index edefb6d..4500a72 100644 --- a/VTIL-Common/util/reverse_iterator.hpp +++ b/VTIL-Common/util/reverse_iterator.hpp @@ -28,7 +28,7 @@ #pragma once #include #include -#include "../io/asserts.hpp" +#include "type_helpers.hpp" namespace vtil { @@ -45,38 +45,34 @@ namespace vtil // Constructed by the original iterator type and the limit. // - reversed_iterator( const iterator& i, const iterator& limit ) + constexpr reversed_iterator( const iterator& i, const iterator& limit ) : iterator( i ), limit( limit ) {} - reversed_iterator( iterator&& i, iterator&& limit ) + constexpr reversed_iterator( iterator&& i, iterator&& limit ) : iterator( std::move( i ) ), limit( std::move( limit ) ) {} // Default copy/move. // - reversed_iterator( reversed_iterator&& ) = default; - reversed_iterator( const reversed_iterator& ) = default; - reversed_iterator& operator=( reversed_iterator&& ) = default; - reversed_iterator& operator=( const reversed_iterator& ) = default; + constexpr reversed_iterator( reversed_iterator&& ) = default; + constexpr reversed_iterator( const reversed_iterator& ) = default; + constexpr reversed_iterator& operator=( reversed_iterator&& ) = default; + constexpr reversed_iterator& operator=( const reversed_iterator& ) = default; // Reverts back to a normal iterator. // - iterator& revert() { return *this; } - const iterator& revert() const { return *this; } + constexpr iterator& revert() { return *this; } + constexpr const iterator& revert() const { return *this; } // Reverse inc/dec. // - reversed_iterator& operator--() + constexpr reversed_iterator& operator--() { - fassert( !at_limit ); - // Invoke inc, make sure it returns a reference and return self. // auto& _ = iterator::operator++(); return *this; } - reversed_iterator& operator++() + constexpr reversed_iterator& operator++() { - fassert( !at_limit ); - // If equal to the limit, set limit and return as is. // if ( operator==( limit ) ) @@ -90,44 +86,55 @@ namespace vtil auto& _ = iterator::operator--(); return *this; } + constexpr reversed_iterator operator++( int ) { auto s = *this; operator--(); return s; } + constexpr reversed_iterator operator--( int ) { auto s = *this; operator++(); return s; } // Implement (not-)equals operator with the special end tag. // - bool operator==( reversed_iterator_end_tag ) const { return at_limit; } - bool operator!=( reversed_iterator_end_tag ) const { return !at_limit; } + constexpr bool operator==( reversed_iterator_end_tag ) const { return at_limit; } + constexpr bool operator!=( reversed_iterator_end_tag ) const { return !at_limit; } // Inherit rest from operator base. // using iterator::operator==; using iterator::operator!=; - using iterator::operator->; - using iterator::operator*; }; // Returns a tuple that behaves equivalent to .rbegin and .rend. // - template - static auto reverse_iterators( T& cont ) + template + static constexpr auto reverse_iterators( T&& cont ) { using iterator_type = decltype( cont.begin() ); - return std::make_tuple( - reversed_iterator{ std::prev( cont.end() ), cont.begin() }, + return std::pair { + reversed_iterator{ std::prev( std::end( cont ) ), std::begin( cont ) }, reversed_iterator_end_tag{} - ); + }; } // Reverses entire container iteration. // - template - struct reversed_container_proxy + namespace impl { - T& proxy; - decltype( auto ) begin() { return proxy.rbegin(); } - decltype( auto ) end() { return proxy.rend(); } + template + struct reversed_container_proxy + { + T container; + decltype( auto ) begin() { return reverse_iterators( container ).first; } + decltype( auto ) end() { return reverse_iterators( container ).second; } + }; + + template + struct reversed_container_proxy + { + T container; + decltype( auto ) begin() { return std::rbegin( container ); } + decltype( auto ) end() { return std::rend( container ); } + }; }; - template - static constexpr auto backwards( T& cont ) + template + static constexpr auto backwards( T&& container ) { - return reversed_container_proxy{ cont }; + return impl::reversed_container_proxy{ std::forward( container ) }; } }; \ No newline at end of file diff --git a/VTIL-Common/util/time.hpp b/VTIL-Common/util/time.hpp new file mode 100644 index 0000000..9d6125a --- /dev/null +++ b/VTIL-Common/util/time.hpp @@ -0,0 +1,144 @@ +// Copyright (c) 2020 Can Boluk and contributors of the VTIL Project +// 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 VTIL Project 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 OWNER 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. +// +#pragma once +#include +#include +#include +#include +#include +#include "literals.hpp" +#include "type_helpers.hpp" +#include "zip.hpp" +#include "reverse_iterator.hpp" + +// No-bloat chrono interface with some helpers and a profiler. +// +namespace vtil +{ + namespace time + { + // Declare basic units. + // + using hours = std::chrono::hours; + using minutes = std::chrono::minutes; + using seconds = std::chrono::seconds; + using milliseconds = std::chrono::milliseconds; + using nanoseconds = std::chrono::nanoseconds; + using unit_t = nanoseconds; + + using basic_units = std::tuple< nanoseconds, milliseconds, seconds, minutes, hours >; + static constexpr std::array basic_unit_names = { "nanoseconds", "milliseconds", "seconds", "minutes", "hours" }; + static constexpr std::array basic_unit_abbreviations = { "ns", "ms", "sec", "min", "hrs" }; + static constexpr std::array basic_unit_durations = make_constant_series>( [ ] ( auto x ) + { + return std::chrono::duration_cast( std::tuple_element_t( 1 ) ); + } ); + + // Declare prefered clock and units. + // + using base_clock = std::chrono::steady_clock; + using stamp_t = base_clock::time_point; + + // Wrap around base clock. + // + static stamp_t now() { return base_clock::now(); } + + // Declare conversion to string. + // + template + static std::string to_string( T duration ) + { + // Convert to unit time. + // + unit_t t = std::chrono::duration_cast( duration ); + + // Iterate duration list in descending order. + // + for ( auto [duration, abbrv] : backwards( zip( time::basic_unit_durations, time::basic_unit_abbreviations ) ) ) + { + // If time is larger than the duration given or if we're at the last duration: + // + if ( t > duration || duration == *std::begin( time::basic_unit_durations ) ) + { + // Convert float to string. + // + char buffer[ 32 ]; + snprintf( buffer, 32, "%.2lf%s", t.count() / double( duration.count() ), abbrv ); + return buffer; + } + } + unreachable(); + } + }; + using timestamp_t = time::stamp_t; + using timeunit_t = time::unit_t; + + // Wrappers around std::this_thread::sleep_*. + // + template + static void sleep_for( T&& d ) { std::this_thread::sleep_for( std::forward( d ) ); } + template + static void sleep_until( T&& d ) { std::this_thread::sleep_until( std::forward( d ) ); } + + // Times the callable given and returns pair [result, duration] if it has + // a return value or just [duration]. + // + template requires InvocableWith + static auto profile( T&& f, Tx&&... args ) + { + using result_t = decltype( std::declval()( std::forward( args )... ) ); + + if constexpr ( std::is_same_v ) + { + timestamp_t t0 = time::now(); + f( std::forward( args )... ); + timestamp_t t1 = time::now(); + return t1 - t0; + } + else + { + + timestamp_t t0 = time::now(); + result_t res = f(); + timestamp_t t1 = time::now(); + return std::make_pair( res, t1 - t0 ); + } + } + + // Same as ::profile but ignores the return value and runs N times. + // + template requires InvocableWith + static timeunit_t profile_n( T&& f, Tx&&... args ) + { + auto t0 = time::now(); + for ( size_t i = 0; i != N; i++ ) + f( args... ); // Not forwarded since we can't move N times. + auto t1 = time::now(); + return t1 - t0; + } +}; \ No newline at end of file diff --git a/VTIL-Common/util/type_helpers.hpp b/VTIL-Common/util/type_helpers.hpp index bd077ac..c4c8c35 100644 --- a/VTIL-Common/util/type_helpers.hpp +++ b/VTIL-Common/util/type_helpers.hpp @@ -34,6 +34,9 @@ #include #include #include +#include +#include +#include #include "intrinsics.hpp" namespace vtil @@ -93,6 +96,17 @@ namespace vtil template typename Tmp, typename T> static constexpr bool is_specialization_v = impl::is_specialization_v>; + // Check whether data is stored linearly in the iterable. + // + template + static constexpr bool is_linear_iterable_v = + ( + is_specialization_v || + is_specialization_v || + is_specialization_v || + std::is_array_v + ); + // Checks if the given lambda can be evaluated in compile time. // template = 0> @@ -135,9 +149,13 @@ namespace vtil template concept Invocable = requires( T&& x, Args&&... args ) { Convertible( args )... ) ), Ret>; }; + template + concept InvocableWith = requires( T&& x, Args&&... args ) { x( std::forward( args )... ); }; template concept Iterable = requires( T v ) { std::begin( v ); std::end( v ); }; + template + concept ReverseIterable = requires( T v ) { std::rbegin( v ); std::rend( v ); }; template concept TypedIterable = Iterable && requires( T v ) { Convertible; }; @@ -153,6 +171,16 @@ namespace vtil template concept Atomic = is_specialization_v; + template + concept Duration = is_specialization_v; + template + concept Timestamp = is_specialization_v; + + // Type of the iterated value. + // + template + using iterated_type_t = std::remove_cvref_t() ) )>; + // Constructs a static constant given the type and parameters, returns a reference to it. // namespace impl @@ -379,31 +407,6 @@ namespace vtil template concept Possessable = !std::is_void_v() ) )>; - // Gets the size of the given container, 0 if N/A. - // - template - static constexpr size_t dynamic_size( T&& o ) - { - if constexpr ( DefaultRandomAccessible ) - return std::size( o ); - else if constexpr ( CustomRandomAccessible ) - return o.size(); - else if constexpr ( Iterable ) - return std::distance( std::begin( o ), std::end( o ) ); - return 0; - } - - // Gets the Nth element from the object, void if N/A. - // - template - static constexpr decltype( auto ) dynamic_get( T&& o, size_t N ) - { - if constexpr( RandomAccessible ) - return o[ N ]; - else if constexpr ( Iterable ) - return *std::next( std::begin( o ), N ); - } - // Bitcasting. // template diff --git a/VTIL-Common/util/zip.hpp b/VTIL-Common/util/zip.hpp index 3cf3e11..69fd6e6 100644 --- a/VTIL-Common/util/zip.hpp +++ b/VTIL-Common/util/zip.hpp @@ -55,7 +55,7 @@ namespace vtil { constexpr decltype( auto ) operator()( T& o, size_t N ) const { - return o[ N % dynamic_size( o ) ]; + return o[ N % std::size( o ) ]; } }; @@ -69,9 +69,9 @@ namespace vtil constexpr auto operator()( T& o, size_t N ) const { if constexpr ( std::is_reference_v ) - return dereference_if_n( N < dynamic_size( o ), std::begin( o ), N ); + return dereference_if_n( N < std::size( o ), std::begin( o ), N ); else - return N < dynamic_size( o ) ? std::optional{ o[ N ] } : std::nullopt; + return N < std::size( o ) ? std::optional{ o[ N ] } : std::nullopt; } }; }; @@ -81,84 +81,84 @@ namespace vtil { // Declare the entry type. // - using value_type = std::tuple{}( std::declval(), 0 ) )... >; + using entry_type = std::tuple{}( std::declval(), 0 ) )... >; // Declare the iterator type. // - struct iterator_end_tag_t {}; - struct iterator + struct base_iterator { // Generic iterator typedefs. // using iterator_category = std::bidirectional_iterator_tag; - using difference_type = size_t; - using pointer = value_type*; - using reference = value_type&; + using difference_type = int; + using value_type = entry_type*; + using pointer = entry_type*; + using reference = entry_type&; - // Self reference. + // Self reference and the index. // const joint_container& container; - - // Range of iteration. - // size_t index; - size_t limit; // Default constructor. // - iterator( const joint_container& container, size_t index = 0 ) : - container( container ), index( index ), limit( container.size() ) {} + base_iterator( const joint_container& container, size_t index = 0 ) : + container( container ), index( index ) {} // Support bidirectional iteration. // - constexpr iterator& operator++() { index++; return *this; } - constexpr iterator& operator--() { index--; return *this; } + constexpr base_iterator& operator++() { ++index; return *this; } + constexpr base_iterator& operator--() { --index; return *this; } + constexpr base_iterator operator++( int ) { auto s = *this; operator--(); return s; } + constexpr base_iterator operator--( int ) { auto s = *this; operator++(); return s; } // Equality check against another iterator. // - constexpr bool operator==( const iterator& other ) const { return index == other.index && &container == &other.container; } - constexpr bool operator!=( const iterator& other ) const { return index != other.index || &container != &other.container; } - - // Equality check against special end iterator. - // - constexpr bool operator==( iterator_end_tag_t ) const { return index == limit; } - constexpr bool operator!=( iterator_end_tag_t ) const { return index != limit; } + constexpr bool operator==( const base_iterator& other ) const { return index == other.index && &container == &other.container; } + constexpr bool operator!=( const base_iterator& other ) const { return index != other.index || &container != &other.container; } // Redirect dereferencing to container. // - constexpr value_type operator*() const { return container.at( index ); } + constexpr entry_type operator*() const { return container.at( index ); } }; - using const_iterator = iterator; + using iterator = base_iterator; + using const_iterator = base_iterator; // Tuple containing data sources. // std::tuple sources; + size_t size_0; + + constexpr joint_container( std::tuple&& source ) + : sources( std::move( source ) ), size_0( std::size( std::get<0>( sources ) ) ) {} // Declare random access helper. // template - constexpr value_type at( size_t idx, std::index_sequence ) const + constexpr entry_type at( size_t idx, std::index_sequence ) const { return { accessor{}( std::get( sources ), idx )... }; } - constexpr value_type at( size_t idx ) const + constexpr entry_type at( size_t idx ) const { return at( idx, std::index_sequence_for{} ); } // Generic container helpers. // - constexpr size_t size() const { return dynamic_size( std::get<0>( sources ) ); } + constexpr size_t size() const { return size_0; } constexpr iterator begin() const { return { *this, 0 }; } - constexpr iterator_end_tag_t end() const { return {}; } + constexpr iterator end() const { return { *this, size_0 }; } }; // Simple joint container creation from wrappers. // - template + template requires ( Iterable && ... ) static constexpr auto zip_s( Tx&... args ) -> joint_container { return { std::tie( args... ) }; } - template + + template requires ( Iterable && ... ) static constexpr auto zip_c( Tx&... args ) -> joint_container { return { std::tie( args... ) }; } - template + + template requires ( Iterable && ... ) static constexpr auto zip( Tx&... args ) -> joint_container { return { std::tie( args... ) }; } }; \ No newline at end of file diff --git a/VTIL-Compiler/common/interface.hpp b/VTIL-Compiler/common/interface.hpp index 888a025..f56b32b 100644 --- a/VTIL-Compiler/common/interface.hpp +++ b/VTIL-Compiler/common/interface.hpp @@ -115,7 +115,7 @@ namespace vtil::optimizer template requires Invocable() ) )> static void transform_parallel( C&& container, const F& worker ) { - size_t container_size = dynamic_size( container ); + size_t container_size = std::size( container ); // If parallel transformation is disabled or if the container only has one entry, // fallback to serial transformation. @@ -445,21 +445,18 @@ namespace vtil::optimizer { if ( !xblock ) logger::log( "Block %08x => %-64s |", blk->entry_vip, T{}.name() ); - auto t0 = std::chrono::steady_clock::now(); - size_t cnt = T::pass( blk, xblock ); - auto t1 = std::chrono::steady_clock::now(); + + auto [cnt, time] = profile( [ & ] () { return T::pass( blk, xblock ); } ); if ( !xblock ) - logger::log( " Took %-8.2fms (N=%d).\n", ( t1 - t0 ).count() * 1e-6f, cnt ); + logger::log( " Took %-10s (N=%d).\n", time, cnt ); return cnt; } size_t xpass( routine* rtn ) override { logger::log( "Routine => %-64s |", T{}.name() ); - auto t0 = std::chrono::steady_clock::now(); - size_t cnt = T::xpass( rtn ); - auto t1 = std::chrono::steady_clock::now(); - logger::log( " Took %-8.2fms (N=%d).\n", ( t1 - t0 ).count() * 1e-6f, cnt ); + auto [cnt, time] = profile( [ & ] () { return T::xpass( rtn ); } ); + logger::log( " Took %-10s (N=%d).\n", time, cnt ); return cnt; } };