The best and most concise way to find the value of the last element in an associative array?

Welp, $ only supports queues, but not associative arrays. And due to the nature of the ref-type argument used in the .last function of associative arrays, we need at least three lines to achieve this simple goal.


int scores [string] = '{ "Bob": 62, "Nancy": 78, "Tom": 93 };

initial begin
   automatic string last_one;
   if ( scores.last (last_one) ) begin
      $display ( "The value of the last element is: %p", scores [last_one] );
   end
end

For sure, we could use .find_last, but then the with clause is mandatory (don’t ask me why, ask the LRM committee), so we have to write some awkward code like this. And to be honest, I don’t know when the associative array scales up, how bad the performance of this .find_last would be.


int scores [string] = '{ "Bob": 62, "Nancy": 78, "Tom": 93 };

initial begin
   $display ( "The value of the last element is: %p", int'( scores.find_last with (1) ) );
   // Yes, we need this do-nothing "with (1)" to make the compiler happy.
end

Any suggestions?

In reply to rzhang313:

From which LRM section you got that the find_last() method is for associative arrays?
Array locator methods (find_last() is one of them) operate on any unpacked array, including queues, they return a queue, which makes the code you posted as second method not to make sense since you are casting a queue to an int.
What exactly you mean by the last element in an associative array? Also I think you could be misinterpreting the last() method as in the LRM is stated that it returns the last (largest)index or key
For example


module test();
  int aa[string]= '{"x":12, "b":23};
  string key;
  initial begin
    aa["a"]=90;
    if(aa.last(key))
      $display("the last of aa =%p is %p index = %p",aa, aa[key], key);
  end
endmodule

The last method returns “x” in one simulator as it is the largest key value used to store the array.

I think the return value of .last() is required for type checking and/or if the array is empty (returns zero), the LRM specifies the following:
The argument passed to first(), last()…"shall be assignment compatible with the index type of the array. If the argument has an integral type that is smaller than the size of the corresponding array index type, then the function returns –1 and shall truncate in order to fit into the argument.

I do not see such a huge overhead of having one if-else, that actually takes care the possibility of having an empty array, I’m not sure in your application what is the problem, even using something like what you propose how can you tell of the array is empty or if the type doesn’t match (which I think it should be an error detected at compile time, instead of handling this especial case of truncation for integral type indexes described in the LRM)

-R

In reply to rgarcia07:

Hi,

Thank you for the reply. Let me answer your questions.

From which LRM section you got that the find_last() method is for associative arrays?
Array locator methods (find_last() is one of them) operate on any unpacked array, including queues, they return a queue, which makes the code you posted as second method not to make sense since you are casting a queue to an int.

Answer: You were already in the correct location of LRM. Just further read on the next page, and you will see this sentence stating .find_last supports associative arrays as below.

Index locator methods return a queue of int for all arrays except associative arrays, which return a queue of the same type as the associative index type. Associative arrays that specify a wildcard index type shall not be allowed.

Next question:

What exactly you mean by the last element in an associative array? Also I think you could be misinterpreting the last() method as in the LRM is stated that it returns the last (largest)index or key

Answer: You’re right. I misunderstood the meaning of .last. Yes, it should be the largest index. Thanks for pointing it out.

Next one:

I do not see such a huge overhead of having one if-else, that actually takes care the possibility of having an empty array, I’m not sure in your application what is the problem, even using something like what you propose how can you tell of the array is empty or if the type doesn’t match (which I think it should be an error detected at compile time, instead of handling this especial case of truncation for integral type indexes described in the LRM)

Answer: I just don’t like to declare a new variable only for this purpose, especially in the middle of a thread, where I have to put the code into a new “begin-end” block or move the declaration to the very beginning of the thread. I agree it is not a big overhead, though I prefer a one-line way.

Regarding the empty checks, I think if .find_last with (1) returns an empty array, it is sufficient to tell us the associative array is also empty.

In reply to rzhang313:

Thanks a lot for pointing me out the LRM section, I find this confusing one paragraph says something then the other one states that it is allowed, regarding the empty check well it is up to each specific implementation if the array is supposed to be used later on some check probably will be required, but if it is just for printing then it should be OK, btw I’ve seen people using ‘with (item)’ more frequently than ‘with (1)’

In any case thanks I learn something new today :-)!

-R

In reply to rgarcia07:

Yes, it was a great discussion. Thanks!

…they return a queue, which makes the code you posted as second method not to make sense since you are casting a queue to an int.

By the way, I believe casting a queue into an int type is supported, and it’s very convenient in this “one-element queue → int” case since it’s done in just one line and straightforward. If interested, you could read Section 6.24.3 Bit-stream casting of LRM. I tried it out myself, and it worked.

btw I’ve seen people using ‘with (item)’ more frequently than ‘with (1)’

You’re right. That’s why I said this .find with (1) usage was a bit awkward. The return value of the with clause is a Boolean per se, so 1 means always true. I put it there because the with clause is mandatory. LRM even has an example on the bottom of Page 166.

qi = IA.find( x ); // shall be an error

Another thing I am not sure is the runtime performance of .find_last with compared to .last, though the same Page 166 says the mechanism of how .find_last works for an associative array should be the same as the .last method does. But it all depends on how vendors implement the search algorithms.

The first or last element is defined as being closest to the leftmost or rightmost indexed element, respectively, except for an associative array, which shall use the element closest to the index returned by the first or last method for the associative array index type.