← Design Verification Interviews

Interview Question · Code Writing

Removing Every Match from a Queue

L0 FresherL1 Juniorsystemverilogarraysqueues

The Question

The interviewer asks

Write code that removes every 5 from an int queue. A candidate wrote the loop below; what is left in q afterwards?

systemverilog
int q[$] = '{5, 5, 3, 5, 7};
// remove every 5
for (int i = 0; i < q.size(); i++)
  if (q[i] == 5) q.delete(i);
Reveal the Model Answer

It leaves 5 3 7. Each delete(i) shifts the later elements down by one. So the second of two neighbouring 5s lands at index i, and the loop moves past it. Write the result instead of editing in place: q = q.find(x) with (x != 5);. If you must delete in a loop, walk the indexes from the end down to 0.

The loop, one pass per column
012i012q[i] checked535actiondelete(0)keepdelete(2)q after5 3 5 75 3 7q.size()43the second 5 slides into slot 0, and i moves on to 1i becomes 3, which is not below size 3: the loop ends

Each delete shifts the later elements down, so the element after a deleted 5 is never checked.

Self-Check

Tick each key point you covered in your answer.

What Interviewers Listen For (Fresher)

A good fresher answer traces the indexes by hand and finds the element that the loop skips.

Cross-Questions

Where the interviewer goes next. Open a node to practise that follow-up.

