I'm trying to convert a BLE native Byte handling helper to Kotlin. In the process, I noticed that in
JAVA
myByteArray[offset] += (byte)(exponent & 0xFF);
it works as expected, but when converted to kotlin
KOTLIN
myByteArray[offset] += (exponent and 0x0F shl 4).toByte()
I get errors that an Integer is expected.
So I assume the
"+="
is my problem and causing an integer to be assumed.
So I have two questions.
1) What exactly does += do with bytes. I understand that
b += 1
is the equivelent of
b = (byte)(b + 1)
but what exactly is happening to the bytes. Is there shifting going on, or is it converting to an int, adding the values then back to a byte?
2) What is the equivelent in Kotlin and why is it failing in Kotlin. I also tried doing
myByteArray[offset] = myByteArray[offset] + (exponent and 0x0F shl 4).toByte()
For the record, this is converting an Integer value into a 32bit Float if you are curious. Not sure if that helps at all.
The full code if you are interested for this is:
mantissa = intToSignedBits(mantissa, 12)
exponent = intToSignedBits(exponent, 4)
myByteArray[offset++] = (mantissa and 0xFF).toByte()
myByteArray[offset] = (mantissa shr 8 and 0x0F).toByte()
myByteArray[offset] += (exponent and 0x0F shl 4).toByte() //hates this line
NOTE* It says
this
because I wrote it as a ByteArray extension, so think of this as the byteArray itself.
KOTLIN version of it (ERRORS)
JAVA version of it (NO ERRORS):
I desire more than just an answer, but I'll take it lol. I would like to understand a bit more of what is going on here so I can solve this on my own in the future as well. Thanks in advance to any who take the time to explain and help.
Also while we are on the subject ;).
private int unsignedByteToInt(byte b) {
return b & 0xFF;
}
why does this work in Java, but fail in Kotlin.
private fun unsignedByteToInt(b: Byte): Int {
return b and 0xFF
}
Gotta be honest, I'm tired of writing Java helper classes to handle bytes, so I'm trying to figure out the idioms of Kotlin byte handling. "and" seems to only have overloads for Ints and bytes are not treated as Ints in Kotlin.
So as a bonus question, if you can explain that one, I would also appreciate it.
I believe you should be using Byte#plus(Byte).
So in your case:
myByteArray[offset] = myByteArray[offset].plus((exponent and 0x0F shl 4).toByte())
.toByte() probably isn't necessary in this case, since plus() takes basically any number, but I'm not able to test it.
Did You notice that breaking down your statement works?
val newBytes = (myByteArray[offset]+(exponent and 0x0F shl 4)).toByte()
myByteArray[offset] = newBytes
Main culprit of this behavior is plus operator signature. Those are all the overloads of plus for Byte:
/** Adds the other value to this value. */
public operator fun plus(other: Byte): Int
/** Adds the other value to this value. */
public operator fun plus(other: Short): Int
/** Adds the other value to this value. */
public operator fun plus(other: Int): Int
/** Adds the other value to this value. */
public operator fun plus(other: Long): Long
/** Adds the other value to this value. */
public operator fun plus(other: Float): Float
/** Adds the other value to this value. */
public operator fun plus(other: Double): Double
None of those return a Byte and there are no overloads of plusAssign, so they are implicitly created.
First it performs plus(Byte) returning Int then tries assignment, but it requires a Byte so it causes your error.
Related
I have an app in which gives you a certain photo based on an integer being fetched via
class RandomImageLogic(){
fun retrive(): Int{
return (1..9).random()
}
}
However, it is not professional to have a repeated outcome, as I desire a random integer to be fetched each time I call the function in order for the image to be different each time my button is pressed. How can I fetch a new random integer whenever the button calls the function?
The easy way is to pass in the last random number you received and filter it out.
fun retrive(except: Int): Int{
return ((1..9).filter {it != except}).random();
}
In your case, this method might not be called extremely often (only when the user clicks a button).
If this method was to be called more often, filter on an IntRange should be used with care (as proposed in #avalerio's answer).
This iterates the whole range (unnecessarily costing time) and it would create a temporary ArrayList on every call (creating unnecessary garbage and triggering the garbage collector more often than needed).
Here is a sample object NonRepeatingRandom (you can also implement it as a class if you wish). retrieve (which has been expanded with a max parameter and basic sanity checks) recursivly calls itself again if the same number would be generated twice in a row:
object NonRepeatingRandom {
private var previous = -1
fun retrieve(max : Int = 9): Int {
if(max < 0) {
error("Only positive numbers")
}
if(max <= 1) {
// There is nothing random about 0 or 1, do not check against previous, just return
previous = max
return max
}
val rand = (1..9).random()
return if(rand == previous) {
retrieve(max) // recursive call if two subsequent retrieve() calls would return the same number
} else {
previous = rand // remember last random number
rand
}
}
}
fun main(args: Array<String>) {
repeat(1000) {
println(NonRepeatingRandom.retrieve())
}
}
I made a quick-and-dirty performance test, calling my "recursive" method 10 million times and calling the "filter" method 10 million times.
Recursive: 125 ms (10 mio calls)
Filter: 864 ms (10 mio calls)
Pre-fill & random shuffle approach:
class RandomIntIterator(
private val range: IntRange
) : Iterator<Int> {
private lateinit var iterator: Iterator<Int>
init { randomize() }
fun randomize() {
iterator = range.shuffled().iterator()
}
override fun hasNext() = iterator.hasNext()
override fun next() = iterator.next()
}
...
val rnd = RandomIntIterator(1..9)
...
// on button click
if (rnd.hasNext()) {
val num = rnd.next()
// use num
} else {
// renew (if needed)
rnd.randomize()
}
I like using Sequences to generate unending streams of values.
In this case we'll have to write custom code, as checking for repeated values is a stateful operation, and while Sequences has a distinct() stateful filter, it applies to all generated values - we only want it to apply to a limited window.
TL;DR:
class RandomImageLogic(
private val random: Random,
/** The number of sequential values that must be distinct */
noRepeatsLimit: Int = 2
) {
private val sourceValues: List<Int> = (0..9).toList()
private fun nextValue(vararg exclusions: Int): Int =
(sourceValues - exclusions.asList()).random(random)
private val randomInts: Iterator<Int> =
generateSequence({
// the initial value just has one random int
val next = nextValue()
ArrayDeque(listOf(next))
}) { previousValues ->
// generate the next value, excluding previous values
val nextValue = nextValue(*previousValues.toIntArray())
// limit the size of previousValues, if necessary
if (previousValues.size >= noRepeatsLimit)
previousValues.removeLastOrNull()
// add the generated value to the beginning of the deque
previousValues.addFirst(nextValue)
previousValues
}
.map {
// convert the Sequence to a list of ints,
// each element is the first item in the deque
it.first()
}
.iterator()
fun retrieve(): Int {
return randomInts.next()
}
}
Testing
Let's write a test first, to make sure our solution works. Kotest has a specific property based testing subproject, and this will let us cover a wide range of test cases very quickly.
So, I ran through the setup, and started setting up the test case.
Seeding RandomImageLogic
First I modified the RandomImageLogic class so that the random selection could be seeded with a provided Random.
import kotlin.random.Random
class RandomImageLogic(private val random: Random) {
fun retrieve(): Int {
return (1..9).random(random = random)
}
}
This will help us to create a Generator for the RandomImageLogic.
Testing all values
Now we can use Kotest to write a property-based test that will assert "for all sequential values, they are different"
import io.kotest.core.spec.style.FunSpec
import io.kotest.property.arbitrary.arbitrary
import io.kotest.property.forAll
class RandomImageLogicTest: FunSpec({
// This generator will create a new instance of `RandomImageLogic`
// and generate two sequential values.
val sequentialValuesArb = arbitrary { rs ->
val randomImageLogic = RandomImageLogic(rs.random)
val firstValue = randomImageLogic.retrieve()
val secondValue = randomImageLogic.retrieve()
firstValue to secondValue
}
test("expect sequential values are different") {
forAll(sequentialValuesArb) { (firstValue, secondValue) ->
firstValue != secondValue
}
}
})
Of course, the test fails.
Property failed after 4 attempts
Arg 0: (1, 1)
Repeat this test by using seed 1210584330919845105
Caused by org.opentest4j.AssertionFailedError: expected:<true> but was:<false>
So let's fix it!
Generating Sequences
As I said earlier, I really like Sequences. They're perfect for this use-case, where we have an infinite source of values.
To demonstrate how to make a Sequence, let's convert the existing code, and use an Iterator to fetch values.
class RandomImageLogic(private val random: Random) {
private val randomInts =
// generate a sequence using values from this lambda
generateSequence { (1..9).random(random = random) }
// use an iterator to fetch values
.iterator()
fun retrieve(): Int {
return randomInts.next()
}
}
This hasn't solved the problem yet - the Sequence only generates and provides one value at a time and so cannot do any filtering. Fortunately generateSequence() has an variant with nextFunction: (T) -> T?, where we can determine the next value based on the previous value.
If we use this constructor, and do a bit of refactoring to share the source values, and a util method to generate a next value while filtering out previous values...
private val sourceValues: List<Int> = (0..9).toList()
private fun nextValue(vararg exclusions: Int): Int =
(sourceValues - exclusions.asList()).random(random)
private val randomInts: Iterator<Int> =
generateSequence({ nextValue() }) { previousValue ->
nextValue(previousValue)
}
.iterator()
and now if we run the test, it passes!
Test Duration Result
expect sequential values are different 0.077s passed
Improvement: more than two distinct sequential values
What happens if you don't just want two sequential values to be distinct, but 3? Or even more? Let's make the 'no-repeated-values' limit configurable, and I think this will demonstrate why Sequences are a good solution.
class RandomImageLogic(
private val random: Random,
/** The number of sequential values that must be distinct */
noRepeatsLimit: Int = 2
) {
// ...
}
Testing
Once again, let's write a test to make sure things work as expected.
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.collections.shouldHaveSize
import io.kotest.matchers.collections.shouldNotContainDuplicates
import io.kotest.property.Arb
import io.kotest.property.arbitrary.int
import io.kotest.property.checkAll
import kotlin.random.Random
class RandomImageLogicTest : FunSpec({
test("expect arbitrary sequential values are different") {
checkAll(Arb.int(), Arb.int(1..10)) { seed, noRepeatsLimit->
val randomImageLogic = RandomImageLogic(Random(seed), noRepeatsLimit)
val result = List(noRepeatsLimit) { randomImageLogic.retrieve() }
withClue("Result: $result") {
result shouldHaveSize noRepeatsLimit
result.shouldNotContainDuplicates()
}
}
}
})
And of course the test fails.
Property test failed for inputs
0) -459964888
1) 5
Caused by java.lang.AssertionError: Result: [3, 8, 0, 2, 8]
Collection should not contain duplicates
There's lots of options to make a Sequence stateful - again let's just look at one.
Sequence of values
Instead of a sequence of individual values, we can have a sequence where each element is a list of not only the current value, but also previously seen values.
Let's use ArrayDeque to store these values, because it's easy to add and remove values from the start and end.
Again, we use the same generateSequence constructor with a seedFunction and nextFunction - except this time each element is deque which stores all values, and in nextFunction we add new values to the start of the deque, trimming it if it's larger than the window size noRepeatsLimit
private val randomInts: Iterator<Int> =
generateSequence({
// the initial value just has one random int
val next = nextValue()
ArrayDeque(listOf(next))
}) { previousValues ->
// generate the next value, excluding previous values
val nextValue = nextValue(*previousValues.toIntArray())
// limit the size of previousValues, if necessary
if (previousValues.size >= noRepeatsLimit)
previousValues.removeLastOrNull()
// add the generated value to the beginning of the deque
previousValues.addFirst(nextValue)
previousValues
}
.map {
// convert the Sequence to a list of ints,
// each element is the first item in the deque
it.first()
}
.iterator()
And yup, the test passes!
Test Duration Result
expect arbitrary sequential values are different 0.210s passed
Storing state
It's important to think about how state will be stored. 'State' is required by RandomImageLogic to know whether a generated value is distinct.
In the Sequence implementation, it's stored internally, and so is specifically associated with an instance of RandomImageLogic. Maybe your application only has one instance of RandomImageLogic at any one time, in which case the state will always be up to date and will be shared between all invocations.
But what happens if there's more than one instance of RandomImageLogic? Or if there's multi-threading? Or if the RandomImageLogic instance is recreated?
The answers to these depend on the implementation and situation. From your question I suspect that it's not critically important that images never repeat, but I bring this up because it is important to think about.
In Android-Kotlin I am getting float number from backend (for example num = 10000000.47)
When I try to String.format it and add that number in my balanceTextview it shows it with exponent (something like 1.0E10).
I want to show number normally without exponent and with 2 decimals. (Without presicion loss!)
Tried to use DecimalFormat("#.##") but it didn't help me. Maybe I'm doing something wrong?
num = 10000000.47f
val dec = DecimalFormat("#.##")
var result = dec.format(num)
my result is: 10000000
It losts my decimal places
The issue is your number type. According to the documentation:
For variables initialized with fractional numbers, the compiler infers the Double type. To explicitly specify the Float type for a value, add the suffix f or F. If such a value contains more than 6-7 decimal digits, it will be rounded.
With an example that shows how information may get lost:
val pi = 3.14 // Double
val e = 2.7182818284 // Double
val eFloat = 2.7182818284f // Float, actual value is 2.7182817
If the value is specified as Double instead of Float, i.e.
val num = 10000000.47
instead of
val num = 10000000.47f
then your approach works as expected, but could be shortened to:
"%.2f".format(num)
(note that the shorter version will also print "100" as "100.00" which is different from your approach but potentially still desired behaviour)
If you receive a Float from the backend then the information is already lost on your side. Otherwise you should be able to fix the issue by improved parsing.
The extension function format is only available in the JVM. In Kotlin/native, you can use this instead:
fun Float.toPrecision(precision: Int) =
this.toDouble().toPrecision(precision)
fun Double.toPrecision(precision: Int) =
if (precision < 1) {
"${this.roundToInt()}"
} else {
val p = 10.0.pow(precision)
val v = (abs(this) * p).roundToInt()
val i = floor(v / p)
var f = "${floor(v - (i * p)).toInt()}"
while (f.length < precision) f = "0$f"
val s = if (this < 0) "-" else ""
"$s${i.toInt()}.$f"
}
I am getting response from server in string format like
V1YYZZ0x0000010x0D0x00112050x0C152031962061900x0D410240x0E152031962061900x0F410240x1021TATADOCOMOINTERNET101
Then I am converting it in to byte array because i need to get value from this byte by byte.
I tried to use
Arrays.copyOfRange(original,
from , to);
but it work on index basis not on byte basis.
I also tried following solution but it also truncating String(if I use string instead of byte[]) on length basis.
public static String truncateWhenUTF8(String s, int maxBytes) {
int b = 0;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
// ranges from http://en.wikipedia.org/wiki/UTF-8
int skip = 0;
int more;
if (c <= 0x007f) {
more = 1;
} else if (c <= 0x07FF) {
more = 2;
} else if (c <= 0xd7ff) {
more = 3;
} else if (c <= 0xDFFF) {
// surrogate area, consume next char as well
more = 4;
skip = 1;
} else {
more = 3;
}
if (b + more > maxBytes) {
return s.substring(0, i);
}
b += more;
i += skip;
}
return s;
}
I know how to calculate string in byte length but it giving only full string length in byte like
Here is how I need to extract packet on byte basis.
Above codes and parameters is only example. I need to get byte by byte from string/byte array.
I searched lot but didn't get any solution or link which I can refer. I am not getting how to split string using byte length because I know byte length for each parameter and for value also.
Please give me any reference or hint.
To determine what is equal to one byte in a String is not trivial. Your String contains bytes in hexadecimal text form: 0x0D (one byte, equal to 13), but also contains values as substrings. For example 1024 can be interpreted as an integer which in this case fits into 2 bytes, but could also be interpreted as a text made up by 4 chars, totaling to 8 bytes.
Anyways, I would split the string using a regular expression, and then further split the parts to length and value:
String message = "V1YYZZ0x0000010x0D0x00112050x0C152031962061900x0D41024"+
"0x0E152031962061900x0F410240x1021TATADOCOMOINTERNET101";
String regex = "(0)(x)(\\w\\w)";
String[] parts = message.split(regex);
Log.d(TAG,"HEADER = "+parts[0]);
for (int i=1; i<parts.length; i++) {
String s = parts[i];
// Only process if it has length > 0
if (s.length()>0) {
String len = "", val = "";
// String s is now in format LVVVV where L is the length, V is the value
if (s.length() < 11) {
// 1 character indicates length, up to 9 contains value
len = s.substring(0, 1);
val = s.substring(1);
} else if (s.length() > 10) {
// 2 characters indicate length, up to 99 contains value
len = s.substring(0, 2);
val = s.substring(2);
} else if (s.length() > 101) {
// 3 characters indicate length, up to 999 contains value
len = s.substring(0, 3);
val = s.substring(3);
}
Log.d(TAG, "Length: " + len + " Value: " + val);
}
}
This produces the following output:
D/Activity: HEADER = V1YYZZ
D/Activity: Length: 0 Value: 001
D/Activity: Length: 1 Value: 1205
D/Activity: Length: 15 Value: 203196206190
D/Activity: Length: 4 Value: 1024
D/Activity: Length: 15 Value: 203196206190
D/Activity: Length: 4 Value: 1024
D/Activity: Length: 21 Value: TATADOCOMOINTERNET101
Then you can check the packages (the first two package in the header is not needed), convert Strings to whatever you would like (e.g. Integer.parseInt(val))
If you explain the structure of the header (V1YYZZ0x0000010x0D0x0011205), I can improve my answer to find the message count.
I think it is doable with Scanner
import java.util.Scanner;
public class Library {
public static void main(String[] args) {
String s = "V1YYZZ0x0000010x0D0x001120"
+ "50x0C152031962061900x0D410240x0E152031962061900x0F410240x1"
+ "021TATADOCOMOINTERNET101";
// Skip first 9? bytes. I'm not sure how you define them
// so I just assumed it is 26 chars long.
s = s.substring(26, s.length());
System.out.println(s);
Scanner scanner = new Scanner(s);
// Use byte as delimiter i.e. 0xDC, 0x00
// Maybe you should use smth like 0x[\\da-fA-F]{2}
// And if you want to know that byte, you should use
// just 0x and get first 2 chars later
scanner.useDelimiter("0x\\w{2}");
// Easily extracted
int numberOfParams = scanner.nextInt();
for (int i = 0; i < numberOfParams; i++) {
String extracted = scanner.next();
// Length of message
int l = extracted.length();
boolean c = getLength(l) == getLength(l - getLength(l));
l -= getLength(l);
l = c ? l : l-1;
System.out.println("length="
+ extracted.substring(0, extracted.length()-l));
System.out.println("message="
+ extracted.substring(extracted.length()-l, extracted.length()));
}
// close the scanner
scanner.close();
}
// Counting digits assuming number is decimal
private static int getLength(int l) {
int length = (int) (Math.log10(l) + 1);
System.out.println("counted length = " + length);
return length;
}
}
We definitely need more information about rules, how string is formed. And what exactly you need to do. This code might be good enough you. And without comments it is really short and simple.
This is not a answer to accessing a byte array byte by byte, but is an answer for the situation in which you find yourself.
Your explanation and description have the appearance of being confused as to what it is that you are really getting from the server (e.g. it is quite hard to represent "V1YYZZ0x0000010x0D0x001120" as a 9 byte field (note it probably ends on the 2, not the 0)). Alternately, that you are using the wrong method to get it from the server, or not getting it as the intended data type.
Your code indicates that you believe that what you are getting is a UTF8 string. The data shown in your question does not appear to indicate that it is intended to be in that format.
Keep in mind when doing something like this that some other programmer had to create structure for the data that you are seeing. They had to define it somewhere with the intent that it be able to be decoded by their intended recipients. Unless there are other considerations (security, minimal bandwidth, etc.), such formats are usually defined in a way that is both easy to encode and decode.
The existence of the multiple "0x"-ASCII-encoded hexadecimal numbers --particularly the single byte representing the parameter (called "varam" in your graphic)-- strongly implies that this data was intended to be interpreted as a ASCII encoded string. While that might not be the case, it should be kept in mind when looking at the problem from a larger perspective.
You are having to put too much effort into decoding the information you are getting from the server. It, probably, should be relatively easy unless there are considerations why it would have intentionally been made difficult.
All of this indicates that the real problem exists in an area for which you have provided us with no information.
Step back:
Think about things like:
How are you receiving this from the server (what function/interface)?
In the call requesting the information from the server is there a way to specify the encoding type be bytes, an ASCII string, or some other format that is easier to deal with than UTF8? At a minimum, it appears to be clear that the data was not intended to be handled as a UTF8 string. There should be a way for you to get it without it having been converted to UTF8.
Also, you should try to find an actual specification for the format of the data. You have not explained much about the source, so it may be you are reverse-engineering something and have no access to specifications.
Basically, it looks like this is a problem where it might be a good idea to step back and ask if you are starting from the point that makes it easiest to solve and if you are headed in the right direction for doing so.
I'm sure I'm missing something obvious...
String.getBytes();
And if you want to process it in order taking defined objects from the array, just wrap using
ByteBuffer.wrap();
The result being something along the lines of:
String s = "OUTPUT FROM SERVER";
byte[] bytes = s.getBytes();
ByteBuffer bb = ByteBuffer.wrap(bytes);
What did I miss from the initial question? :/
I am currently making an android application which accepts bluetooth measurement from a device. The way the data is packaged is in 4 bytes. I need to get two values out of these bytes.
First value is made up of: 6bit and 7bit of first byte and bit 0 to bit 6 of byte 2
Second values is simpler and consists of the full 3rd byte.
What is a good way to access these bit values, combine them and convert them to integer values? Right now i'm trying to convert from byte array to bitset, and then access individual bits to create new bytes that would then be converted to a integer.
Thanks, and please ask if I am not being clear enough.
I figured it out: I converted the byte array to int using this method
public static int byteArrayToInt(byte[] b, int offset) {
int value = 0;
for (int i = 0; i < 4; i++) {
int shift = (4 - 1 - i) * 8;
value += (b[i + offset] & 0x000000FF) << shift;
}
return value;
}
Then I used the method pokey described. Thanks for your help!
im not sure if i understood your format correctly.
Does this bitmask correspond to your first value?
0xC07F0000
That is bits 16-22,30,31 (zero based indexing used here, i.e. bit 31 is last bit).
Another thing, is your value expected to be signed or unsigned?
Anyway, if it is the way i assume then you can convert it like this with some bitmasks:
unsigned int val = 0xdeadbeef;
unsigned int mask1 = 0xC0000000;
unsigned int mask2 = 0x007F0000;
unsigned int YourValue = (val&mask1)>>23 | (val&mask2)>>16;
Do that in the same way with your other values. Define a bitmask and shift it to the right. Done.
Cheers
This is a performance critical part of my android application, and I am using the NDK (c) to process a large bitmap array.
int blender(const char* blendMode, int c1, int c2, int amount){
int sob, sog, sor, soa, dsr, dsg, dsb, dsa = 0;
dsr = Argb_GetRed(c1);
dsg = Argb_GetGreen(c1);
dsb = Argb_GetBlue(c1);
dsa = Argb_GetAlpha(c1);
sor = Argb_GetRed(c2);
sog = Argb_GetGreen(c2);
sob = Argb_GetBlue(c2);
soa = Argb_GetAlpha(c2);
int src_alpha, mix_alpha, dst_alpha;
src_alpha = soa * ((255 * amount) / 100) >> 8;
if (!strcmp(blendMode, "normal")) {
PSD_BLEND_NORMAL(dsr, sor, mix_alpha);
PSD_BLEND_NORMAL(dsg, sog, mix_alpha);
PSD_BLEND_NORMAL(dsb, sob, mix_alpha);
}
else if (!strcmp(blendMode, "exclusion")) {
mix_alpha = soa / 255;
//.... it's not always just the 3 macros
PSD_BLEND_EXCLUSION(dsr, sor, mix_alpha);
PSD_BLEND_EXCLUSION(dsg, sog, mix_alpha);
PSD_BLEND_EXCLUSION(dsb, sob, mix_alpha);
}
~~~~~~~~~ X 20 or so blend modes ~~~~~~~~~~~~
}
Currently it's running this blender function on every pixel, and doing a switch (clearly inefficient)
also, it has to take the original command as a string (From json, and passed down through java)
I can think of a couple ways to make it more efficient, but they all involve writing 2 giant switch statements. I would prefer to use 1 switch statement, or lookup if possible
Thank you!
Pretty nasty problem but I got a "hackish" idea.
If the 'blendMode' names are chosen nicely, you could compare only the first two (or three) letters of the strings. If there are multiple strings with same first letters, you could make a special case and compare first and third letter and so on.
This trick would make the code a lot faster than calling strcmp() all the time. Also inlining the compare function might help too.
Here is some code:
/* compares first two letters of the string */
inline int fast_cmp(const char *mode, const char *cmp) {
return (mode[0] == cmp[0] && mode[1] == cmp[1]) ? 1 : 0;
}
if( fast_cmp(blendMode, "no") ); /* for "normal" */
if( fast_cmp(blendMode, "ex") ); /* for "exclusion" */
In action: http://ideone.com/OiXS0
Ofcourse the comparisons could be written directly into if / else statements but it might get confusing. This can be fixed with small and nifty macro:
#define FAST_CMP(x, y) x[0] == y[0] && x[1] == y[1]
And here is the macro in action: http://ideone.com/NQFwW
This macro version is perhaps the fastest way to do the comparison.