I have a look at the ArrayList Source code,found remove method as follows:
/**
* Removes the element at the specified position in this list.
* Shifts any subsequent elements to the left (subtracts one from their
* indices).
*
* #param index the index of the element to be removed
* #return the element that was removed from the list
* #throws IndexOutOfBoundsException {#inheritDoc}
*/
public E remove(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
modCount++;
E oldValue = (E) elementData[index];
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
why it doesn't consider the situation when index<0?
Passing in a negative index would fail on the following line:
E oldValue = (E) elementData[index];
Specifically, an access to the elementData underlying array would happen with some negative index. This would cause an ArrayIndexOutOfBoundsException to be thrown, as the documentation describes:
Thrown to indicate that an array has been accessed with an illegal index. The index is either negative or greater than or equal to the size of the array.
Hence, the ArrayList#remove() implementation does not need to do anything extra as the language will already handle the case of negative indices.
However, you might be wondering why the code does make the following check if the index is larger than the size:
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
The reason this check is made is because it is possible that an index is passed in which is within the bounds of elementData but is larger than the logical size of the actual list/array. In other words, the size of the underlying array does not (and often will not) need to be in lock step with the actual number of entries in the list. Rather, the JVM will grow or shrink the elementData array as needed depending the size and usage of the list.
Related
I'm writing a smart contract and want to use Arrays to manipulate data, but looking at the AssemblyScript docs, I'm not sure the best way to proceed.
It seems fine to me to just use:
let testData:string[] = []
but when I consulted the assemblyscript docs, there are three recommended ways to create an Array:
// The Array constructor implicitly sets `.length = 10`, leading to an array of
// ten times `null` not matching the value type `string`. So, this will error:
var arr = new Array<string>(10);
// arr.length == 10 -> ERROR
// To account for this, the .create method has been introduced that initializes
// the backing capacity normally but leaves `.length = 0`. So, this will work:
var arr = Array.create<string>(10);
// arr.length == 0 -> OK
// When pushing to the latter array or subsequently inserting elements into it,
// .length will automatically grow just like one would expect, with the backing
// buffer already properly sized (no resize will occur). So, this is fine:
for (let i = 0; i < 10; ++i) arr[i] = "notnull";
// arr.length == 10 -> OK
When would I want to use one type of instantiation over another? Why wouldn't I just always use the version I presented in the beginning?
Nothing wrong with the array literal approach. It is basically equivalent to
let testData = new Array<string>();
However, sometimes you know what the length of the array should be and in such cases, preallocating the memory using Array.create is more efficient.
UPDATE
With this PR Array.create deprecated and should not be used anymore.
OLD ANSWER
let testData:string[] = []
semantically the same as
let testData = new Array<string>()
AssemblyScript doesn't support preallocated sparse arrays (arrays with holes) for reference elements which not explicitly declared as nullable like:
let data = new Array<string>(10);
data[9] = 1; // will be compile error
Instead you could use:
let data = new Array<string | null>(10);
assert(data.length == 10); // ok
assert(data[0] === null); // ok
or Array.create but in this case your length will be zero. Array.create is actually just reserve capacity for backing buffer.
let data = Array.create<string>(10);
assert(data.length == 0); // true
For plain (non-reference) types you could use usual way without care about nullabe or creating array via Array.create:
let data = new Array<i32>(10);
assert(data.length == 10); // ok
assert(data[0] == 0); // ok
How can I create a fixed multidimensional array in Specman/e using varibles?
And then access individual elements or whole rows?
For example in SystemVerilog I would have:
module top;
function automatic my_func();
bit [7:0] arr [4][8]; // matrix: 4 rows, 8 columns of bytes
bit [7:0] row [8]; // array : 8 elements of bytes
row = '{1, 2, 3, 4, 5, 6, 7, 8};
$display("Array:");
foreach (arr[i]) begin
arr[i] = row;
$display("row[%0d] = %p", i, row);
end
$display("\narr[2][3] = %0d", arr[2][3]);
endfunction : my_func
initial begin
my_func();
end
endmodule : top
This will produce this output:
Array:
row[0] = '{'h1, 'h2, 'h3, 'h4, 'h5, 'h6, 'h7, 'h8}
row[1] = '{'h1, 'h2, 'h3, 'h4, 'h5, 'h6, 'h7, 'h8}
row[2] = '{'h1, 'h2, 'h3, 'h4, 'h5, 'h6, 'h7, 'h8}
row[3] = '{'h1, 'h2, 'h3, 'h4, 'h5, 'h6, 'h7, 'h8}
arr[2][3] = 4
Can someone rewrite my_func() in Specman/e?
There are no fixed arrays in e. But you can define a variable of a list type, including a multi-dimensional list, such as:
var my_md_list: list of list of my_type;
It is not the same as a multi-dimensional array in other languages, in the sense that in general each inner list (being an element of the outer list) may be of a different size. But you still can achieve your purpose using it. For example, your code might be rewritten in e more or less like this:
var arr: list of list of byte;
var row: list of byte = {1;2;3;4;5;6;7;8};
for i from 0 to 3 do {
arr.add(row.copy());
print arr[i];
};
print arr[2][3];
Notice the usage of row.copy() - it ensures that each outer list element will be a copy of the original list.
If we don't use copy(), we will get a list of many pointers to the same list. This may also be legitimate, depending on the purpose of your code.
In case of a field (as opposed to a local variable), it is also possible to declare it with a given size. This size is, again, not "fixed" and can be modified at run time (by adding or removing items), but it determines the original size of the list upon creation, for example:
struct foo {
my_list[4][8]: list of list of int;
};
I cannot find this information in the documentation: Does Redis guarantee that an element is returned with ZSCAN command under this condition:
The element was contained in the sorted set from the start to the end
of a full iteration, BUT the score of such element has changed (even
several times, for instance by another client) during iteration?
Only related statement I found regarding this is the following:
Elements that were not constantly present in the collection during a
full iteration, may be returned or not: it is undefined.
But I don't know if score change in such case is the same thing as remove/add operations or not.
If the element exists during the full iteration, it will be returned by the zscan command. It doesn't matter whether the score has been changed during the iteration.
Normally, zset is implemented as a hash table (i.e. Redis' dict), and a skiplist. When running the zscan command, it iterates over the hash table entries to do the scan job. The changing of the score (value of the dict entry) won't affect the iteration process.
If zset is small enough, Redis implements it as a ziplist. In this case, Redis returns all elements in a single zscan call. So the score CANNOT be changed during the iteration.
In a word, you have the guarantee.
Thanks a lot for_stack for the confirmation. I didn't know if someone will response so meanwhile I implemented some own checks in Java:
#Test
public void testZScanGuaranteeWithScoreUpdates() {
try (Jedis jedis = jedisPool.getResource()) {
IntStream.rangeClosed(1, 50).forEach(i -> testZScanGuaranteeWithUpdates(jedis, false));
IntStream.rangeClosed(1, 50).forEach(i -> testZScanGuaranteeWithUpdates(jedis, true));
}
}
/**
* Changing score of elements (named ids) during iteration (eventually inserting and removing another unchecked ids)
* and then assert that no element (id) is missing
*/
private void testZScanGuaranteeWithUpdates(Jedis jedis, boolean noise) {
Random ran = new Random();
List<String> noiseIds = IntStream.range(0, 4000).mapToObj(i -> UUID.randomUUID().toString()).collect(toList());
if (noise) { // insert some noise with random score (from 0 to 5000)
noiseIds.forEach(id -> jedis.zadd(KEY, ran.nextInt(5000), id));
}
int totalIds = 2000;
List<String> ids = IntStream.range(0, totalIds).mapToObj(i -> UUID.randomUUID().toString()).collect(toList());
Set<String> allScanned = new HashSet<>();
ids.forEach(id -> jedis.zadd(KEY, ran.nextInt(2500) + 1000, id)); // insert all IDs with random score (from 1000 to 3500)
redis.scanIds(KEY, 100, res -> { // encapsulate iteration step - this closure is executed for every 100 elements during iteration
allScanned.addAll(res); // record 100 scanned ids
Collections.shuffle(ids);
ids.stream().limit(500).forEach(id -> jedis.zadd(KEY, ran.nextInt(2500) + 1000, id)); // change score of 500 random ids
if (noise) { // insert and remove some noise
IntStream.range(0, 50).forEach(i -> jedis.zadd(KEY, ran.nextInt(5000), UUID.randomUUID().toString()));
IntStream.range(0, 60).forEach(i -> jedis.zrem(KEY, noiseIds.get(ran.nextInt(noiseIds.size()))));
}
});
if (!noise) {
assertEquals(totalIds, allScanned.size()); // 2000 unique ids scanned
}
assertTrue(allScanned.containsAll(ids)); // none id is missing
jedis.del(KEY); // prepare for test re-execution
}
Tests are passing, i.e. all elements are returned by ZSCAN even when their score has changed during iteration using ZADD command.
This question already has answers here:
What is an IndexOutOfRangeException / ArgumentOutOfRangeException and how do I fix it?
(5 answers)
Closed 7 years ago.
I'm getting one of the following errors:
"Index was out of range. Must be non-negative and less than the size of the collection"
"Insertion index was out of range. Must be non-negative and less than or equal to size."
"Index was outside the bounds of the array."
What does it mean, and how do I fix it?
See Also
IndexOutOfRangeException
ArgumentOutOfRangeException
Why does this error occur?
Because you tried to access an element in a collection, using a numeric index that exceeds the collection's boundaries.
The first element in a collection is generally located at index 0. The last element is at index n-1, where n is the Size of the collection (the number of elements it contains). If you attempt to use a negative number as an index, or a number that is larger than Size-1, you're going to get an error.
How indexing arrays works
When you declare an array like this:
var array = new int[6]
The first and last elements in the array are
var firstElement = array[0];
var lastElement = array[5];
So when you write:
var element = array[5];
you are retrieving the sixth element in the array, not the fifth one.
Typically, you would loop over an array like this:
for (int index = 0; index < array.Length; index++)
{
Console.WriteLine(array[index]);
}
This works, because the loop starts at zero, and ends at Length-1 because index is no longer less than Length.
This, however, will throw an exception:
for (int index = 0; index <= array.Length; index++)
{
Console.WriteLine(array[index]);
}
Notice the <= there? index will now be out of range in the last loop iteration, because the loop thinks that Length is a valid index, but it is not.
How other collections work
Lists work the same way, except that you generally use Count instead of Length. They still start at zero, and end at Count - 1.
for (int index = 0; i < list.Count; index++)
{
Console.WriteLine(list[index]);
}
However, you can also iterate through a list using foreach, avoiding the whole problem of indexing entirely:
foreach (var element in list)
{
Console.WriteLine(element.ToString());
}
You cannot index an element that hasn't been added to a collection yet.
var list = new List<string>();
list.Add("Zero");
list.Add("One");
list.Add("Two");
Console.WriteLine(list[3]); // Throws exception.
I'm starting to play around with some C code within Objective-C programs. The function I'm trying to write sorts all of the lat/long coordinates from a KML file into clusters based on 2D arrays.
I'm using three 2D arrays to accomplish this:
NSUInteger **bucketCounts refers to the number of CLLocationCoordinate2Ds in a cluster.
CLLocationCoorindate2D **coordBuckets is an array of arrays of coordinates
NSUInteger **bucketPointers refers to an index in the array of coordinates from coordBuckets
Here's the code that is messing me up:
//Initialize C arrays and indexes
int n = 10;
bucketCounts = (NSUInteger**)malloc(sizeof(NSUInteger*)*n);
bucketPointers = (NSUInteger**)malloc(sizeof(NSUInteger*)*n);
coordBuckets = (CLLocationCoordinate2D **)malloc(sizeof(CLLocationCoordinate2D*)*n);
for (int i = 0; i < n; i++) {
bucketPointers[i] = malloc(sizeof(NSUInteger)*n);
bucketCounts[i] = malloc(sizeof(NSUInteger)*n);
}
NSUInteger nextEmptyBucketIndex = 0;
int bucketMax = 500;
Then for each CLLocationCoordinate2D that needs to be added:
//find location to enter point in matrix
int latIndex = (int)(n * (oneCoord.latitude - minLat)/(maxLat-minLat));
int lonIndex = (int)(n * (oneCoord.longitude - minLon)/(maxLon-minLon));
//see if necessary bucket exists yet. If not, create it.
NSUInteger positionInBucket = bucketCounts[latIndex][lonIndex];
if (positionInBucket == 0) {
coordBuckets[nextEmptyBucketIndex] = malloc(sizeof(CLLocationCoordinate2D) * bucketMax);
bucketPointers[latIndex][lonIndex] = nextEmptyBucketIndex;
nextEmptyBucketIndex++;
}
//Insert point in bucket.
NSUInteger bucketIndex = bucketPointers[latIndex][lonIndex];
CLLocationCoordinate2D *bucketForInsert = coordBuckets[bucketIndex];
bucketForInsert[positionInBucket] = oneCoord;
bucketCounts[latIndex][lonIndex]++;
positionInBucket++;
//If bucket is full, expand it.
if (positionInBucket % bucketMax == 0) {
coordBuckets[bucketIndex] = realloc(coordBuckets[bucketIndex], (sizeof(CLLocationCoordinate2D) * (positionInBucket + bucketMax)));
}
Things seem to be going well for about 800 coordinates, but at the same point a value in either bucketCounts or bucketPointers gets set to an impossibly high number, which causes a reference to a bad value and crashes the program. I'm sure this is a memory management issue, but I don't know C well enough to troubleshoot it myself. Any helpful pointers for where I'm going wrong? Thanks!
It seems to me each entry in bucketPointers can potentially have its own "bucket", requiring a unique element of coordBuckets to hold the pointer to that bucket.
The entries in bucketPointers are indexed by bucketPointers[latIndex][lonIndex], so there can be n*n of them, but you allocated only n places in coordBuckets.
I think you should allocate for n*n elements in coordBuckets.
Two problems I see:
You don't initialize bucketCounts[] in the given code. It may well happen to all 0s but you should still initialize it with calloc() or memset():
bucketCounts[i] = calloc(n, sizeof(NSUInteger));
if oneCoord.latitude == maxLat then latIndex == n which will overflow your arrays which have valid indexes from 0 to n-1. Same issue with lonIndex. Either allocate n+1 elements and/or make sure latIndex and lonIndex are clamped from 0 to n-1.
In code using raw arrays like this you can solve a lot of issues with two simple rules:
Initialize all arrays (even if you technically don't need to).
Check/verify all array indexes to prevent out-of-bounds accesses.