<?php

error_reporting( -1 );
ini_set('display_errors', 1);

$trials = 1000000;

define( 'WP_MEMORY_LIMIT', '32M' );

$functions = array( 'wp_function', 'patch_function_original', 'patch_function_new', 'patch_function_new_complete', 'wp_convert_hr_to_bytes', 'map', 'aaron', 'str' );
$comparisons = array(
	''			=> '32M',
	'2147483648'=> '2147483648',
	'4294967296'=> '4294967296',
	'-1'		=> '-1',
	'100'		=> '32M',
	'1m'		=> '32M',
	'7.5G'		=> '7.5G',
	'234k'		=> '32M',
	'94556M'	=> '94556M',
	'128 M'		=> '128 M',
	'52428800'	=> '52428800',
);

$normalize_mem = create_function( '$val', '$val = trim($val); $last = strtolower($val[strlen($val)-1]); switch($last) { case \'g\': $val *= 1024; case \'m\': $val *= 1024; case \'k\': $val *= 1024; return max(0, (int) $val); }' );

/**
 * static error catching class
 *
 * start() starts tracking, stop() stops it and returns errors
 * that occured.
 */
class catcherrors {
	static $messages = array();
	static $active=false;
	static $oldDisplay;
	static function callback() {
		self::$messages[] = func_get_args();
		return true;
	}
	static function start() {
		if (self::$active) throw new Exception('already active. stop() first.');
		set_error_handler('catcherrors::callback');
		self::$active = true;
	}
	static function stop() {
		restore_error_handler();
		self::$active = false;
		$messages = self::$messages;
		self::$messages = array();
		return $messages;
	}
}

for ( $count = 0; $count < count( $functions ); $count++ ) {
	$function = $functions[$count];
	
	foreach ( $comparisons as $size => $answer ) {
		ini_set( 'memory_limit', $size );
		
		catcherrors::start();
		$function();
		$errors = catcherrors::stop();
		$result = ini_get( 'memory_limit' );
		
		echo "$function  $size => $answer ($result) ";

		if (count($errors)) {
			echo "(", count($errors), " errors!) ";
		} else {
			echo " (no errors) ";
		}
		if ( $answer == $result )
			echo "Success\n";
		else
			echo "Fail\n";

		foreach($errors as $index => $error) {
			printf(" #%d: %s %s %s\n", $index, $error[0], $error[1], $error[2]);
		}

	}
	echo "\n";
}

$results = array();

echo 'Running ', $trials, ' iterations now...';

for ( $count = 0; $count < $trials; $count++ ) {
	$function = $functions[ rand( 0, count( $functions ) - 1 ) ];
	
	if ( ! isset( $results[$function] ) ) {
		$results[$function] = array(
			'trials'		=> 0,
			'total_time'	=> 0,
			'trial_time'	=> array(),
			'success_count'	=> 0,
			'total_count'	=> 0,
		);
	}
	
	run_trial( $function );
}

echo ' - done.', "\n\nResults:\n\n";

foreach ( $functions as $function ) {
	$result = $results[$function];
	
	echo "$function\n";
	echo "==========================\n";
	echo "Trials:           {$result['trials']}\n";
	echo "Total Time:       {$result['total_time']}\n";
	echo "Average Time:     " . ( $result['total_time'] / $result['trials'] ) . "\n";
	echo "Runs per Sec:     " . ( 1 / ( $result['total_time'] / $result['trials'] ) ) . "\n";
	
	if ( $result['total_count'] > 0 )
		echo "Success Rate:     " . ( $result['success_count'] / $result['total_count'] ) . "\n";
	
	if ( isset( $results['wp_function']['total_time'] ) )
		echo "Speed Difference: " . ( ( $result['total_time'] - $results['wp_function']['total_time'] ) / $results['wp_function']['total_time'] ) . "\n";
	
	echo "\n";
}

function run_trial( $function, $count = 10 ) {
	global $results, $comparisons;
	
	
	$time = 0;
	
	$success_count = $total_count = 0;
	
	for ( $i = 0; $i < $count; $i++ ) {
		foreach ( $comparisons as $size => $answer ) {
			ini_set( 'memory_limit', $size );
			
			catcherrors::start();
			$start = microtime( true );
			$function();
			$end = microtime( true );
			$errors = catcherrors::stop();
			$error_count = count($errors);
			
			$time += $end - $start;
			
			
			if ( 0 ===  $error_count && $answer == ini_get( 'memory_limit' ) )
				$success_count++;
			$total_count++;
		}
	}
	
	
	$results[$function]['trials']++;
	$results[$function]['total_time'] += $time;
	$results[$function]['success_count'] += $success_count;
	$results[$function]['total_count'] += $total_count;
}


function wp_function() {
	if ( function_exists('memory_get_usage') && ( (int) @ini_get('memory_limit') < abs(intval(WP_MEMORY_LIMIT)) ) )
		@ini_set('memory_limit', WP_MEMORY_LIMIT);
}

function patch_function_original() {
	global $normalize_mem;
	
	if (
		function_exists( 'memory_get_usage' )
		&& ( function_exists( $normalize_mem ) )
		&& ( $normalize_mem( @ini_get( 'memory_limit' ) ) < $normalize_mem( WP_MEMORY_LIMIT ) )
	) {
		@ini_set('memory_limit', WP_MEMORY_LIMIT);
	}
	unset( $normalize_mem );
}

