PracHub
QuestionsPremiumCoachesLearningGuidesInterview Prep

Quick Overview

This question evaluates understanding of ring-buffer data structures, circular indexing, fixed-capacity storage, and object-oriented design for a single-producer, multi-consumer implementation in C++.

  • medium
  • Citadel
  • Coding & Algorithms
  • Software Engineer

Implement a single-producer multi-consumer ring buffer

Company: Citadel

Role: Software Engineer

Category: Coding & Algorithms

Difficulty: medium

Interview Round: Technical Screen

Implement a fixed-capacity ring buffer in **C++** for a setting with **one producer** and **multiple consumers**. Design a class that stores integers in a preallocated circular array and supports the following operations: - `RingBuffer(int capacity)`: initialize the buffer with a fixed capacity. - `bool push(int value)`: insert a value at the tail. Return `false` if the buffer is full. - `bool pop(int& value)`: remove the oldest value from the head and write it into `value`. Return `false` if the buffer is empty. - `bool empty() const` - `bool full() const` - `int size() const` Requirements: - All operations should run in **O(1)** time. - Use circular indexing to reuse freed space. - Do not resize the underlying storage. - Focus on the **object-oriented design** and correct ring-buffer behavior. - You may assume synchronization is handled externally; the main goal is to implement the ring-buffer logic correctly for a single-producer, multi-consumer use case. After coding, briefly explain how you would adapt the design if true thread safety were required.

Quick Answer: This question evaluates understanding of ring-buffer data structures, circular indexing, fixed-capacity storage, and object-oriented design for a single-producer, multi-consumer implementation in C++.

Implement the core logic of a fixed-capacity ring buffer, inspired by this C++ interview design: a preallocated circular array that supports one producer and multiple consumers, with synchronization handled externally. The original API is: - RingBuffer(int capacity) - bool push(int value) - bool pop(int& value) - bool empty() const - bool full() const - int size() const For automated evaluation, write a function `solution(capacity, operations)` that simulates this class. Each operation in `operations` is one of: - `(\"push\", value)` -> insert `value` at the tail, return `True` if successful, `False` if the buffer is full. - `(\"pop\",)` -> remove the oldest value from the head. Return `(True, value)` if successful, or `(False, None)` if the buffer is empty. - `(\"empty\",)` -> return whether the buffer is empty. - `(\"full\",)` -> return whether the buffer is full. - `(\"size\",)` -> return the current number of elements. All operations must run in O(1) time. Use circular indexing to reuse freed space, and do not resize the underlying storage. Follow-up discussion (no code required): briefly explain how you would adapt the design if true thread safety were required in C++.

Constraints

  • 1 <= capacity <= 10^5
  • 0 <= len(operations) <= 2 * 10^5
  • -10^9 <= pushed values <= 10^9
  • Each operation should run in O(1) time
  • Do not resize the buffer after initialization

Examples

Input: (3, [("empty",), ("push", 10), ("push", 20), ("size",), ("pop",), ("push", 30), ("push", 40), ("full",), ("pop",), ("pop",), ("pop",), ("empty",)])

Expected Output: [True, True, True, 2, (True, 10), True, True, True, (True, 20), (True, 30), (True, 40), True]

Explanation: This checks basic FIFO behavior, size tracking, and wrap-around after a pop frees space.

Input: (2, [("push", 1), ("push", 2), ("push", 3), ("full",), ("size",), ("pop",), ("push", 3), ("pop",), ("pop",), ("empty",)])

Expected Output: [True, True, False, True, 2, (True, 1), True, (True, 2), (True, 3), True]

Explanation: The third push fails because the buffer is full. After popping one item, pushing succeeds again.

Input: (1, [("pop",), ("push", -5), ("full",), ("push", 7), ("size",), ("pop",), ("empty",), ("pop",)])

Expected Output: [(False, None), True, True, False, 1, (True, -5), True, (False, None)]

Explanation: Capacity 1 is a boundary case. It also checks failed pop on empty, failed push on full, and a negative value.

Input: (4, [("push", 5), ("push", 5), ("push", -1), ("pop",), ("push", 7), ("push", 7), ("full",), ("size",), ("pop",), ("pop",), ("pop",), ("pop",)])

Expected Output: [True, True, True, (True, 5), True, True, True, 4, (True, 5), (True, -1), (True, 7), (True, 7)]

Explanation: This verifies correct FIFO order with duplicates, a negative value, and wrap-around after earlier pops.

Input: (5, [])

Expected Output: []

Explanation: No operations means no output.

Hints

  1. Track `head`, `tail`, and the current element count. That lets you avoid shifting elements after each pop.
  2. When either index reaches the end of the array, wrap it back using modulo arithmetic. A separate count helps distinguish `empty` from `full`.
Last updated: Apr 19, 2026

Loading coding console...

PracHub

Master your tech interviews with 8,500+ real questions from top companies.

Product

  • Questions
  • Learning Tracks
  • Interview Guides
  • Resources
  • Premium
  • For Universities
  • Student Access

Browse

  • By Company
  • By Role
  • By Category
  • Topic Hubs
  • SQL Questions
  • Compare Platforms
  • Discord Community

Support

  • support@prachub.com
  • (916) 541-4762

Legal

  • Privacy Policy
  • Terms of Service
  • About Us

© 2026 PracHub. All rights reserved.

Related Coding Questions

  • Sort a Nearly Sorted Array - Citadel (hard)
  • Compute BBO and NBBO from order data - Citadel (medium)
  • Compute maximum later-earlier difference - Citadel (medium)
  • Implement LRU/LFU cache with custom eviction - Citadel (easy)
  • Design dynamic weighted random sampling with updates - Citadel (medium)