Does it make sense to store byte values in Map or it will still use 4 bytes? - dictionary

In Java in-memory there is no difference between byte or int - both will be represented as 4 bytes.
Does for Chronicle Map the difference exist, i.e. does Chronicle Map store byte values as 8 bits or still use 32?
Same question if byte is an object property.

In primitive map implementations (fastutil, koloboke, gs, hppc) byte values are implemented as a separate byte[] array, so they actually take only 1 byte. If a byte is a field of another on-heap Java object (which is a Map value), indeed, the object size is rounded up to 8-byte boundary, so a single byte field could "take" 8 bytes. But more often, it "takes" 0 bytes, because the field is placed in the already existing alignment holes.
For Chronicle Map, a value could freely be 1 byte in size. (And even 0 bytes, this is how ChronicleSet is currently implmeneted -- a ChronicleMap with 0-byte dummy values.) This is true for all Chronicle Map versions (2, 3).
Edit -- answer to the comment.
If you have a constantly sized structure e. g. 6 byte fields, easiest and efficient way - to use data value generation mechanishm:
interface MyValue {
byte getA(); void setA(byte a);
byte getB(); void setB(byte b);
byte getC(); void setC(byte c);
byte getD(); void setD(byte d);
byte getE(); void setE(byte e);
byte getF(); void setF(byte f);
}
map = ChronicleMapBuilder.of(Key.class, MyValue.class).entries(1000).create();
// Chronicle Map 2 syntax
MyValue value = DataValueClasses.newDirectReference(MyValue.class);
try (Closeable handle = map.getUsingLocked(key, value)) {
// access the value here
System.out.println(value);
}
// Chronicle Map 3 syntax
try (ExternalMapQueryContext<Key, MyValue, ?> q = map.queryContext(key)) {
// if not sure the key is present in the map, check q.entry() != null
MyValue value = q.entry().value().get();
// access the value here
System.out.println(value);
}
It will take exactly 6 bytes per value.

I think I know the response. At least at the version 2.3.8 offheap value will be 1 byte for a byte (work done in SerializationBuilder class).

Related

How to create an array of references to arrays?

I'm having some syntax troubles with my code. A bit of context...
My program has a schedule, it's an array of 24 bytes. There's one schedule per day, so 7 arrays.
I want to have a single array of 7 elements storing references to the above 7 arrays. This way, by calling schedules[1], I get schedule1[24], which is Monday.
// One schedule per day (0 = sunday)
byte schedule0[24];
byte schedule1[24];
byte schedule2[24];
byte schedule3[24];
byte schedule4[24];
byte schedule5[24];
byte schedule6[24];
byte * schedules[7] = {&schedule0, &schedule1};
The problem comes from the last line, the error being "a value of type "byte (*)[24]" cannot be used to initialize an entity of type "byte *" ".
I tried inserting [24] before or after the star/pointer character, with no luck.
Could any of you please show me the correct syntax to do this?
In C++, name of the array is the pointer to the first element in the array. So in your case schedule0 is a pointer to &schedule0[0] not &schedule0.
You can change the last line as
byte * schedules[2] = {&schedule0[0], &schedule1[0]}; or byte * schedules[2] = {schedule0, schedule1};
This will create a pointer array containing the base address of the scheduleX arrays.
I want to have a single array of 7 elements storing references to the above 7 arrays. This way, by calling schedules[1], I get schedule1[24], which is Monday.
A different approach is needed to index across days. This can be done using a two dimensional array and some pointer arithmetic.
Declare a two dimensional array for your schedules:
byte schedulesArray[7][24];
Declare pointers that point to the schedules for each day:
byte *schedule0 = &schedulesArray[0][0];
byte *schedule1 = &schedulesArray[1][0];
byte *schedule2 = &schedulesArray[2][0];
byte *schedule3 = &schedulesArray[3][0];
byte *schedule4 = &schedulesArray[4][0];
byte *schedule5 = &schedulesArray[5][0];
byte *schedule6 = &schedulesArray[6][0];
Declare a pointer to the first element of the two dimensional array:
byte *schedules = &schedulesArray[0][0];
So if we seed some data:
schedule0[0] = 1;
schedule1[0] = 11;
schedule1[1] = 12;
schedule2[0] = 21;
schedule2[1] = 22;
Then you can use the schedules pointer to index across days:
schedules[0]; // = 1
schedules[24]; // = 11
schedules[25]; // = 12
schedules[48]; // = 21
schedules[49]; // = 22
This works because multidimensional arrays are laid out as a contiguous block of memory.
Simply, you can't do it.
And here is explanation why:
Basically, a reference is an alias to an existing variable. This means, if you apply any operation on a reference, it will behave as if you were using the original variable name. And there are no references at a reference or pointer at references, references don't allocate any memory so there is nothing that you can use to put in an array.
What you can do is create an array of pointers and it will work.

How can a 1 byte int conversion of a QByteArray fail?

So here is the thing, I'm receiving 1 byte from Bluetooth transmission. When using QDebug I get this message:
The array with error has "\x06"
The line that fails is this:
bool ok = true;
int v = value.toInt(&ok,0);
Because ok has false. But I'm trying to wrap my head around the fact that, How can the conversion fail in the first place if the data represented in that byte (as a sequence of zeros and ones) will always have a valid integer representation. (one byte can always be represented as a int between -127 and 128). So I'm left with the question, how can the conversion fail?
Reading the documentation does not provide many clues as it does not say how the byte array will be interpreted.
QByteArray::toInt converts a string representation in the default C locale to an integer. That means to successfully convert the value in your example, your byte array must contain the string "0x06", which consists of 4 bytes.
To convert a single byte to an int, just extract it:
int i = value[0];
Type promotion will widen the char to an int