function patch_function_new() {
	if ( function_exists( 'memory_get_usage' ) ) {
		$memory_limit = @ini_get( 'memory_limit' );
		
		if ( $memory_limit > -1 ) {
			switch( substr( $memory_limit, -1 ) ) {
				case 'M': case 'm':
					$memory_limit = (int) $memory_limit;
					break;
				case 'G': case 'g':
					$memory_limit = (int) $memory_limit * 1024;
					break;
				case 'K': case 'k':
					$memory_limit = (int) $memory_limit / 1024;
					break;
				default:
					$memory_limit = (int) $memory_limit / 1048576;
			}
			
			if ( $memory_limit < abs( intval( WP_MEMORY_LIMIT ) ) )
				@ini_set( 'memory_limit', WP_MEMORY_LIMIT );
		}
	}
}

function patch_function_new_complete() {
	$memory_limit = @ini_get( 'memory_limit' );
	
	if ( $memory_limit > -1 ) {
		$unit = strtolower( substr( $memory_limit, -1 ) );
		
		$wp_memory_limit = WP_MEMORY_LIMIT;
		$wp_unit = strtolower( substr( $wp_memory_limit, -1 ) );
		
		if ( 'm' == $unit )
			$memory_limit *= 1048576;
		else if ( 'g' == $unit )
			$memory_limit *= 1073741824;
		else if ( 'k' == $unit )
			$memory_limit *= 1024;
		
		if ( 'm' == $wp_unit )
			$wp_memory_limit *= 1048576;
		else if ( 'g' == $wp_unit )
			$wp_memory_limit *= 1073741824;
		else if ( 'k' == $wp_unit )
			$wp_memory_limit *= 1024;
		
		if ( (int) $memory_limit < (int) $wp_memory_limit )
			@ini_set( 'memory_limit', WP_MEMORY_LIMIT );
	}
}

function wp_convert_hr_to_bytes() {
	$size = strtolower(@ini_get('memory_limit'));
	$bytes = (int) $size;
	if ( strpos($size, 'k') !== false )
		$bytes = intval($size) * 1024;
	elseif ( strpos($size, 'm') !== false )
		$bytes = intval($size) * 1024 * 1024;
	elseif ( strpos($size, 'g') !== false )
		$bytes = intval($size) * 1024 * 1024 * 1024;
	
	$wp_size = strtolower(@ini_get('memory_limit'));
	$wp_bytes = (int) $wp_size;
	if ( strpos($wp_size, 'k') !== false )
		$wp_bytes = intval($wp_size) * 1024;
	elseif ( strpos($wp_size, 'm') !== false )
		$wp_bytes = intval($wp_size) * 1024 * 1024;
	elseif ( strpos($wp_size, 'g') !== false )
		$wp_bytes = intval($wp_size) * 1024 * 1024 * 1024;
	
	if ( $bytes < $wp_bytes )
		@ini_set( 'memory_limit', WP_MEMORY_LIMIT );
}

function map() {
	static $map = array('g' => 1073741824, 'm' => 1048576, 'k'=> 1024);
	$memory_limit = @ini_get( 'memory_limit' );
	
	if ( $memory_limit > -1 ) {
		$wp_memory_limit = WP_MEMORY_LIMIT;
		$unit = strtolower( substr( $memory_limit, -1 ) );
		$wp_unit = strtolower( substr( $wp_memory_limit, -1 ) );
		
		isset($map[$unit]) && (float) $memory_limit *= $map[$unit];
		isset($map[$wp_unit]) && (float) $wp_memory_limit *= $map[$wp_unit];
		
		if ( $memory_limit < $wp_memory_limit )
			@ini_set( 'memory_limit', WP_MEMORY_LIMIT );
	}
}

function str() {
	static $str = ' kmg';
	$memory_limit = @ini_get( 'memory_limit' );
	
	if ( $memory_limit > -1 ) {
		$wp_memory_limit = WP_MEMORY_LIMIT;

		$unit = strtolower( substr( $memory_limit, -1 ) );
		$wp_unit = strtolower( substr( $wp_memory_limit, -1 ) );
		
		$unit && (float) $memory_limit *= pow(1024, strpos($str, $unit, 1));
		$wp_unit && (float) $wp_memory_limit *= pow(1024, strpos($str, $wp_unit, 1));
		
		if ( $memory_limit < $wp_memory_limit )
			@ini_set( 'memory_limit', WP_MEMORY_LIMIT );
	}
}

function aaron() {
	$memory_limit = @ini_get( 'memory_limit' );
	
	if ( $memory_limit > -1 ) {
		$symbol = array('B', 'K', 'M', 'G');
		
		$unit = strtolower( substr( $memory_limit, -1 ) );
		
		$wp_memory_limit = WP_MEMORY_LIMIT;
		$wp_unit = strtolower( substr( $wp_memory_limit, -1 ) );
		
		$memory_limit *= pow(1024, array_search(strtoupper($unit), $symbol));
		$wp_memory_limit *= pow(1024, array_search(strtoupper($wp_unit), $symbol));
		
		if ( (int) $memory_limit < (int) $wp_memory_limit )
			@ini_set( 'memory_limit', WP_MEMORY_LIMIT );
	}
}
