<commit_before>package aerys.minko.render.geometry.stream
{
	import aerys.minko.ns.minko_stream;
	import aerys.minko.render.geometry.stream.format.VertexComponent;
	import aerys.minko.render.geometry.stream.format.VertexComponentType;
	import aerys.minko.render.geometry.stream.format.VertexFormat;
	import aerys.minko.render.resource.VertexBuffer3DResource;
	import aerys.minko.type.Signal;
	import aerys.minko.type.math.Matrix4x4;
	
	import flash.utils.ByteArray;
	import flash.utils.Dictionary;

	public final class VertexStream implements IVertexStream
	{
		use namespace minko_stream;

		public static const DEFAULT_FORMAT	: VertexFormat		= VertexFormat.XYZ_UV;

		private static const TMP_NUMBERS	: Vector.<Number>	= new <Number>[];
		
		minko_stream var _data			: Vector.<Number>			= null;
		minko_stream var _localDispose	: Boolean					= false;

		private var _usage				: uint						= 0;
		private var _format				: VertexFormat				= null;
		private var _resource			: VertexBuffer3DResource	= null;
		private var _length				: uint						= 0;
		
		private var _invalidMinMax		: Boolean					= true;
		private var _minimum			: Vector.<Number>			= null;
		private var _maximum			: Vector.<Number>			= null;
		
		private var _locked				: Boolean					= false;

		private var _boundsHaveChanged	: Boolean					= false;
		private var _dataHasChanged		: Boolean					= false;
		
		private var _changed			: Signal					= new Signal('VertexStream.changed');
		private var _boundsChanged		: Signal					= new Signal('VertexStream.boundsChanged');
		
		public function get format() : VertexFormat
		{
			return _format;
		}
		
		public function get usage() : uint
		{
			return _usage;
		}
		
		public function get resource() : VertexBuffer3DResource
		{
			return _resource;
		}
		
		public function get length() : uint
		{
			return _length;
		}
		
		protected function get data() : Vector.<Number>
		{
			return _data;
		}

		protected function set data(value : Vector.<Number>) : void
		{
			if (value && value.length != 0 && value.length % _format.size)
				throw new Error(
					'Invalid data: length does not match with the size of a vertex.'
				);
			
			_data = value;
			_changed.execute(this);
			updateMinMax(true);
		}
		
		public function get locked() : Boolean
		{
			return _locked;
		}
		
		public function get changed() : Signal
		{
			return _changed;
		}
		
		public function get boundsChanged() : Signal
		{
			return _boundsChanged;
		}

		public function VertexStream(usage		: uint,
									 format		: VertexFormat,
									 data 		: Vector.<Number>	= null)
		{
			super();

			initialize(data, format, usage);
		}

		private function initialize(data 	: Vector.<Number>,
									format	: VertexFormat,
									usage	: uint) : void
		{
			_changed.add(changedHandler);
			
			_resource = new VertexBuffer3DResource(this);
			_format = format || DEFAULT_FORMAT;
			
			_usage = usage;
			this.data = data ? data.concat() : new Vector.<Number>();
		}
		
		private function updateMinMax(forceReset : Boolean = false) : void
		{
			if (!_invalidMinMax && !forceReset)
				return ;
				
			_invalidMinMax = false;
			
			var dataLength	: uint	= data.length;
			var i			: uint	= 0;
			
			if (forceReset)
			{
				var size	: uint	= format.size;
				
				_minimum = new Vector.<Number>(size, true);
				_maximum = new Vector.<Number>(size, true);
				
				for (i = 0; i < size; ++i)
				{
					_minimum[i] = Number.MAX_VALUE;
					_maximum[i] = -Number.MAX_VALUE;
				}
			}
			
			_boundsHaveChanged = false;
			for (i = 0; i < dataLength; i += size)
			{
				for (var j : uint = 0; j < size; ++j)
				{
					var value : Number = _data[uint(i + j)];
					
					if (value < _minimum[j])
					{
						_minimum[j] = value;
						_boundsHaveChanged = true;
					}
					if (value > _maximum[j])
					{
						_maximum[j] = value;
						_boundsHaveChanged = true;
					}
				}
			}
			
			if (_boundsHaveChanged)
			{
				_boundsHaveChanged = false;
				_boundsChanged.execute(this);
			}
		}
		
		public function deleteVertexByIndex(index : uint) : Boolean
		{
			checkWriteUsage(this);
			
			if (index > length)
				return false;

			_data.splice(index, _format.size);
			
			if (_locked)
			{
				_invalidMinMax = true;
				_dataHasChanged = true;
			}
			else
			{
				_changed.execute(this);
				updateMinMax();
			}

			return true;
		}

		public function getStreamByComponent(vertexComponent : VertexComponent) : VertexStream
		{
			return _format.hasComponent(vertexComponent) ? this : null;
		}

		public function get(i : uint) : Number
		{
			checkReadUsage(this);
			
			return _data[i];
		}
		
		public function getMinimum(index : uint) : Number
		{
			return _minimum[index];
		}
		
		public function getMaximum(index : uint) : Number
		{
			return _maximum[index];
		}
		
		/**
		 * Lock the stream in order to perform bulk updates without triggering
		 * any signal to get better performances.
		 *  
		 * @return 
		 * 
		 */
		public function lock() : Vector.<Number>
		{
			if (_locked) 
				throw new Error('The stream is already locked.');
			if (_localDispose)
				throw new Error('Cannot lock stream data which is already disposed.');
			
			checkWriteUsage(this);
			
			_locked = true;
			_invalidMinMax = false;
			
			return _data;
		}
		
		/**
		 * Unlock the stream to reactivate signals. The VertexStream.changed signal
		 * is always executed when this method is called. The VertexStream.boundsChanged
		 * signal is called only if the bounds of the stream actually changed.
		 * 
		 */
		public function unlock() : void
		{
			if (!_locked)
				throw new Error('Cannot unlock a stream that is not locked.');
			
			var invalidMinMax : Boolean = _invalidMinMax;
			
			_locked = false;
			_invalidMinMax = true;
			
			if (_dataHasChanged)
			{
				_dataHasChanged = false;
				_changed.execute(this);
			}
			
			if (invalidMinMax)
				updateMinMax();
			if (_boundsHaveChanged)
				_boundsChanged.execute(this);
		}

		/**
		 * Set the value at the specified position in the stream.<commit_msg>add hasChanged : Boolean argument to VertexStream.unlock() to avoid executing the VertexStream.changed signal if nothing has changed since VertexStream.lock()<commit_after>package aerys.minko.render.geometry.stream
{
	import aerys.minko.ns.minko_stream;
	import aerys.minko.render.geometry.stream.format.VertexComponent;
	import aerys.minko.render.geometry.stream.format.VertexComponentType;
	import aerys.minko.render.geometry.stream.format.VertexFormat;
	import aerys.minko.render.resource.VertexBuffer3DResource;
	import aerys.minko.type.Signal;
	import aerys.minko.type.math.Matrix4x4;
	
	import flash.utils.ByteArray;
	import flash.utils.Dictionary;

	public final class VertexStream implements IVertexStream
	{
		use namespace minko_stream;

		public static const DEFAULT_FORMAT	: VertexFormat		= VertexFormat.XYZ_UV;

		private static const TMP_NUMBERS	: Vector.<Number>	= new <Number>[];
		
		minko_stream var _data			: Vector.<Number>			= null;
		minko_stream var _localDispose	: Boolean					= false;

		private var _usage				: uint						= 0;
		private var _format				: VertexFormat				= null;
		private var _resource			: VertexBuffer3DResource	= null;
		private var _length				: uint						= 0;
		
		private var _invalidMinMax		: Boolean					= true;
		private var _minimum			: Vector.<Number>			= null;
		private var _maximum			: Vector.<Number>			= null;
		
		private var _locked				: Boolean					= false;

		private var _boundsHaveChanged	: Boolean					= false;
		private var _dataHasChanged		: Boolean					= false;
		
		private var _changed			: Signal					= new Signal('VertexStream.changed');
		private var _boundsChanged		: Signal					= new Signal('VertexStream.boundsChanged');
		
		public function get format() : VertexFormat
		{
			return _format;
		}
		
		public function get usage() : uint
		{
			return _usage;
		}
		
		public function get resource() : VertexBuffer3DResource
		{
			return _resource;
		}
		
		public function get length() : uint
		{
			return _length;
		}
		
		protected function get data() : Vector.<Number>
		{
			return _data;
		}

		protected function set data(value : Vector.<Number>) : void
		{
			if (value && value.length != 0 && value.length % _format.size)
				throw new Error(
					'Invalid data: length does not match with the size of a vertex.'
				);
			
			_data = value;
			_changed.execute(this);
			updateMinMax(true);
		}
		
		public function get locked() : Boolean
		{
			return _locked;
		}
		
		public function get changed() : Signal
		{
			return _changed;
		}
		
		public function get boundsChanged() : Signal
		{
			return _boundsChanged;
		}

		public function VertexStream(usage		: uint,
									 format		: VertexFormat,
									 data 		: Vector.<Number>	= null)
		{
			super();

			initialize(data, format, usage);
		}

		private function initialize(data 	: Vector.<Number>,
									format	: VertexFormat,
									usage	: uint) : void
		{
			_changed.add(changedHandler);
			
			_resource = new VertexBuffer3DResource(this);
			_format = format || DEFAULT_FORMAT;
			
			_usage = usage;
			this.data = data ? data.concat() : new Vector.<Number>();
		}
		
		private function updateMinMax(forceReset : Boolean = false) : void
		{
			if (!_invalidMinMax && !forceReset)
				return ;
				
			_invalidMinMax = false;
			
			var dataLength	: uint	= data.length;
			var i			: uint	= 0;
			
			if (forceReset)
			{
				var size	: uint	= format.size;
				
				_minimum = new Vector.<Number>(size, true);
				_maximum = new Vector.<Number>(size, true);
				
				for (i = 0; i < size; ++i)
				{
					_minimum[i] = Number.MAX_VALUE;
					_maximum[i] = -Number.MAX_VALUE;
				}
			}
			
			_boundsHaveChanged = false;
			for (i = 0; i < dataLength; i += size)
			{
				for (var j : uint = 0; j < size; ++j)
				{
					var value : Number = _data[uint(i + j)];
					
					if (value < _minimum[j])
					{
						_minimum[j] = value;
						_boundsHaveChanged = true;
					}
					if (value > _maximum[j])
					{
						_maximum[j] = value;
						_boundsHaveChanged = true;
					}
				}
			}
			
			if (_boundsHaveChanged)
			{
				_boundsHaveChanged = false;
				_boundsChanged.execute(this);
			}
		}
		
		public function deleteVertexByIndex(index : uint) : Boolean
		{
			checkWriteUsage(this);
			
			if (index > length)
				return false;

			_data.splice(index, _format.size);
			
			if (_locked)
			{
				_invalidMinMax = true;
				_dataHasChanged = true;
			}
			else
			{
				_changed.execute(this);
				updateMinMax();
			}

			return true;
		}

		public function getStreamByComponent(vertexComponent : VertexComponent) : VertexStream
		{
			return _format.hasComponent(vertexComponent) ? this : null;
		}

		public function get(i : uint) : Number
		{
			checkReadUsage(this);
			
			return _data[i];
		}
		
		public function getMinimum(index : uint) : Number
		{
			return _minimum[index];
		}
		
		public function getMaximum(index : uint) : Number
		{
			return _maximum[index];
		}
		
		/**
		 * Lock the stream in order to perform bulk updates without triggering
		 * any signal to get better performances.
		 *  
		 * @return 
		 * 
		 */
		public function lock() : Vector.<Number>
		{
			if (_locked) 
				throw new Error('The stream is already locked.');
			if (_localDispose)
				throw new Error('Cannot lock stream data which is already disposed.');
			
			checkReadUsage(this);
			checkWriteUsage(this);
			
			_locked = true;
			_invalidMinMax = false;
			
			return _data;
		}
		
		/**
		 * Unlock the stream to reactivate signals. The VertexStream.changed signal
		 * is always executed when this method is called. The VertexStream.boundsChanged
		 * signal is called only if the bounds of the stream actually changed.
		 * 
		 */
		public function unlock(hasChanged : Boolean = true) : void
		{
			if (!_locked)
				throw new Error('Cannot unlock a stream that is not locked.');
			
			var invalidMinMax : Boolean = _invalidMinMax;
			
			_locked = false;
			_invalidMinMax = true;
			
			if (_dataHasChanged && hasChanged)
			{
				_dataHasChanged = false;
				_changed.execute(this);
			}
			
			if (invalidMinMax)
				updateMinMax();
			if (_boundsHaveChanged && hasChanged)
				_boundsChanged.execute(this);
		}

		/**
		 * Set the value at the specified position in the stream.
{'fraction_non_alphanumeric': 0.09875437596678335, 'fraction_numerical': 0.002116746723113246, 'mean_word_length': 2.7066988533494265, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1688555', 'n_tokens_mistral': 5063, 'n_tokens_neox': 3837, 'n_words': 1027}