What IfProve ItBreak ItCompare

  1. Removing Every Match from a Queue
  2. CompareLocator Methods vs a Hand-Written LoopL1 Junior

    Compare q.find(x) with (x != 5) with a loop that pushes the survivors into a new queue.

    Reveal the Model Answer

    Both build a new queue and both are linear. The locator method states the intent in one line and cannot get an index wrong. The loop can do more in one pass, such as count and log the removed items. In reviews, prefer the method unless the loop does more than filter.

    Self-Check

    Tick each key point you covered in your answer.

    Half-Truth

    "Locator methods are faster because they are built in."

    The standard sets no complexity for them. Choose them for clarity, and measure if speed matters.

    Source IEEE 1800-2017 §7.12

  3. Break ItDeleting from a Queue Inside a LoopL1 Junior

    Break it: a loop deletes matches in place with q.delete(i) while i counts up. What goes wrong?

    Reveal the Model Answer

    After q.delete(i), every later element moves down one index. The loop then adds 1 to i and skips the element that moved into slot i. So two matches in a row leave the second one behind. Loop down from the end, or build a new queue.

    Self-Check

    Tick each key point you covered in your answer.

    Misconception

    "Use foreach and delete inside it; the loop follows the size."

    The standard leaves the result undefined if the array size changes during a foreach. Tools may skip or repeat elements.

    Source IEEE 1800-2017 §12.7.3

  4. What IfCounting with Sum on a Bit ArrayL1 JuniorL2 Mid-Level

    Asked if they count matches with sum()

    What if they count set flags with flags.sum() on a bit flags[8], or total byte lengths with lens.sum()? Predict the output.

    systemverilog
    module tb;
      bit  flags [8] = '{default: 1};   // eight set flags
      byte lens  []  = '{100, 100};     // two lengths of 100
      initial begin
        $display("flags.sum()=%0d  with int=%0d", flags.sum(), flags.sum() with (int'(item)));
        $display("lens.sum()=%0d  with int=%0d", lens.sum(), lens.sum() with (int'(item)));
      end
    endmodule
    
    Reveal the Model Answer

    It prints flags.sum()=0 with int=8 and lens.sum()=-56 with int=200. A reduction method returns the element type, so eight 1-bit flags add up modulo 2 and two signed bytes overflow. Cast each item in a with clause, such as flags.sum() with (int'(item)), to make the sum wide enough.

    Three Questions Asked of One ArrayThree method calls on an associative array age, keyed by read ID. Arrows show data: the values each method reads and the result it returns. Step 2 shows the cast that makes a sum wide enough.
    Three questions asked of one arrayThree method calls on an associative array `age`, keyed by read ID. Arrows show data: the values each method reads and the result it returns. Step 2 shows the cast that makes a sum wide enough. assoc array age [int] ID 3: 12, ID 7: 1500,ID 9: 40, ID 12: 2048 locator find_index with (item > 1000) reduction sum with (int'(item >1000)) locator find with (item > 5000) queue ids queue {7, 12} int n int: 2 queue ages queue {}, size() is 0 keysone valuevalues
    1. Search for stuck reads

      item stands for each value in turn, and two values exceed 1,000. On an associative array find_index returns their keys, IDs 7 and 12, as a queue.

      Follow the calls, values and waits
      1. data 1500 and 2048 match: age [int] → find_index
      2. data {7, 12}: find_index → ids
    2. Count them

      The cast inside the with clause turns each comparison into a 32-bit 0 or 1, so the sum is 2. Without the cast, the sum is 1 bit wide and 1 + 1 wraps to 0.

      Follow the calls, values and waits
      1. data 0, 1, 0, 1: age [int] → sum
      2. data 2: sum → n
    3. An empty answer

      No value exceeds 5,000, so find returns an empty queue. Check size() before reading element 0 of any result.

      Follow the calls, values and waits
      1. data no match: age [int] → find
      2. data {}: find → ages
    4. The array is unchanged

      None of these calls changed age. Locator and reduction methods only read the collection; sort and the other reordering methods change it.

    Read the diagram as text
    • age [int]: ID 3: 12, ID 7: 1500, ID 9: 40, ID 12: 2048
    • find_index: with (item > 1000)
    • sum: with (int'(item > 1000))
    • find: with (item > 5000)
    • ids: queue {7, 12}
    • n: int: 2
    • ages: queue {}, size() is 0
    • age [int] → find_index
    • age [int] → sum
    • age [int] → find
    • find_index → ids: keys
    • sum → n: one value
    • find → ages: values

    Every locator method returns a queue, even when the answer has one element or none.

    RUNVerilator · simulator service
    Edit the code, then run it
    Expected: flags.sum()=0 with int=8 lens.sum()=-56 with int=200

    Self-Check

    Tick each key point you covered in your answer.

    Misconception

    "sum() returns an int, like most functions."

    Its result has the type of the array elements, unless a with expression gives another type. So a bit array sums in one bit.

    Source IEEE 1800-2017 §7.12.3

  5. Prove ItSolve 2.4.2: Wide Population ReductionSimulator-graded

    Show it, don't just say it: this Silicon Lab problem is graded by the simulator.

    Open Problem 2.4.2

  6. Prove ItSolve 2.2.2: Bounded Queue OperationsSimulator-graded

    Show it, don't just say it: this Silicon Lab problem is graded by the simulator.

    Open Problem 2.2.2

  7. Break ItPopping an Empty QueueL1 Junior

    A scoreboard calls exp_q.pop_front() when a response arrives. How does this break when the DUT sends a response nobody asked for?

    Reveal the Model Answer

    Popping an empty queue returns the element type's default, perhaps with a warning, and the scoreboard compares the response against that default. A spurious response of value 0 then passes. Check exp_q.size() first and report an unexpected response.

    Self-Check

    Tick each key point you covered in your answer.

    Misconception

    "An empty pop stops the simulation with an error."

    The standard returns the default value and at most warns, so the test keeps running with a made-up expectation.

    Source IEEE 1800-2017 §7.10.2.4

What People Get Wrong

Common wrong answers and why they fail. Run It shows the wrong belief failing on a real simulator.

Misconception

"Deleting inside the index loop removes every match."

The indexes move under the loop. The twin starts with 5 5 3 5 7 and leaves a 5 behind.

Run It

The candidate's loop on 5 5 3 5 7.

RUNVerilator · simulator service
Edit the code, then run it
Expected: left: 5 3 7 FAIL: each delete shifted the next 5 into the slot the loop had already passed
See the Fix
module tb;
  int q[$] = '{5, 5, 3, 5, 7};
  string s = "";
  initial begin
    q = q.find(x) with (x != 5);     // the fix: build the survivors, no index juggling
    foreach (q[i]) s = {s, $sformatf(" %0d", q[i])};
    $display("left:%s", s);
    if (5 inside {q}) $display("FAIL: each delete shifted the next 5 into the slot the loop had already passed");
    else $display("PASS: no 5 is left");
  end
endmodule

Prints: left: 3 7 PASS: no 5 is left

Tool as Truth

"Use foreach with delete; foreach handles the shifting."

Changing a collection's size inside a foreach over it is undefined. One simulator may happen to give the right answer; another need not.

Source IEEE 1800-2017 §12.7.3

Spec Misquote

"find returns the indexes of the matches."

find returns the matching elements; find_index returns their indexes. Both return a queue, empty when nothing matches.

Source IEEE 1800-2017 §7.12.1

Learn It, Then Prove It