Skip to content

Instantly share code, notes, and snippets.

@hirosof
Created March 31, 2023 18:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hirosof/94b389fb9dd076921a42dd93e9adf621 to your computer and use it in GitHub Desktop.
Save hirosof/94b389fb9dd076921a42dd93e9adf621 to your computer and use it in GitHub Desktop.
#pragma once
#include <limits>
#include <stdexcept>
template <typename T> class GeneralCounter {
private:
const bool m_is_signed_type = std::numeric_limits<T>::is_signed;
T m_start;
T m_end;
T m_update;
T m_frame_count;
static bool s_isRangeValue( T value, T range_x, T range_y ) {
if ( range_x > range_y ) return s_isRangeValue( value, range_y, range_x );
return ( value >= range_x ) && ( value <= range_y );
}
static T s_clipValue( T value, T range_x, T range_y ) {
if ( range_x > range_y ) return s_clipValue( value, range_y, range_x );
T v = ( value > range_y ) ? range_y : value;
return ( v < range_x ) ? range_x : v;
}
public:
GeneralCounter( ) {
const T default_start = 0;
const T default_end = 10;
const T default_update = 1;
change( default_start, default_end, default_update );
}
GeneralCounter( T startValue, T endValue, T updateValue = 1 ){
change( startValue, endValue, updateValue );
}
template <typename U, size_t elements> GeneralCounter( const U( &array_value )[elements] ) {
change( 0, static_cast<T>( elements - 1 ), 1 );
}
void change( T startValue, T endValue, T updateValue = 1 ) {
if ( updateValue == 0 ) {
throw std::invalid_argument( "不正パラメータ:カウンター更新値が0です" );
}
if ( m_is_signed_type ) {
if ( ( endValue - startValue ) / updateValue < 0 ) {
throw std::exception( "実現不可能なカウンター:終点値に到達不可能なカウンターです。" );
}
} else {
if ( startValue > endValue ) {
throw std::exception( "実現不可能なカウンター:終点値に到達不可能なカウンターです。" );
}
}
m_start = startValue;
m_end = endValue;
m_update = updateValue;
reset( );
}
template <typename U, size_t elements> void change_of_array_size( const U (&array_value)[elements] ) {
change( 0, static_cast<T>(elements - 1), 1 );
}
T get_setting_start( void ) const {
return m_start;
}
T get_setting_end( void ) const {
return m_end;
}
T get_setting_update( void )const {
return m_update;
}
void reset( void ) {
m_frame_count = 0;
}
void update( void ) {
if ( checkWithin( ) ) m_frame_count++;
}
T get_frame( void ) const{
return m_frame_count;
}
T get_raw_value( void ) const {
return m_start + m_frame_count * m_update;
}
T get( void )const {
return s_clipValue( get_raw_value( ), m_start, m_end );
}
bool checkWithin( void ) const {
return s_isRangeValue( get_raw_value( ), m_start, m_end );
}
};
@hirosof
Copy link
Author

hirosof commented Mar 31, 2023

サンプル使用コード

#include <iostream>
#include <cstdio>
#include <cstdint>
#include "GeneralCounter.hpp"

template <typename T> void GeneralCounterRun( T start, T end, T  update ) {
	using std::cout;
	using std::endl;


	try {
		GeneralCounter <T> c( start, end, update );

		cout << "" << c.get_setting_start( ) << "』から『" << c.get_setting_end( ) << "』まで『" << c.get_setting_update( ) << "』刻みでカウント\n" << endl;

		cout << "name" << "\t\t" << "get" << "\t\t" << "rawget" << "\t\t" << "frame" << endl;

		for ( c.reset( ); c.checkWithin( ); c.update( ) ) {
			cout << "forループ内" << "\t" << c.get( ) << "\t\t" << c.get_raw_value( ) << "\t\t" << c.get_frame( ) << endl;
		}

		cout << "forループ後" << "\t" << c.get( ) << "\t\t" << c.get_raw_value( ) << "\t\t" << c.get_frame( ) << "\n" << endl;
	} catch ( std::exception e ) {
		printf( "std::exception(\"%s\")\n\n", e.what( ) );
	}
}


