I'm in a tricky situation where I have a very large memory represented by an UnsafeBufferPointer, and I need to represent it as an Array. Now, the Swift standard library offers an initializer that copies elements from any given sequence, however it offers no way to directly provide the underlying storage.
Is there any way I can 'cast' an UnsafeBufferPointer to an Array while avoiding copying?
struct UnsafeBufferPointer<Element> { ... }
A non-owning pointer to buffer of Elements stored contiguously in
memory, presenting a Collection interface to the underlying elements.
The answer is no, it is impossible.
init(start: UnsafePointer<Element>, count: Int)
Construct an UnsafePointer over the count contiguous Element instances
beginning at start.
The constructor doesn't copy anything anywhere. The constructor doesn't create any memory allocation
Related
I know that accessing something from an array takes O(1) time if it is of one type using mathematical formula array[n]=(start address of array + (n * size Of(type)), but Assume you have an array of objects. These objects could have any number of fields including nested objects. Can we consider the access time to be constant?
Edit- I am mainly asking for JAVA, but I would like to know if there is a difference in case I choose another mainstream language like python, c++, JavaScript etc.
For example in the below code
class tryInt{
int a;
int b;
String s;
public tryInt(){
a=1;
b=0;
s="Sdaas";
}
}
class tryobject{
public class tryObject1{
int a;
int b;
int c;
}
public tryobject(){
tryObject1 o=new tryObject1();
sss="dsfsdf";
}
String sss;
}
public class Main {
public static void main(String[] args) {
System.out.println("Hello World!");
Object[] arr=new Object[5];
arr[0]=new tryInt();
arr[1]=new tryobject();
System.out.println(arr[0]);
System.out.println(arr[1]);
}
}
I want to know that since the tryInt type object should take less space than tryobject type object, how will an array now use the formula array[n]=(start address of array + (n * size Of(type)) because the type is no more same and hence this formula should/will fail.
The answer to your question is it depends.
If it's possible to random-access the array when you know the index you want, yes, it's a O(1) operation.
On the other hand, if each item in the array is a different length, or if the array is stored as a linked list, it's necessary to start looking for your element at the beginning of the array, skipping over elements until you find the one corresponding to your index. That's an O(n) operation.
In the real world of working programmers and collections of data, this O(x) stuff is inextricably bound up with the way the data is represented.
Many people reserve the word array to mean a randomly accessible O(1) collection. The pages of a book are an array. If you know the page number you can open the book to the page. (Flipping the book open to the correct page is not necessarily a trivial operation. You may have to go to your library and find the right book first. The analogy applies to multi-level computer storage ... hard drive / RAM / several levels of processor cache)
People use list for a sequentially accessible O(n) collection. The sentences of text on a page of a book are a list. To find the fifth sentence, you must read the first four.
I mention the meaning of the words list and array here for an important reason for professional programmers. Much of our work is maintaining existing code. In our justifiable rush to get things done, sometimes we grab the first collection class that comes to hand, and sometimes we grab the wrong one. For example, we might grab a list O(n) rather than an array O(1) or a hash O(1, maybe). The collection we grab works well for our tests. But, boom!, performance falls over just when the application gets successful and scales up to holding a lot of data. This happens all the time.
To remedy that kind of problem we need a practical understanding of these access issues. I once inherited a project with a homegrown hashed dictionary class that consumed O(n cubed) when inserting lots of items into the dictionary. It took a lot of digging to get past the snazzy collection-class documentation to figure out what was really going on.
In Java, the Object type is a reference to an object rather than an object itself. That is, a variable of type Object can be thought of as a pointer that says “here’s where you should go to find your Object” rather than “I am an actual, honest-to-goodness Object.” Importantly, the size of this reference - the number of bytes used up - is the same regardless of what type of thing the Object variable refers to.
As a result, if you have an Object[], then the cost of indexing into that array is indeed O(1), since the entries in that array are all the same size (namely, the size of an object reference). The sizes of the objects being pointed at might not all be the same, as in your example, but the pointers themselves are always the same size and so the math you’ve given provides a way to do array indexing in constant time.
The answer depends on context.
It's really common in some textbooks to treat array access as O(1) because it simplifies analysis.
And in fairness it is O(1) cpu instructions in today's architectures.
But:
As the dataset gets larger tending to infinity, it doesn't fit in memory. If the "array" is implemented as a database structure spread across multiple machines, you'll end up with a tree structure and probably have logarithmic worst case access times.
If you don't care about data size going to infinity, then big O notation may not be the right fit for your situation
On real hardware, memory accesses are not all equal -- there are many layers of caches and cache misses cost hundreds or thousands of cycles. The O(1) model for memory access tends to ignore that
In theory work, random access machines access memory in O(1), but turing machines cannot. Hierarchical cache effects tend to be ignored. Some models like transdichotomous RAM try to account for this.
In short, this is a property of your model of computation. There are many valid and interesting models of computation and what to choose depends on your needs and your situation.
In general. array denotes a fixed-size memory range, storing elements of the same size. If we consider this usual concept of array, then if objects are members of the array, then under the hood your array stores the object references and referring the i'th element in your array you find the reference of the object/pointer it contains, with an O(1) complexity and the address it points to is something the language is to find.
However, there are arrays which do not comply to this definition. For example, in Javascript you can easily add items to the array, which makes me think that in Javascript the arrays are somewhat different from an allocated fixed-sized range of elements of the same size/type. Also, in Javascript you can add any types of elements to an array. So, in general I would say the complexity is O(1), but there are quite a few important exceptions from this rule, depending on the technologies.
I have a pointer to a trie of structs that gradually increases in size, so I realloc when needed. After a certain point, realloc returns a new address, and moves the structs. The issue though, is that within the structs are more pointers, which point to the address of another struct within the block. When the block gets shifted to a new address, the pointers addresses stay the same, so now all point to invalid locations within the original block.
Is there a good way to mitigate this issue? All I can think of is instead of storing pointers in the struct, is to store an offset value to direct a pointer to the next struct. This is do-able, but I imagine there must be some form of normal operation people do in this case, as this situation surely isnt that uncommon?
Otherwise, having a pointer within an allocated block that points to another address within that block is pretty useless if used with realloc
There's no in-built solution, because the general use case for realloc() is to increase the size of some opaque content while it's being used by its "owner." The runtime doesn't know who has referenced it or what's hiding in some other chunk of dynamic memory, so all the references need to be updated manually.
Unfortunately, the way you describe your program's architecture in the comments, even the most traditional approach (build a hash table--or equivalent data structure--that maps "handles" or other fake pointers to real pointers) won't get you very far, because it sounds like you'd still need to search through memory and rebuild the entire table every time.
If you're married to allocating memory for all of the objects at once, your best bet is probably going to be to host your list inside of an array (or memory that you treat like an array), using the array indices instead of your pointers.
That said, since the worry you mention in the comments is deallocating a linked list, just bite the bullet and do that manually. Deallocating is only marking the space available, so even thousands of elements aren't going to take much time and nobody is ever going to care if the program is a little bit slow on exit, even if you have billions of elements.
At its most basic, if you only have one linked list of structures you only need to know the address of the first structure and the address of the structure that you're currently reading in order to navigate through all members of the list.
If you have more than one linked list, then you will need to store the same data, but for that list.
For example (unchecked pseudo code):
struct ListIndexEntry
{
ListEntry* startOfLinkedList;
ListEntry* currentLinkedListEntryBeingRead;
};
//fixed size data for structure, but could be variable if the structure has a size of data indicator.
stuct ListEntry
{
ListEntry* previousEntry;
ListEntry* nextEntry;
char Data[255];
}
struct ListIndexEntry ListTable[20]; //fixed table for 20 linked lists
So you allocate memory for the first element of your first linked list and update the first entry in the ListTable accordingly.
Okay - I see from comments that have appeared whilst I've been typing that you may already know this.
You can speed up navigation of large linked lists by using multiple layers of linked lists. Thus you could allocate a large block of memory that would store multiple ListEntry e.g.
struct ListBlock
{
void* previousBlock;
void* nextBlock;
ListEntry Entries[2000];
}
then you allocate memory for a ListBlock and store your ListEntrys contiguously within it.
The ListIndexEntry would now be:
struct ListIndexEntry
{
ListBlock* startOfLinkedList;
ListBlock* currentListBlock;
ListEntry* currentLinkedListEntryBeingRead;
}
You can then coarsely allocate memory, navigate and deallocate memory by ListBlock.
You'll still need to handle the pointers within the table and the current ListBlock manually.
Admittedly this means that there may be some unused memory within the last ListBlock in the list and so you'll need to choose your ListBlock.Entries size carefully.
From the description, I would describe this pattern as an object pool. The idea that you don't want to allocate lots of small structs, but instead store them in a single contiguous array means that you basically want an efficient malloc. However, the premise (or a "contract") behind the object pool is that the caller is "borrowing" items from the pool, and requires that the borrowed objects are not destroyed by the pool implementation before they are returned back to the pool.
So, you can do three things:
Make this array of structs coupled to the implementation, and store array indices instead of pointers. This means that the linked list code "knows" that it's using an array under the hood and the entire code is written to accomodate this. Accessing a list item is always done by indexing the array.
Write a memory pool which will grow as needed by adding blocks of structs into the pool, instead of resizing and moving existing blocks. This is a useful data structure and I've used it a lot, but it's most useful when you do rarely need to grow and do lots of borrowing and returning -- it's faster than malloc, doesn't suffer from fragmentation and likely exhibits better reference locality. But if you rarely need to return items to the pool, it's likely an overkill over a generic malloc implementation.
Obviusly, the third approach is to just use malloc and don't worry about this until you've profiled it and identified it to be an actual bottleneck.
As commentors pointed out and confirmed, "Don't mix embedded pointers and realloc(). It's a fundamentally bad design.". I ended up changing the embedded pointers to instead hold an offset value, to direct a pointer to the appropriate node. Many others commented with great list suggestions, but as Im using a trie (I was late to state this, my fault), I found this to be an easier fix without completely re-doing all of the general basis of my code
From A Tour of Go:
An array has a fixed size. A slice, on the other hand, is a dynamically-sized, flexible view into the elements of an array.
How can the slice be called as dynamically sized when it cannot go beyond the size of the underlying array.
The size of a Go array is fixed at compile time. The size of a Go slice is set dynamically at runtime.
References:
The Go Blog: Go Slices: usage and internals
The Go Blog: Arrays, slices (and strings): The mechanics of 'append'
Even with a cap, a dynamic size is still dynamic: it can range between zero and whatever the cap is.
That said, as Flimzy noted in a comment, if you use an operation that can "grow" a slice, it always returns a new slice, or takes a pointer to the slice—usually the former—so that the routine that needed to go past the current capacity could allocate a new, larger array1 and make the slice use that instead of the old array.
That's why append returns a new value, and you must write:
s = append(s, element)
for instance.
(The previous underlying array, if any, is garbage collected if and when it is appropriate to do so. A nil slice has no underlying array and hence a zero capacity.)
1The runtime uses unsafe and other special tricks to allocate this array, bypassing type-checking, but coordinating with the runtime's own garbage collection code. Hence it can allocate an array whose size is chosen at runtime instead of at compile time. The compiler's new and make and append built-ins have access to this same ability.
You can write this same kind of tricky code yourself using unsafe, but if you do, you run the risk of having to rewrite your code when a new Go release comes out, if the new Go has changed something internally. So, don't do that: use append or make to create the runtime-sized array with the slice data already set up for you.
How can the slice be called as dynamically sized when it cannot go beyond the size of the underlying array.
The types are static vs dynamic. An array type is like [4]byte - the size is part of the type definition, and therefore set at compile time. Only a [4]byte can be stored in a variable of type [4]byte. Not a [3]byte, not a [5]byte. It's static.
A slice type is like []byte - the size isn't part of the type definition, so it is not set at compile time, and a slice of any size can be stored in a []byte at runtime. It could be zero-length, it could be a thousand, it could be a four-byte window into a million-length array. It's dynamic.
The size of a slice can also shrink and grow within its capacity at runtime, though the capacity can only change by replacing the underlying array (which, being an array, is of fixed size). This is done automatically behind the scenes by append, for example. But, to my understanding at least, this is not what makes slices "dynamic"; it's the fact that a slice can be of any size at runtime - it is not known at compile time. That is what defines them as "dynamic" to me.
For example: I want to use reflect to get a slice's data as an array to manipulate it.
func inject(data []int) {
sh := (*reflect.SliceHeader)(unsafe.Pointer(&data))
dh := (*[len(data)]int)(unsafe.Pointer(sh.Data))
printf("%v\n", dh)
}
This function will emit a compile error for len(data) is not a constant. How should I fix it?
To add to the #icza's comment, you can easily extract the underlying array by using &data[0]—assuming data is an initialized slice. IOW, there's no need to jump through the hoops here: the address of the first slice's element is actually the address of the first slot in the slice's underlying array—no magic here.
Since taking an address of an element of an array is creating
a reference to that memory—as long as the garbage collector is
concerned—you can safely let the slice itself go out of scope
without the fear of that array's memory becoming inaccessible.
The only thing which you can't really do with the resulting
pointer is passing around the result of dereferencing it.
That's simply because arrays in Go have their length encoded in
their type, so you'll be unable to create a function to accept
such array—because you do not know the array's length in advance.
Now please stop and think.
After extracting the backing array from a slice, you have
a pointer to the array's memory.
To sensibly carry it around, you'll also need to carry around
the array's length… but this is precisely what slices do:
they pack the address of a backing array with the length of the
data in it (and also the capacity).
Hence really I think you should reconsider your problem
as from where I stand I'm inclined to think it's a non-problem
to begin with.
There are cases where wielding pointers to the backing arrays
extracted from slices may help: for instance, when "pooling"
such arrays (say, via sync.Pool) to reduce memory churn
in certain situations, but these are concrete problems.
If you have a concrete problem, please explain it,
not your attempted solution to it—what #Flimzy said.
Update I think I should may be better explain the
you can't really do with the resulting
pointer is passing around the result of dereferencing it.
bit.
A crucial point about arrays in Go (as opposed to slices)
is that arrays—as everything in Go—are passed around
by value, and for arrays that means their data is copied.
That is, if you have
var a, b [8 * 1024 * 1024]byte
...
b = a
the statement b = a would really copy 8 MiB of data.
The same obviously applies to arguments of functions.
Slices sidestep this problem by holding a pointer
to the underlying (backing) array. So a slice value
is a little struct type containing
a pointer and two integers.
Hence copying it is really cheap but "in exchange" it
has reference semantics: both the original value and
its copy point to the same backing array—that is,
reference the same data.
I really advise you to read these two pieces,
in the indicated order:
https://blog.golang.org/go-slices-usage-and-internals
https://blog.golang.org/slices
Let's say I have an associative array keyed by unsigned int; values could be of any fixed-size type. There is some pre-defined maximum no. of instances.
API usage example: MyStruct * valuePtr = get(1234); and put(6789, &myStructInstance); ...basic.
I want to minimise cache misses as I read entries rapidly and at random from this array, so I pre-malloc(sizeof(MyType) * MAX_ENTRIES) to ensure locality of reference inasmuch as possible.
Genericism is important for the values array. I've looked at C pseudo-generics, but prefer void * for simplicity; however, not sure if this is at odds with performance goals. Ultimately, I would like to know what is best for performance.
How should I implement my associative array for performance? Thoughts thus far...
Do I pass the associative array a single void * pointer to the malloced values array and allow it to use that internally (for which we would need to guarantee a matching keys array size)? Can I do this generically, since the type needs(?) to be known in order to index into values array?
Do I have a separate void * valuePtrs[] within the associative array, then have these pointers point to each element in the malloced values array? This would seem to avoid need to know about concrete type?
Do I use C pseudo-generics and thus allow get() to return a specific value type? Surely in this case, the only benefit is not having to explicitly cast, e.g. MyStruct* value = (MyStruct*) get(...)... the array element still has to be dereferenced and so has the same overhead?
And, in general, does the above approach to minimising cahce misses appear to make sense?
In both cases, the performance is basically the same.
In the first one (void* implementation), you will need to look up the value + dereference the pointer. So these are two instructions.
In the other implementation, you will need to multiply the index with the size of the values. So this implementation also asks for two instructions.
However, the first implementation will be easier and more clean to implement. Also, the array is fully transparent; the user will not need to know what kind of structures are in the array.
See solutions categorised below, in terms of pros and cons (thanks to Ruben for assisting my thinking)... I've implemented Option 2 and 5 for my use case, which is somewhat generalised; I recommend Option 4 if you need a very specific, one-off data structure. Option 3 is most flexible while being trivial to code, and is also the slowest. Option 4 is the quickest. Option 5 is a little slow but with flexibility on the array size and ease of general use.
Associative array struct points to array of typed pointers:
pros no failure value required, explicit casts not required, does not need compile-time size of array
cons costly double deref, requires generic library code
Associative array struct holds array of void * pointers:
pros no failure value required, no generic library code
cons costly double deref, explicit casts following get(), needs compile time size of array if VLAs are not used
Associative array struct points to array of void * values:
pros no generic library code, does not need compile-time size of array
cons costly triple deref, explicit casts following get(), requires offset calc which requires sizeof value passed in explicitly
Associative array struct holds array of typed values:
pros cheap single deref, explicit casts not required, keys and entries allocated contiguously
cons requires generic library code, failure value must be supplied, needs compile time size of array if VLAs are not used
Associative array struct points to array of typed values:
pros explicit casts not required, flexible array size
cons costly double deref, requires generic library code, failure value must be supplied, needs compile time size of array if VLAs are not used