Computing the memory footprint (or byte length) of a map

I want to limit a map to be maximum X bytes. It seems there is no straightforward way of computing the byte length of a map though.
"encoding/binary" package has a nice Size function, but it only works for slices or "fixed values", not for maps.
I could try to get all key/value pairs from the map, infer their type (if it's a map[string]interface{}) and compute the length - but that would be both cumbersome and probably incorrect (because that would exclude the "internal" Go cost of the map itself - managing pointers to elements etc).
Any suggested way of doing this? Preferably a code example.
This is the definition for a map header:
// A header for a Go map.
type hmap struct {
// Note: the format of the Hmap is encoded in ../../cmd/gc/reflect.c and
// ../reflect/type.go. Don't change this structure without also changing that code!
count int // # live cells == size of map. Must be first (used by len() builtin)
flags uint32
hash0 uint32 // hash seed
B uint8 // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
buckets unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
nevacuate uintptr // progress counter for evacuation (buckets less than this have been evacuated)
}
Calculating its size is pretty straightforward (unsafe.Sizeof).
This is the definition for each individual bucket the map points to:
// A bucket for a Go map.
type bmap struct {
tophash [bucketCnt]uint8
// Followed by bucketCnt keys and then bucketCnt values.
// NOTE: packing all the keys together and then all the values together makes the
// code a bit more complicated than alternating key/value/key/value/... but it allows
// us to eliminate padding which would be needed for, e.g., map[int64]int8.
// Followed by an overflow pointer.
}
bucketCnt is a constant defined as:
bucketCnt = 1 << bucketCntBits // equals decimal 8
bucketCntBits = 3
The final calculation would be:
unsafe.Sizeof(hmap) + (len(theMap) * 8) + (len(theMap) * 8 * unsafe.Sizeof(x)) + (len(theMap) * 8 * unsafe.Sizeof(y))
Where theMap is your map value, x is a value of the map's key type and y a value of the map's value type.
You'll have to share the hmap structure with your package via assembly, analogously to thunk.s in the runtime.

OpenCL void pointer arithmetic - strange behavior

I have wrote an OpenCL kernel that is using the opencl-opengl interoperability to read vertices and indices, but probably this is not even important because I am just doing simple pointer addition in order to get a specific vertex by index.
uint pos = (index + base)*stride;
Here i am calculating the absolute position in bytes, in my example pos is 28,643,328 with a stride of 28, index = 0 and base = 1,022,976. Well, that seems correct.
Unfortunately, I cant use vload3 directly because the offset parameter isn't calculated as an absolute address in bytes. So I just add pos to the pointer void* vertices_gl
void* new_addr = vertices_gl+pos;
new_addr is in my example = 0x2f90000 and this is where the strange part begins,
vertices_gl = 0x303f000
The result (new_addr) should be 0x4B90000 (0x303f000 + 28,643,328)
I dont understand why the address vertices_gl is getting decreased by 716,800 (0xAF000)
I'm targeting the GPU: AMD Radeon HD5830
Ps: for those wondering, I am using a printf to get these values :) ( couldn't get CodeXL working)
There is no pointer arithmetic for void* pointers. Use char* pointers to perform byte-wise pointer computations.
Or a lot better than that: Use the real type the pointer is pointing to, and don't multiply offsets. Simply write vertex[index+base] assuming vertex points to your type containing 28 bytes of data.
Performance consideration: Align your vertex attributes to a power of two for coalesced memory access. This means, add 4 bytes of padding after each vertex entry. To automatically do this, use float8 as the vertex type if your attributes are all floating point values. I assume you work with position and normal data or something similar, so it might be a good idea to write a custom struct which encapsulates both vectors in a convenient and self-explaining way:
// Defining a type for the vertex data. This is 32 bytes large.
// You can share this code in a header for inclusion in both OpenCL and C / C++!
typedef struct {
float4 pos;
float4 normal;
} VertexData;
// Example kernel
__kernel void computeNormalKernel(__global VertexData *vertex, uint base) {
uint index = get_global_id(0);
VertexData thisVertex = vertex[index+base]; // It can't be simpler!
thisVertex.normal = computeNormal(...); // Like you'd do it in C / C++!
vertex[index+base] = thisVertex; // Of couse also when writing
}
Note: This code doesn't work with your stride of 28 if you just change one of the float4s to a float3, since float3 also consumes 4 floats of memory. But you can write it like this, which will not add padding (but note that this will penalize memory access bandwidth):
typedef struct {
float pos[4];
float normal[3]; // Assuming you want 3 floats here
} VertexData;

Convert ByteArray to Integer in Flex

Can someone shed some lights on how to convert ByteArray into int?
Thanks,
So to get a flavor of doing this, you can try this bit of code:
function test(){
var bytes:ByteArray = new ByteArray();
bytes.writeInt(0x00DDAA99); //create my byte array with int 14527129
bytes.position = 0; //move the postion to the start
var newInt:int = bytes.readInt(); //read the bytes from starting position
trace("new num: "+newInt); //print out the number
}
This code will first create a byte array and put an int into it. This is presumably where you need your code to start. This then makes the assumption that there are 4 bytes to read after the starting position which I have set to 0. It then reads the 4 bytes off the byte array into the queue. Note that if you do not have 4 bytes in your ByteArray or your position is not set correctly, your code will fail. Make sure you add the checks for those scenarios.
This code also assumes that the byte array is Big Endian. Make sure that if you have a byte array from another system, that you know which endian-ness the int value has. Change the endian value on your byte array if needed.

Resources