int main( void ) {

	using std::cout;
	using std::endl;

	cout << " 【GeneralCounterRun<int>( 0, 5, 1 )】" << endl;
	GeneralCounterRun<int>( 0, 5, 1 );

	cout << " 【GeneralCounterRun<int>( 1, 10, 3 )】" << endl;
	GeneralCounterRun<int>( 1, 10, 3 );

	cout << " 【GeneralCounterRun<int>( 5, 0, -1 )】" << endl;
	GeneralCounterRun<int>( 5, 0, -1 );

	cout << " 【GeneralCounterRun<double>( 0, 1, 0.2 )】" << endl;
	GeneralCounterRun<double>( 0, 1, 0.2 );

	cout << " 【GeneralCounterRun<int>( 5, 0, 0 )】 (実現不可能なケース)" << endl;
	GeneralCounterRun<int>( 5, 0, 0 );

	cout << " 【GeneralCounterRun<int>( 5, 0, 1 )】 (実現不可能なケース)" << endl;
	GeneralCounterRun<int>( 5, 0, 1 );

	cout << " 【GeneralCounterRun<int>( 0, 5, -1 )】 (実現不可能なケース)" << endl;
	GeneralCounterRun<int>( 0, 5, -1 );

	try{ 
		cout << "配列内容出力" << endl;
		double a[] = { 5.25,2.4,6.001 };
		for ( GeneralCounter<size_t> c(a) ; c.checkWithin( ); c.update( ) ) {
			cout << "[" << c.get( ) << "] " << a[c.get( )] << endl;
		}

	} catch ( std::exception e ) {
		printf( "std::exception(\"%s\")\n\n", e.what( ) );
	}

	return 0;
}

@hirosof
Copy link
Author

hirosof commented Mar 31, 2023

サンプル使用コードの実行結果

 【GeneralCounterRun<int>( 0, 5, 1 )】
『0』から『5』まで『1』刻みでカウント

name            get             rawget          frame
forループ内     0               0               0
forループ内     1               1               1
forループ内     2               2               2
forループ内     3               3               3
forループ内     4               4               4
forループ内     5               5               5
forループ後     5               6               6

 【GeneralCounterRun<int>( 1, 10, 3 )】
『1』から『10』まで『3』刻みでカウント

name            get             rawget          frame
forループ内     1               1               0
forループ内     4               4               1
forループ内     7               7               2
forループ内     10              10              3
forループ後     10              13              4

 【GeneralCounterRun<int>( 5, 0, -1 )】
『5』から『0』まで『-1』刻みでカウント

name            get             rawget          frame
forループ内     5               5               0
forループ内     4               4               1
forループ内     3               3               2
forループ内     2               2               3
forループ内     1               1               4
forループ内     0               0               5
forループ後     0               -1              6

 【GeneralCounterRun<double>( 0, 1, 0.2 )】
『0』から『1』まで『0.2』刻みでカウント

name            get             rawget          frame
forループ内     0               0               0
forループ内     0.2             0.2             1
forループ内     0.4             0.4             2
forループ内     0.6             0.6             3
forループ内     0.8             0.8             4
forループ内     1               1               5
forループ後     1               1.2             6

 【GeneralCounterRun<int>( 5, 0, 0 )】 (実現不可能なケース)
std::exception("不正パラメータ:カウンター更新値が0です")

 【GeneralCounterRun<int>( 5, 0, 1 )】 (実現不可能なケース)
std::exception("実現不可能なカウンター:終点値に到達不可能なカウンターです。")

 【GeneralCounterRun<int>( 0, 5, -1 )】 (実現不可能なケース)
std::exception("実現不可能なカウンター:終点値に到達不可能なカウンターです。")

配列内容出力
[0] 5.25
[1] 2.4
[2] 6.001

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment