Release soft dependencies if they stop early.
[oweals/dinit.git] / src / cpbuffer.h
index 94132ca2db001f224e36e5f0bea3e53743811df3..1478b740a9ac2512c971f85e61b0e962ab45279e 100644 (file)
@@ -4,9 +4,9 @@
 #include <cstring>
 
 // control protocol buffer, a circular buffer with 1024-byte capacity.
-class CPBuffer
+template <int SIZE> class CPBuffer
 {
-    char buf[1024];
+    char buf[SIZE];
     int cur_idx = 0;
     int length = 0;  // number of elements in the buffer
     
@@ -16,12 +16,43 @@ class CPBuffer
         return length;
     }
     
+    int get_free() noexcept
+    {
+        return SIZE - length;
+    }
+    
+    char * get_ptr(int index)
+    {
+        int pos = cur_idx + index;
+        if (pos >= SIZE) pos -= SIZE;
+    
+        return &buf[pos];
+    }
+    
+    char * get_buf_base()
+    {
+        return buf;
+    }
+    
+    int get_contiguous_length(char *ptr)
+    {
+        int eidx = cur_idx + length;
+        if (eidx >= SIZE) eidx -= SIZE;
+        
+        if (buf + eidx > ptr) {
+            return (buf + eidx) - ptr;
+        }
+        else {
+            return (buf + SIZE) - ptr;
+        }
+    }
+    
     // fill by reading from the given fd, return positive if some was read or -1 on error.
     int fill(int fd) noexcept
     {
         int pos = cur_idx + length;
-        if (pos >= 1024) pos -= 1024;
-        int max_count = std::min(1024 - pos, 1024 - length);
+        if (pos >= SIZE) pos -= SIZE;
+        int max_count = std::min(SIZE - pos, SIZE - length);
         ssize_t r = read(fd, buf + pos, max_count);
         if (r >= 0) {
             length += r;
@@ -29,9 +60,9 @@ class CPBuffer
         return r;
     }
     
-    // fill by readin from the given fd, until at least the specified number of bytes are in
+    // fill by reading from the given fd, until at least the specified number of bytes are in
     // the buffer. Return 0 if end-of-file reached before fill complete, or -1 on error.
-    int fillTo(int fd, int rlength) noexcept
+    int fill_to(int fd, int rlength) noexcept
     {
         while (length < rlength) {
             int r = fill(fd);
@@ -40,27 +71,35 @@ class CPBuffer
         return 1;
     }
     
-    int operator[](int idx) noexcept
+    // Trim the buffer to the specified length (must be less than current length)
+    void trim_to(int new_length)
+    {
+        length = new_length;
+    }
+    
+    char operator[](int idx) noexcept
     {
         int dest_idx = cur_idx + idx;
-        if (dest_idx > 1024) dest_idx -= 1024;
+        if (dest_idx > SIZE) dest_idx -= SIZE;
         return buf[dest_idx];
     }
     
+    // Remove the given number of bytes from the start of the buffer.
     void consume(int amount) noexcept
     {
         cur_idx += amount;
-        if (cur_idx >= 1024) cur_idx -= 1024;
+        if (cur_idx >= SIZE) cur_idx -= SIZE;
         length -= amount;
     }
     
+    // Extract bytes from the buffer. The bytes remain in the buffer.
     void extract(char *dest, int index, int length) noexcept
     {
         index += cur_idx;
-        if (index >= 1024) index -= 1024;
-        if (index + length > 1024) {
+        if (index >= SIZE) index -= SIZE;
+        if (index + length > SIZE) {
             // wrap-around copy
-            int half = 1024 - index;
+            int half = SIZE - index;
             std::memcpy(dest, buf + index, half);
             std::memcpy(dest + half, buf, length - half);
         }
@@ -69,21 +108,40 @@ class CPBuffer
         }
     }
     
-    // Extract string of give length from given index
+    // Extract string of given length from given index
     // Throws:  std::bad_alloc on allocation failure
     std::string extract_string(int index, int length)
     {
         index += cur_idx;
-        if (index >= 1024) index -= 1024;
-        if (index + length > 1024) {
-            std::string r(buf + index, 1024 - index);
-            r.insert(r.end(), buf, buf + length - (1024 - index));
+        if (index >= SIZE) index -= SIZE;
+        if (index + length > SIZE) {
+            std::string r(buf + index, SIZE - index);
+            r.insert(r.end(), buf, buf + length - (SIZE - index));
             return r;
         }
         else {
             return std::string(buf + index, length);
         }
     }
+    
+    // Append characters to the buffer. Caller must make certain there
+    // is enough space to contain the characters first.
+    void append(const char * s, int len) noexcept
+    {
+        int index = cur_idx + length;
+        if (index >= SIZE) index -= SIZE;
+
+        length += len; // (before we destroy len)
+        
+        int max = SIZE - index;
+        std::memcpy(buf + index, s, std::min(max, len));
+        if (len > max) {
+            // Wrapped around buffer: copy the rest
+            s += max;
+            len -= max;
+            std::memcpy(buf, s, len);
+        }
+    }
 };
 
 #endif