When playing sound, I need to adjust the volume of the right and left channels separately.
I have the class to play sound:
public class SoundPlayer
{
private WaveOutEvent _outputDevice;
private AudioFileReader _audioFile;
private float _volume = 1f;
public float Volume
{
get => _volume;
set
{
_volume = value;
if (_audioFile != null)
_audioFile.Volume = value;
}
}
public void Play(string fileName)
{
if (_outputDevice == null)
{
_outputDevice = new WaveOutEvent();
_outputDevice.PlaybackStopped += (sender, args) =>
{
_outputDevice.Dispose();
_outputDevice = null;
_audioFile.Dispose();
_audioFile = null;
};
}
if (_audioFile == null)
{
_audioFile = new AudioFileReader(fileName) { Volume = _volume };
_outputDevice.Init(_audioFile);
}
else
{
if (string.IsNullOrWhiteSpace(fileName))
_outputDevice = null;
else
{
if (_audioFile.FileName != fileName)
{
_audioFile = new AudioFileReader(fileName) { Volume = _volume };
_outputDevice.Init(_audioFile);
}
}
}
_outputDevice?.Play();
}
public void Stop()
{
_outputDevice?.Stop();
}
}
But in this class you can only adjust the overall volume. How to make such a property:
soundPlayer.LeftChannelVolume = 1.0f
soundPlayer.RightChannelVolume = 0.5f
I made my provider and it worked!)
If anyone needs it, then here:
/// <summary>
/// Very simple sample provider supporting adjustable gain
/// </summary>
public class VolumeStereoSampleProvider : ISampleProvider
{
private readonly ISampleProvider source;
/// <summary>
/// Allows adjusting the volume left channel, 1.0f = full volume
/// </summary>
public float VolumeLeft { get; set; }
/// <summary>
/// Allows adjusting the volume right channel, 1.0f = full volume
/// </summary>
public float VolumeRight { get; set; }
/// <summary>
/// Initializes a new instance of VolumeStereoSampleProvider
/// </summary>
/// <param name="source">Source sample provider, must be stereo</param>
public VolumeStereoSampleProvider(ISampleProvider source)
{
if (source.WaveFormat.Channels != 2)
throw new ArgumentException("Source sample provider must be stereo");
this.source = source;
VolumeLeft = 1.0f;
VolumeRight = 1.0f;
}
/// <summary>
/// WaveFormat
/// </summary>
public WaveFormat WaveFormat => source.WaveFormat;
/// <summary>
/// Reads samples from this sample provider
/// </summary>
/// <param name="buffer">Sample buffer</param>
/// <param name="offset">Offset into sample buffer</param>
/// <param name="sampleCount">Number of samples desired</param>
/// <returns>Number of samples read</returns>
public int Read(float[] buffer, int offset, int sampleCount)
{
int samplesRead = source.Read(buffer, offset, sampleCount);
for (int n = 0; n < sampleCount; n += 2)
{
buffer[offset + n] *= VolumeLeft;
buffer[offset + n + 1] *= VolumeRight;
}
return samplesRead;
}
}
Made with the help of PanningSampleProvider. But for this you have to convert to mono. Also, the reaction to changing Pan - occurs with a slight delay. How can this be avoided? How to work with stereo and just change the volume of its right and left channels? I think this should work much faster.
_audioFile = new AudioFileReader(_fileName) { Volume = _volume };
var mono = new StereoToMonoSampleProvider(_audioFile) { LeftVolume = 1f, RightVolume = 1f };
var panner = new PanningSampleProvider(mono);
_outputDevice.Init(panner);
Related
i need function that goes through all the existing layer names and find if my layer is there and if not then the code need to add the given layer to the layer list
i tried this code this unity forum
void CreateLayer()
{
SerializedObject tagManager = new SerializedObject(AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/TagManager.asset")[0]);
SerializedProperty layers = tagManager.FindProperty("layers");
if (layers == null || !layers.isArray)
{
Debug.LogWarning("Can't set up the layers. It's possible the format of the layers and tags data has changed in this version of Unity.");
Debug.LogWarning("Layers is null: " + (layers == null));
return;
}
for (int i = 8; i < 31; i++)
{
SerializedProperty layerSP = layers.GetArrayElementAtIndex(i);
if (layerSP.stringValue == "MyLayer")
{
return;
}
}
for (int i = 8; i < 31; i++)
{
SerializedProperty layerSP = layers.GetArrayElementAtIndex(i);
if (layerSP.stringValue != "")
{
layerSP.stringValue = "MyLayer";
break;
}
}
tagManager.ApplyModifiedProperties();
}
but it dosen't work for me
by the way i'm using unity 5.6.3
if anybody knows the answer please share
i found out this one over here this answer will work only in editor and will not work in build
create a new c# script add this code into it
using UnityEngine;
using System.Collections;
public class Layers
{
private static int maxTags = 10000;
private static int maxLayers = 31;
/////////////////////////////////////////////////////////////////////
public void AddNewLayer(string name)
{
CreateLayer(name);
}
public void DeleteLayer(string name)
{
RemoveLayer(name);
}
////////////////////////////////////////////////////////////////////
/// <summary>
/// Adds the layer.
/// </summary>
/// <returns><c>true</c>, if layer was added, <c>false</c> otherwise.</returns>
/// <param name="layerName">Layer name.</param>
public static bool CreateLayer(string layerName)
{
// Open tag manager
SerializedObject tagManager = new SerializedObject(AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/TagManager.asset")[0]);
// Layers Property
SerializedProperty layersProp = tagManager.FindProperty("layers");
if (!PropertyExists(layersProp, 0, maxLayers, layerName))
{
SerializedProperty sp;
// Start at layer 9th index -> 8 (zero based) => first 8 reserved for unity / greyed out
for (int i = 8, j = maxLayers; i < j; i++)
{
sp = layersProp.GetArrayElementAtIndex(i);
if (sp.stringValue == "")
{
// Assign string value to layer
sp.stringValue = layerName;
Debug.Log("Layer: " + layerName + " has been added");
// Save settings
tagManager.ApplyModifiedProperties();
return true;
}
if (i == j)
Debug.Log("All allowed layers have been filled");
}
}
else
{
//Debug.Log ("Layer: " + layerName + " already exists");
}
return false;
}
public static string NewLayer(string name)
{
if (name != null || name != "")
{
CreateLayer(name);
}
return name;
}
/// <summary>
/// Removes the layer.
/// </summary>
/// <returns><c>true</c>, if layer was removed, <c>false</c> otherwise.</returns>
/// <param name="layerName">Layer name.</param>
public static bool RemoveLayer(string layerName)
{
// Open tag manager
SerializedObject tagManager = new SerializedObject(AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/TagManager.asset")[0]);
// Tags Property
SerializedProperty layersProp = tagManager.FindProperty("layers");
if (PropertyExists(layersProp, 0, layersProp.arraySize, layerName))
{
SerializedProperty sp;
for (int i = 0, j = layersProp.arraySize; i < j; i++)
{
sp = layersProp.GetArrayElementAtIndex(i);
if (sp.stringValue == layerName)
{
sp.stringValue = "";
Debug.Log("Layer: " + layerName + " has been removed");
// Save settings
tagManager.ApplyModifiedProperties();
return true;
}
}
}
return false;
}
/// <summary>
/// Checks to see if layer exists.
/// </summary>
/// <returns><c>true</c>, if layer exists, <c>false</c> otherwise.</returns>
/// <param name="layerName">Layer name.</param>
public static bool LayerExists(string layerName)
{
// Open tag manager
SerializedObject tagManager = new SerializedObject(AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/TagManager.asset")[0]);
// Layers Property
SerializedProperty layersProp = tagManager.FindProperty("layers");
return PropertyExists(layersProp, 0, maxLayers, layerName);
}
/// <summary>
/// Checks if the value exists in the property.
/// </summary>
/// <returns><c>true</c>, if exists was propertyed, <c>false</c> otherwise.</returns>
/// <param name="property">Property.</param>
/// <param name="start">Start.</param>
/// <param name="end">End.</param>
/// <param name="value">Value.</param>
private static bool PropertyExists(SerializedProperty property, int start, int end, string value)
{
for (int i = start; i < end; i++)
{
SerializedProperty t = property.GetArrayElementAtIndex(i);
if (t.stringValue.Equals(value))
{
return true;
}
}
return false;
}
}
and to create a layer
new Layers().AddNewLayer("PP");
Hi everyone. The problem is too long for me to paste it here so I will paste a URL instead. I get 50% invalid returns. I added a check if a cat has hit a deadlock to collect food/soul on that cell. I have been tackling this issue since 6 am and it is 11am now and I am getting to the point of frustration.
Briefly the problem is the following:
Your task is to calculate the food and the souls collected by Kitty or to output that she is deadlocked.
On the first line of the input you will receive the positions of the coder souls ("#"), food ("*") and deadlocks ("x") as string.
On the second line of the input you will receive the path of the Kitty as string with integers separated by single space. Positive means, move to the right, negative means, move to the left.
The starting position will always be at index 0.
The final result is either the souls, food and deadlocks count or a string informing that the Kitty is deadlocked. The format is shown in the zero tests and the example.
# - symbol for coder soul
* - symbol for food
x - symbol for deadlock
More details below:
https://judge.telerikacademy.com/problem/30kitty
string input = Console.ReadLine();
int deadlocks = 0;
string input2 = Console.ReadLine();
string[] output = input2.Split(' ');
int position = 0;
int startposition = 0;
int codersoulscollected = 0;
int foodcollected = 0;
int iterations = Math.Max(input.Length, output.Length);
bool[] isCollected = new bool[input.Length];
for (int i = 0; i <= iterations; i++)
{
startposition += position;
if (startposition < 0)
{
startposition = input.Length + startposition;
}
if (startposition >= input.Length)
{
startposition = startposition - input.Length;
}
char a = input[startposition];
if (a == '#' && (isCollected[startposition] == false))
{
codersoulscollected++;
isCollected[startposition] = true;
}
if (a == '*' && (isCollected[startposition] == false))
{
foodcollected++;
isCollected[startposition] = true;
}
if (a == 'x' && (isCollected[startposition] == false))
{
deadlocks++;
if (startposition % 2 == 0)
{
codersoulscollected--;
isCollected[startposition] = true;
}
else
{
foodcollected--;
isCollected[startposition] = true;
}
}
else if (a == 'x' && (isCollected[startposition] == true))
{
if (startposition % 2 == 0)
{
codersoulscollected++;
}
else
{
foodcollected++;
}
}
if (output.Length == i)
{
break;
}
position = int.Parse(output[i]);
if (foodcollected < 0 || codersoulscollected < 0)
{
Console.WriteLine("You are deadlocked, you greedy kitty!");
Console.WriteLine($"Jumps before deadlock: {i}");
return;
}
}
if (foodcollected >= 0 || codersoulscollected >= 0)
{
Console.WriteLine($"Coder souls collected: {codersoulscollected}\r\nFood collected: {foodcollected}\r\nDeadlocks: {deadlocks}");
}
Since I had some time at my hand, I wrote a simple solution for you which walks you step by step in an OOP manner. Hopefully you can see your problem as well.
This is your cat. It can walk the given amount of steps on a given Path. It also collects food and soul etc.
public class Cat
{
/// <summary>
/// Amount of collected coder souls.
/// </summary>
private int _coderSouls;
/// <summary>
/// Amount of collected food.
/// </summary>
private int _food;
/// <summary>
/// Amount of deadlocks collected.
/// </summary>
private int _deadlocks;
/// <summary>
/// Number of jumps before deadlocking.
/// Starts from -1 because When we set the path
/// The kitty starts from the 0th tile.
/// </summary>
private int _numberOfJumps = -1;
/// <summary>
/// If Cat can still move.
/// </summary>
private bool _deadLocked;
/// <summary>
/// Path to follow.
/// </summary>
private Path _path;
/// <summary>
/// Creates a Kitty
/// </summary>
/// <param name="path">Path for Kitty</param>
public Cat(Path path)
{
SetPath(path);
}
/// <summary>
/// Set the path for Kitty to follow.
/// </summary>
/// <param name="path">Path to follow.</param>
private void SetPath(Path path)
{
_path = path;
Walk(0);
}
/// <summary>
/// Walks the Kitty with the given amount of steps.
/// </summary>
/// <param name="step">Amount of steps</param>
/// <returns>If kitty can move any more.</returns>
public bool Walk(int step)
{
// If Kitty is deadlocked it can not move any more
if (_deadLocked)
{
return false;
}
// Walks the cat with the given step amount
var got = _path.MoveToNext(step);
// Increase the number of Jumps
_numberOfJumps++;
// Rule written in the question
switch (got)
{
case ItemType.CoderSoul:
_coderSouls++;
break;
case ItemType.Food:
_food++;
break;
case ItemType.DeadLock:
_deadlocks++;
var isEven = _path.GetPosition() % 2 == 0;
if (isEven)
{
if (_coderSouls > 0)
{
_coderSouls--;
return true;
}
_deadLocked = true;
return false;
}
if (_food > 0)
{
_food--;
return true;
}
_deadLocked = true;
return false;
}
return true;
}
/// <summary>
/// When Kitty finished moving, Gets Summary.
/// </summary>
/// <returns>Summary of movemebt</returns>
public string Summarize()
{
return _deadLocked ? PrepareDeadLockMessage() : PrepareSummaryMessage();
}
/// <summary>
/// Deadlock message.
/// </summary>
/// <returns>Deadlock message.</returns>
private string PrepareDeadLockMessage()
{
return $"You are deadlocked, you greedy kitty!{Environment.NewLine}Jumps before deadlock: {_numberOfJumps}";
}
/// <summary>
/// Normal finish.
/// </summary>
/// <returns>Normal finish.</returns>
private string PrepareSummaryMessage()
{
return $"Coder souls collected: {_coderSouls}{Environment.NewLine}Food collected: {_food}{Environment.NewLine}Deadlocks: {_deadlocks}";
}
}
This is your path. You have to parse it as it was given in the question.
public class Path
{
private readonly Item[] path;
private int _currentIndex;
public Path(string pathElements)
{
path = pathElements.Select(t => new Item(t)).ToArray();
_currentIndex = 0;
}
public ItemType MoveToNext(int increase)
{
_currentIndex += increase;
if (_currentIndex > path.Length)
{
_currentIndex -= path.Length;
}
if (_currentIndex < 0)
{
_currentIndex += path.Length;
}
return path[_currentIndex].Collect();
}
public int GetPosition()
{
return _currentIndex;
}
}
This is your single item in your given cell.
public class Item
{
/// <summary>
/// Kitty already collected this cell or not?
/// </summary>
public bool IsCollected { get; private set; }
/// <summary>
/// ItemType in this cell
/// </summary>
public ItemType ItemType { get; }
/// <summary>
/// Represents a single item in each cell.
/// </summary>
/// <param name="c">Type of the item decided by char.</param>
public Item(char c)
{
switch (c)
{
case '#':
ItemType = ItemType.CoderSoul;
break;
case '*':
ItemType = ItemType.Food;
break;
case 'x':
ItemType = ItemType.DeadLock;
break;
}
}
/// <summary>
/// Collect the item in this cell.
/// </summary>
/// <returns>The collected item.</returns>
public ItemType Collect()
{
if (IsCollected)
{
return ItemType.None;
}
IsCollected = true;
return ItemType;
}
}
And finally this is your ItemTypes that can be contained in each cell
/// <summary>
/// The type of item located in each single cell.
/// </summary>
public enum ItemType
{
None,
CoderSoul,
Food,
DeadLock,
}
This is how you use this example. Please go through each step with a debugger.
var cat = new Cat(new Path("x#*#*#*"));
var walkinOrder = "1 -1 -1 4";
var intOrder = walkinOrder.Split(' ').Select(int.Parse);
foreach (var step in intOrder) {
if (cat.Walk(step) == false)
{
break;
}
}
Console.WriteLine(cat.Summarize());
Today I was looking for ways to store my Wavefront Models, and hopefully increase performance, too. I wanted to look into serialization, mainly because I had never used it before. In my mind, serialization/deserialization should be faster than parsing and reinitializing a Wavefront model, however, my benchmark shows otherwise.
Here is the code for my benchmark:
using System;
using System.Diagnostics;
using GrimoireTactics.Framework.OpenGL.Modeling;
using GrimoireTactics.Framework.Utilities;
namespace GrimoireDevelopmentKit.DevelopmentKit
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
WavefrontModel model;
Stopwatch benchmark = new Stopwatch();
//
// Benchmark Deserialization
//
// Do a warm up
for (int i = 0; i < 500; i++)
{
model = ResourceCompiler.ReadFromBinaryFile<WavefrontModel>("C:/Users/Krythic/Desktop/Compiled.sfg"); // Sfg is an extension I wanted to use
}
benchmark.Start();
model = ResourceCompiler.ReadFromBinaryFile<WavefrontModel>("C:/Users/Krythic/Desktop/Compiled.sfg"); // Sfg is an extension I wanted to use
benchmark.Stop();
Console.WriteLine("Deserialization: "+ benchmark.Elapsed);
benchmark.Reset();
//
// Benchmark Plain Old Initialization
//
model = new WavefrontModel();
// Do a Warm up
for (int i = 0; i < 500; i++)
{
model.Load("C:/Users/Krythic/Desktop/Closet.obj");
}
benchmark.Start();
model.Load("C:/Users/Krythic/Desktop/Closet.obj");
benchmark.Stop();
Console.WriteLine("Plain Old Initialization: " + benchmark.Elapsed);
Console.Read();
}
}
}
And here is the output:
Here is the code for Serialization and Deserialization(Which I found on Stackoverflow:
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace GrimoireTactics.Framework.Utilities
{
public class ResourceCompiler
{
/// <summary>
/// Writes the given object instance to a binary file.
/// <para>Object type (and all child types) must be decorated with the [Serializable] attribute.</para>
/// <para>To prevent a variable from being serialized, decorate it with the [NonSerialized] attribute; cannot be applied to properties.</para>
/// </summary>
/// <typeparam name="T">The type of object being written to the XML file.</typeparam>
/// <param name="filePath">The file path to write the object instance to.</param>
/// <param name="objectToWrite">The object instance to write to the XML file.</param>
/// <param name="append">If false the file will be overwritten if it already exists. If true the contents will be appended to the file.</param>
public static void WriteToBinaryFile<T>(string filePath, T objectToWrite, bool append = false)
{
using (Stream stream = File.Open(filePath, append ? FileMode.Append : FileMode.Create))
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
binaryFormatter.Serialize(stream, objectToWrite);
}
}
/// <summary>
/// Reads an object instance from a binary file.
/// </summary>
/// <typeparam name="T">The type of object to read from the XML.</typeparam>
/// <param name="filePath">The file path to read the object instance from.</param>
/// <returns>Returns a new instance of the object read from the binary file.</returns>
public static T ReadFromBinaryFile<T>(string filePath)
{
using (Stream stream = File.Open(filePath, FileMode.Open))
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
return (T)binaryFormatter.Deserialize(stream);
}
}
}
}
And here is my WavefrontModel class:
using System;
using System.Collections.Generic;
using System.IO;
using GrimoireTactics.Framework.OpenGL.Texturing;
using OpenTK;
using OpenTK.Graphics.OpenGL;
namespace GrimoireTactics.Framework.OpenGL.Modeling
{
[Serializable]
public class WavefrontModel
{
public Vector3[] Vertices;
public Vector2[] TexCoords;
public Vector3[] Normals;
public Face[] Faces;
public string ModelSource;
public string Name;
public Material Material;
/// <summary>
/// A static buffer used by all models when they are loaded.
/// </summary>
private static readonly string[] FileBuffer = new string[15];
/// <summary>
/// A static buffer used by all models when they are loaded.
/// </summary>
private static readonly string[] IndiceBuffer = new string[3];
/// <summary>
/// A static buffer used by all models when they are loaded.
/// </summary>
private static readonly FaceIndices[] VerticesIndexBuffer = new FaceIndices[3];
/// <summary>
/// The Triangle Count of this model.
/// </summary>
public int TriCount
{
get
{
return Faces.Length;
}
}
public WavefrontModel()
{
}
public WavefrontModel(string modelPath, Material material)
{
this.ModelSource = modelPath;
this.Material = material;
}
public WavefrontModel(string modelPath)
{
this.ModelSource = modelPath;
this.Material = null;
}
public WavefrontModel(string[] data)
{
this.ModelSource = String.Empty;
this.Material = null;
Load(data);
}
public WavefrontModel(string[] data, Material material)
{
this.ModelSource = String.Empty;
this.Material = material;
Load(data);
}
/// <summary>
/// Loads a model from the desired Wavefront.obj source given
/// at constructor initialization.
/// </summary>
public void Load()
{
Load(this.ModelSource);
}
/// <summary>
/// Loads a model from a Wavefront.obj located on disk.
/// </summary>
/// <param name="file"></param>
public void Load(string file)
{
Parse(File.ReadAllLines(file), this);
}
/// <summary>
/// Initializes this model with the data provided.
/// </summary>
/// <param name="data"></param>
public void Load(string[] data)
{
Parse(data, this);
}
/// <summary>
/// Current Benchmarked time(Warm boot)
/// </summary>
/// <param name="data"></param>
/// <param name="model"></param>
public static void Parse(string[] data, WavefrontModel model)
{
// Create Header
int totalVertices = 0;
int totalNormals = 0;
int totalTextureCoordinates = 0;
int totalFaces = 0;
for (int i = 0; i < data.Length; i++)
{
switch (data[i][0])
{
case 'v': // Geometric Parameter
switch (data[i][1])
{
case ' ': // Detect Vertices
totalVertices++;
break;
case 't': // Detect TexCoords
totalTextureCoordinates++;
break;
case 'n': // Detect Normals
totalNormals++;
break;
}
break;
case 'f':
totalFaces++;
break;
}
}
// Create the Buffers
model.Vertices = new Vector3[totalVertices];
model.Normals = new Vector3[totalNormals];
model.TexCoords = new Vector2[totalTextureCoordinates];
model.Faces = new Face[totalFaces];
// Load the Data
// Iterators
int verticesIterator = 0;
int normalsIterator = 0;
int textureCoordinatesIterator = 0;
int facesIterator = 0;
for (int line = 0; line < data.Length; line++)
{
string[] lineTokens = SplitStringFast(data[line], ' ', FileBuffer);
switch (lineTokens[0])
{
case "v": // Vector
Vector3 vertex = new Vector3
{
X = ParseFloatFast(lineTokens[1]),
Y = ParseFloatFast(lineTokens[2]),
Z = ParseFloatFast(lineTokens[3])
};
model.Vertices[verticesIterator] = vertex;
verticesIterator++;
break;
case "vt": // Texture Coordinate
Vector2 textureCoordinate = new Vector2
{
X = ParseFloatFast(lineTokens[1]), // U
Y = -ParseFloatFast(lineTokens[2]) // V (Inverted)
};
model.TexCoords[textureCoordinatesIterator] = textureCoordinate;
textureCoordinatesIterator++;
break;
case "vn": // Normal
Vector3 normal = new Vector3
{
X = ParseFloatFast(lineTokens[1]),
Y = ParseFloatFast(lineTokens[2]),
Z = ParseFloatFast(lineTokens[3])
};
model.Normals[normalsIterator] = normal;
normalsIterator++;
break;
case "f": // Face (Triangle indices)
for (int i = 0; i < 3; i++)
{
string[] parameters = SplitStringFast(lineTokens[i + 1], '/', IndiceBuffer);
FaceIndices indices = new FaceIndices
{
Vertex = ParseUInt32Fast(parameters[0]) - 1,
Texture = ParseUInt32Fast(parameters[1]) - 1,
Normal = ParseUInt32Fast(parameters[2]) - 1
};
VerticesIndexBuffer[i] = indices;
}
model.Faces[facesIterator] = new Face(VerticesIndexBuffer[0], VerticesIndexBuffer[1], VerticesIndexBuffer[2]);
facesIterator++;
break;
}
}
}
/// <summary>
/// A custom implementation of Int32.Parse. This
/// function is, on average, 5-6x faster than the one
/// offered by .NET. This function assumes that the string
/// given will yield a positive integer.
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
private static int ParseUInt32Fast(string value)
{
int result = 0;
for (int i = 0; i < value.Length; i++)
{
result = 10 * result + (value[i] - 48);
}
return result;
}
/// <summary>
/// A custom implementation of String.Split(). Realistically, this
/// function is not much faster than what .NET offers; it gains speed
/// more from a preset buffer mechanism.
/// </summary>
/// <param name="value"></param>
/// <param name="delimiter"></param>
/// <param name="buffer"></param>
/// <returns></returns>
private static string[] SplitStringFast(string value, char delimiter, string[] buffer)
{
int resultIndex = 0;
int startIndex = 0;
for (int i = 0; i < value.Length; i++)
{
if (value[i] == delimiter)
{
buffer[resultIndex] = value.Substring(startIndex, i - startIndex);
resultIndex++;
startIndex = i + 1;
}
}
buffer[resultIndex] = value.Substring(startIndex, value.Length - startIndex);
return buffer;
}
/// <summary>
/// A custom implementation of Float.Parse. This
/// function is, on average, 5-6x faster than the one
/// offered by .NET
/// </summary>
/// <param name="inputData">The inputData.</param>
/// <returns></returns>
private static float ParseFloatFast(string inputData)
{
float result = 0;
int position = 0;
int inputLength = inputData.Length;
char firstCharacter = inputData[0];
float negativeSign = 1;
if (firstCharacter == '-')
{
negativeSign = -1;
++position;
}
while (true)
{
if (position >= inputLength)
{
return negativeSign * result;
}
firstCharacter = inputData[position++];
if (firstCharacter < '0' || firstCharacter > '9')
{
break;
}
result = (float)((result * 10.0) + (firstCharacter - '0'));
}
float exponent = 0.1f;
while (position < inputLength)
{
firstCharacter = inputData[position++];
result += (firstCharacter - '0') * exponent;
exponent *= 0.1f;
}
return negativeSign * result;
}
/// <summary>
/// Renders the Model using deprecated immediate mode. This
/// function exists only for testing purposes.
/// </summary>
public void Render()
{
GL.Enable(EnableCap.Texture2D);
GL.Color3(Material.AmbientColor);
GL.BindTexture(TextureTarget.Texture2D, Material.Diffuse);
GL.Begin(PrimitiveType.Triangles);
for (int i = 0; i < Faces.Length; i++)
{
for (int index = 0; index < Faces[i].Indices.Length; index++)
{
Vector3 v = Vertices[Faces[i].Indices[index].Vertex];
Vector3 n = Normals[Faces[i].Indices[index].Normal];
Vector2 tc = TexCoords[Faces[i].Indices[index].Texture];
GL.Normal3(n.X, n.Y, n.Z);
GL.TexCoord2(tc.X, tc.Y);
GL.Vertex3(v.X, v.Y, v.Z);
}
}
GL.End();
}
}
}
Sorry for all the code, I just wanted to show you guys everything I was doing. Now, in my mind, deserialization SHOULD be faster than reparsing the model, creating the arrays, etc, etc, etc. So my question is really: why is deserializtaion NOT faster? Is there something that I could do better to make the roles shift, so that Deserialization becomes faster?
For starters try taking the creation of the binary formatter out of the inner loop. Note that "creating the arrays etc, etc, etc" will also be done by the BinaryFormatter when deserialising - there's no magic way to avoid isntantiating the object graph.
Also you could look into faster serialisers such as Protobuf-net. Check out http://maxondev.com/serialization-performance-comparison-c-net-formats-frameworks-xmldatacontractserializer-xmlserializer-binaryformatter-json-newtonsoft-servicestack-text/
I have a result dataset,
Dataset dsResult = new Dataset();
dsResult.Tables[0].Rows.Count = 17
Now i want to loop through data table for first 5 rows and create a dsResult.Tables[1]
and then next 5 more rows to dsResult.Tables[2]
and next 5 more to dsResult.Tables[3]
then last two rows to dsResult.Tables[4]
from below code i am getting number of tables required
decimal remainder = Decimal.Divide(dsResult.Tables[0].Rows.Count, 5);
var numberOfRequests = Math.Ceiling((decimal)remainder);
Or can we do it in SQL
How to genaralize this logic.
Please guide me here.
using Linq this is very simple
var firstFive = dsResult.Tables[0].AsEnumerable().Take(5);
var secondFive = dsResult.Tables[0].AsEnumerable().Skip(5).Take(5);
and so on.
Do not loop, let Linq do it for you.
If later you will need to convert results to a datatables MSDN has very good example on how to
Creating a DataTable From a Query (LINQ to DataSet)
Maybe helps, but I don't recommend use this solution in real project.
// size of chunk
int chunkSize = 5;
// dataset and table variables
DataSet ds = GetDataSet(); // get your DataSet from somewhere
DataTable source = ds.Tables[0], dest;
// total rows
int count = ds.Tables[0].Rows.Count;
int tableCount = (count + 1) / chunkSize;
// create tables (copy structure)
for (int i = 0; i < tableCount; i++)
{
dest = source.Clone();
dest.TableName = source.TableName + "_" + i.ToString();
ds.Tables.Add(dest);
}
// fill tables
int index = 0;
foreach (DataRow row in source.Rows)
{
dest = ds.Tables[1 + index++ / chunkSize];
// copy row (via copying item arrays)
DataRow rowCopy = dest.NewRow();
rowCopy.ItemArray = row.ItemArray;
dest.Rows.Add(rowCopy);
}
Another solution with ChunkReader<T> (class that slices list to parts with fixed length)
ChunkReader
using System;
using System.Collections.Generic;
using System.Linq;
namespace ServiceCore.Helpers
{
/// <summary>
/// чанкер
/// </summary>
public class ChunkReader<T>
{
#region Declarations
private List<T> _data; // данные
private int _pos; // позиция
#endregion
#region Properties
/// <summary>
/// число записей
/// </summary>
public int Count { get { return _data.Count; } }
/// <summary>
/// размер чанка
/// </summary>
public int ChunkSize { get; set; }
/// <summary>
/// число чанков
/// </summary>
public int ChunksCount
{
get
{
int count = _data.Count;
return count == 0 ? 0 : (int)Math.Ceiling((double)count / (double)ChunkSize);
}
}
#endregion
#region Constructors
/// <summary>
/// конструктор
/// </summary>
public ChunkReader()
{
ChunkSize = 20;
}
/// <summary>
/// конструктор
/// </summary>
/// <param name="data"> данные </param>
public ChunkReader(List<T> data)
: this()
{
Init(data);
}
/// <summary>
/// конструктор
/// </summary>
/// <param name="data"> данные </param>
/// <param name="chunkSize"> размер чанка </param>
public ChunkReader(List<T> data, int chunkSize)
: this()
{
ChunkSize = chunkSize;
Init(data);
}
#endregion
#region Private methods
#endregion
#region Protected methods
#endregion
#region Public methods
/// <summary>
/// инициализация
/// </summary>
/// <param name="data"> данные </param>
public void Init(List<T> data)
{
_data = data;
_pos = 0;
}
/// <summary>
/// сбросить текущую позицию
/// </summary>
public void Reset()
{
_pos = 0;
}
/// <summary>
/// прочитать очередной чанк
/// </summary>
/// <param name="chunk"> чанк </param>
/// <returns></returns>
public bool Read(out List<T> chunk)
{
int count = _data.Count;
if (_pos >= count)
{
chunk = null;
return false;
}
else
{
chunk = new List<T>();
int last = _pos + ChunkSize;
for (int i = _pos; i < count && i < last; i++, _pos++)
{
chunk.Add(_data[_pos]);
}
return true;
}
}
#endregion
}
}
Usage:
// create ChunkReader based on DataTable
var chunker = new ServiceCore.Helpers.ChunkReader<DataRow>(ds.Tables[0].Select().ToList(), 5); // 5 - size of chunk
List<DataRow> chunk;
while (chunker.Read(out chunk))
{
// do somethind with chunk of data rows
}
With LINQ you can acheive it in the following way,
int rowCountPerTable = 5; //Number of tables would be based on this
int currPos = 0;
DataTable dt = ds.Tables[0];
DataTable tempDt = dt.Clone();
dt.Rows.OfType<DataRow>().ToList().ForEach(x =>
{
currPos++;
tempDt.ImportRow(x);
if (currPos == rowCountPerTable)
{
currPos = 0;
tempDt.TableName = "Table" + (ds.Tables.Count + 1);
ds.Tables.Add(tempDt);
tempDt = dt.Clone();
}
else if ((dt.Rows.Count - 1) == dt.Rows.IndexOf(x))
{
tempDt.TableName = "Table" + (ds.Tables.Count + 1);
ds.Tables.Add(tempDt);
}
});
Hope this helps...
I have a need for a circular buffer (or other data structure), on which I can do a "ToArray" or similar call to get the current state of the buffer and use whilst the buffer carries on possibly overwriting the values held.
The reason for this use case is that the returned data is passed to a worker thread to process and the idea is to ensure that as little data is overwritten as possible in between the calls. The choice of a circular data structure was ostensibly to reduce the memory usage of the buffer to a fixed value.
I built the data structure below, which up until yesterday was sufficient for my needs. The relevant calls are TakeSnapshot, TakeAll and TakeWeakArraySnapshot which are all variations on the same theme.
The call is made quite frequently when about a 1000 samples of reference types are available.
All the calls result in an out of memory exception at some point. The exception is the TakeWeakArraySnapshot which basically reverts to null midway through using the array (something i guess is to do with the fact that the gc handle is weak?)
Is there a more suitable memory efficient data structure for this use or something I am doing wrong? Would changing the gc handle type to normal help. Is it possible to create a output type that wraps the references (like i attempted to with the weakreference) which would be easily be reclaimed by the garbage collector?
Thanks for reading.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Threading;
using System.Runtime.InteropServices;
public class WeakArray<T>
{
private GCHandle[] fArray;
public WeakArray(int length)
{
fArray = new GCHandle[length];
for (int i = 0; i < length; i++)
fArray[i] = GCHandle.Alloc(null, GCHandleType.Weak);
}
~WeakArray()
{
if (fArray == null)
return;
int count = fArray.Length;
for (int i = 0; i < count; i++)
{
GCHandle gcHandle = fArray[i];
if (!gcHandle.IsAllocated)
break;
gcHandle.Free();
}
}
public int Length
{
get
{
return fArray.Length;
}
}
public T this[int index]
{
get
{
return (T) fArray[index].Target;
}
set
{
fArray[index].Target = value;
}
}
}
public class OutputData<TDataType>:IEnumerable<TDataType>,IDisposable
{
private TDataType[] Buffer { get; set; }
private readonly object _lock = new object();
public OutputData(ref TDataType[] buffer,long length)
{
Buffer = buffer;
Length = length;
}
public long Length { get; private set; }
/// <summary>
/// Gets the <see cref="`0"/> at the specified index. Throws IndexOutOfRange for an invalid index
/// or returns the default value of the generic type on an empty queue
/// </summary>
/// <value>
/// The <see cref="`0"/>.
/// </value>
/// <param name="i">The item at that index.</param>
/// <returns></returns>
public TDataType this[int i]
{
get
{
lock (_lock)
{
return Length > 0 ? Buffer[i] : default(TDataType);
}
}
}
public IEnumerator<TDataType> GetEnumerator()
{
for (int i = 0; i < Length; i++)
{
yield return Buffer[i];
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Dispose()
{
Array.Clear(Buffer,0,Buffer.Length);
}
public void SetLength(int count)
{
Length = count;
}
}
/// <summary>
/// Implements a CircularBuffer that behaves as a queue
/// </summary>
/// <typeparam name="T"></typeparam>
public class FixedCapacityQueue<T>
{
private T[] _buffer;
private T[] _output;
private OutputData<T> _outputData;
/// <summary>
/// Gets the dropped count. This is the number of samples that have been dropped to
/// maintain the fixed size of the datastructure.
/// </summary>
/// <value>
/// The dropped count.
/// </value>
public int DroppedCount { get; protected set; }
/// <summary>
/// The default number of dropped items required to generate a report
/// </summary>
protected const int DroppedFramesBetweenReports = 1000;
/// <summary>
/// The _start. Index of the first element in buffer.
/// </summary>
private int _start;
/// <summary>
/// The _end. Index after the last element in the buffer.
/// </summary>
private int _end;
/// <summary>
/// The _size. Buffer size.
/// </summary>
private int _numberOfItemsInBuffer;
private readonly object _lock = new object();
/// <summary>
/// Gets or sets the name of the buffer.
/// </summary>
/// <value>
/// The name.
/// </value>
public string Name { get; protected set; }
private readonly T _default = default(T);
/// <summary>
/// Initializes a new instance of the <see cref="FixedCapacityQueue{T}" /> class.
/// </summary>
/// <param name="name">The name of the queue.</param>
/// <param name="bufferSize">Size of the buffer.</param>
public FixedCapacityQueue(string name, int bufferSize)
{
Contract.Requires(bufferSize > 0);
Contract.Requires(!String.IsNullOrEmpty(name));
_buffer = new T[bufferSize];
_output = new T[bufferSize];
_outputData = new OutputData<T>(ref _output, 0);
_start = 0;
_end = _numberOfItemsInBuffer == bufferSize ? 0 : _numberOfItemsInBuffer;
Name = String.Format("FixedCapacityQueue for {0}", name);
}
/// <summary>
/// Initializes a new instance of the <see cref="FixedCapacityQueue{T}" /> class.
/// </summary>
/// <param name="name">The nameof the buffer.</param>
/// <param name="bufferSize">Size of the buffer.</param>
/// <param name="data">The data to be added to the queue.</param>
/// <exception cref="System.ArgumentException"></exception>
public FixedCapacityQueue(string name, int bufferSize, ICollection<T> data)
: this(name, bufferSize)
{
Contract.Requires(data != null);
Contract.Requires(bufferSize > 0);
Contract.Requires(data.Count < bufferSize);
foreach (var dataItem in data)
{
Enqueue(dataItem);
}
}
/// <summary>
/// Gets a value indicating whether the queue [is empty].
/// </summary>
/// <value>
/// <c>true</c> if [is empty]; otherwise, <c>false</c>.
/// </value>
public bool IsEmpty
{
get
{
lock (_lock)
{
return _numberOfItemsInBuffer == 0;
}
}
}
/// <summary>
/// Gets a value indicating whether the queue [is full].
/// </summary>
/// <value>
/// <c>true</c> if [is full]; otherwise, <c>false</c>.
/// </value>
public bool IsFull
{
get
{
lock (_lock)
{
return Count == Size;
}
}
}
/// <summary>
/// Gets the number of items currently present in the queue.
/// </summary>
/// <value>
/// The count.
/// </value>
public int Count
{
get
{
lock (_lock)
{
return _numberOfItemsInBuffer;
}
}
}
/// <summary>
/// Gets the declared size of the queue.
/// </summary>
/// <value>
/// The size.
/// </value>
public int Size
{
get
{
lock (_lock)
{
return _buffer.Length;
}
}
}
/// <summary>
/// Dequeues an item from the queue. The expected behaviour is that if a Dequeue operation is
/// requested whilst a queue is empty, the default type of the generic queue is returned.
/// </summary>
/// <returns></returns>
public T Dequeue()
{
lock (_lock)
{
if (IsEmpty) return _default;
var item = _buffer[_start];
_buffer[_start] = _default;
Increment(ref _start);
--_numberOfItemsInBuffer;
return item;
}
}
/// <summary>
/// Enqueues the specified item to the queue.
/// </summary>
/// <param name="toAdd">To add.</param>
public void Enqueue(T toAdd)
{
lock (_lock)
{
if (IsFull)
{
_buffer[_end] = toAdd;
Increment(ref _end);
_start = _end;
DroppedCount++;
//report drops
if (DroppedCount >= DroppedFramesBetweenReports)
{
//EventAndErrorPump.Instance.WriteOnce(1000, ReportLevelEnum.Warning,
// String.Format("{0} FixedQueue Dropped Items: {1} ", Name, DroppedCount));
DroppedCount = 0;
}
}
else
{
_buffer[_end] = toAdd;
Increment(ref _end);
++_numberOfItemsInBuffer;
}
}
}
/// <summary>
/// Increments the provided index variable by one, wrapping
/// around if necessary.
/// </summary>
/// <param name="index"></param>
private void Increment(ref int index)
{
if (++index == Size)
{
index = 0;
}
}
/// <summary>
/// Decrements the provided index variable by one, wrapping
/// around if necessary.
/// </summary>
/// <param name="index"></param>
private void Decrement(ref int index)
{
if (index == 0)
{
index = Size;
}
index--;
}
public void Enqueue(IEnumerable<T> toAdd)
{
lock (_lock)
{
foreach (var dataItem in toAdd)
{
Enqueue(dataItem);
}
}
}
public IEnumerator<T> GetEnumerator()
{
var segments = new ArraySegment<T>[2] {ArrayOne(), ArrayTwo()};
foreach (ArraySegment<T> segment in segments)
{
for (int i = 0; i < segment.Count; i++)
{
yield return segment.Array[segment.Offset + i];
}
}
}
/// <summary>
/// Gets the at the specified index. Throws IndexOutOfRange for an invalid index
/// or returns the default value of the generic type on an empty queue. The head/earliest item index can also be
/// null in the event of a dequeue. If the front of the queue is required,please use the front function instead
/// </summary>
/// <param name="i">The item at that index.</param>
/// <returns></returns>
/// <exception cref="System.IndexOutOfRangeException"></exception>
public T this[int index]
{
get
{
lock (_lock)
{
if (IsEmpty)
{
return _default;
}
if (index >= _numberOfItemsInBuffer)
{
throw new IndexOutOfRangeException(string.Format("Cannot access index {0}. Buffer size is {1}",
index, _numberOfItemsInBuffer));
}
int actualIndex = InternalIndex(index);
return _buffer[actualIndex];
}
}
}
/// <summary>
/// Converts the index in the argument to an index in <code>_buffer</code>
/// </summary>
/// <returns>
/// The transformed index.
/// </returns>
/// <param name='index'>
/// External index.
/// </param>
private int InternalIndex(int index)
{
return _start + (index < (Size - _start) ? index : index - Size);
}
/// <summary>
/// Clears this instance.
/// </summary>
public void Clear()
{
lock (_lock)
{
_numberOfItemsInBuffer = 0;
_start = 0;
_end = 0;
}
}
/// <summary>
/// Takes a snapshot of the queue and returns it. If used in isolation .i.e not in a buffer implementation
/// it will return all the elements of the queue and leave the queue empty.
/// In a buffer implementation , since the buffer could be accepting data at the point of this call; it is a stale
/// snapshot of the queue when the call is made.
/// </summary>
/// <returns></returns>
[Obsolete("Use TakeAllData() instead")]
public T[] TakeSnapshot()
{
lock (_lock)
{
return TakeSnapshot(Count);
}
}
/// <summary>
/// Takes all data available in the queue.
/// </summary>
/// <returns></returns>
public OutputData<T> TakeAll()
{
var count = Count;
if (count <= 0) return null;
lock (_lock)
{
CopyInto(count, _output);
_outputData.SetLength(count);
return _outputData;
}
}
/// <summary>
/// Takes a snapshot of the queue using the count to limit the output to return. In the event that the specified
/// count is larger than the current size of the queue, it will throw an exception. A zero count value will immediately return
/// In a buffer implementation , since the buffer could be accepting data at the point of this call; it is a stale
/// snapshot of the queue when the call is made.
/// </summary>
/// <returns></returns>
[Obsolete("Use TakeAllData(int count) instead")]
public T[] TakeSnapshot(int count)
{
if (count == 0) return null;
lock (_lock)
{
if (count > _numberOfItemsInBuffer)
{
count = _numberOfItemsInBuffer;
//throw new ArgumentOutOfRangeException(String.Format("Queue size is {0}", Size));
}
var output = new T[count];
CopyInto(count, output);
return output;
}
}
private void CopyInto(int count, T[] output)
{
var lastIndex = (_start + count) - 1;
if (lastIndex >= Size)
{
Array.Copy(_buffer, _start, output, 0, Size - _start);
Array.Copy(_buffer, 0, output, Size - _start, (lastIndex%Size) + 1);
}
else
{
Array.Copy(_buffer, _start, output, 0, count);
}
_start = (_start + count)%Size;
_numberOfItemsInBuffer = _numberOfItemsInBuffer - count;
}
public T[] PeekSnapshot()
{
lock (_lock)
{
var count = Count;
var output = new T[count];
for (var i = 0; i < count; i++)
{
output[i] = this[i];
}
return output;
}
}
public T[] PeekSnapshot(int count)
{
if (count == 0) return null;
lock (_lock)
{
if (count > Size)
{
throw new ArgumentOutOfRangeException(String.Format("Queue size is {0}", Size));
}
var output = new T[count];
for (var i = 0; i < count; i++)
{
output[i] = this[i];
}
return output;
}
}
/// <summary>
/// Gets the front of the queue. The earliest item added to the queue.
/// Use this in lieu of checking this[0] as that could be null whilst items still
/// exist in the queue
/// </summary>
/// <value>
/// The front.
/// </value>
public T Front()
{
lock (_lock)
{
return IsEmpty ? _default : _buffer[_start];
}
}
/// <summary>
/// Gets the utilisation of the datastructure i.e % of the datastructure currently in use
/// </summary>
/// <value>
/// The utilisation.
/// </value>
public float Utilisation
{
get
{
lock (_lock)
{
return CalculateUtilisation();
}
}
}
private float CalculateUtilisation()
{
var util = 0f;
if (Size > 0)
{
util = (Count/(float) Size)*100;
}
return util;
}
/// <summary>
/// Returns the latest item in the queue.
/// </summary>
/// <returns></returns>
public T Back()
{
lock (_lock)
{
return Count > 0 ? _buffer[_end - 1] : _default;
;
}
}
public WeakArray<T> TakeWeakArraySnapshot()
{
lock (_lock)
{
var count = Count;
var arr = new WeakArray<T>(count);
for (var i = 0; i < count; i++)
{
arr[i] = Dequeue();
}
return arr;
}
}
/// <summary>
/// Gets the internal array. Use with EXTREME CAUTION! This is not a thread safe operation
/// and should ONLY be used in situations where any modification to the queue is not possible.
/// Modification operations include Enqueing or Dequeing
/// </summary>
/// <returns></returns>
public T[] GetInternalArray()
{
return _buffer;
}
// doing ArrayOne and ArrayTwo methods returning ArraySegment<T> as seen here:
// http://www.boost.org/doc/libs/1_37_0/libs/circular_buffer/doc/circular_buffer.html#classboost_1_1circular__buffer_1957cccdcb0c4ef7d80a34a990065818d
// http://www.boost.org/doc/libs/1_37_0/libs/circular_buffer/doc/circular_buffer.html#classboost_1_1circular__buffer_1f5081a54afbc2dfc1a7fb20329df7d5b
// should help a lot with the code.
#region Array items easy access.
// The array is composed by at most two non-contiguous segments,
// the next two methods allow easy access to those.
private ArraySegment<T> ArrayOne()
{
if (_start < _end)
{
return new ArraySegment<T>(_buffer, _start, _end - _start);
}
else
{
return new ArraySegment<T>(_buffer, _start, _buffer.Length - _start);
}
}
private ArraySegment<T> ArrayTwo()
{
if (_start < _end)
{
return new ArraySegment<T>(_buffer, _end, 0);
}
else
{
return new ArraySegment<T>(_buffer, 0, _end);
}
}
#endregion
}
Most data structure performance and efficiency comes down to the problem you are trying to solve.
I would recommend not to re-implement data structures yourself unless they don't exist already. Things like ngenerics exist exactly to solve those kind of problems.
This is just a sample project but I'm sure there is other types.