// ---------------------------------------------------------------------- // File: PinnedBuffer.hh // Author: Georgios Bitzes - CERN // ---------------------------------------------------------------------- /************************************************************************ * quarkdb - a redis-like highly available key-value store * * Copyright (C) 2016 CERN/Switzerland * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* ************************************************************************/ #ifndef QUARKDB_PINNED_BUFFER_HH #define QUARKDB_PINNED_BUFFER_HH #include #include #include #include namespace quarkdb { class MemoryRegion; //------------------------------------------------------------------------------ // This is a buffer "pinned" to a MemoryRegion. As long as such an object is // alive, it keeps a reference to its corresponding MemoryRegion. // // This way, it's possible to tell if any given MemoryRegion has any active // buffers depending on it, and ensures the underlying MemoryRegion will not // be de-allocated from under our feet. // // It's also possible to have this object own its buffer, as an internal // std::string. // // NOTE: While we allow changing the contents of the buffer, the size is // immutable. A new object needs to be created if you want to change the // size. //------------------------------------------------------------------------------ class PinnedBuffer { public: //---------------------------------------------------------------------------- // Constructor: Make empty PinnedBuffer. //---------------------------------------------------------------------------- PinnedBuffer() {} //---------------------------------------------------------------------------- // Constructor: Pass the corresponding reference to MemoryRegion, as well as // the chunk we're pointing to. //---------------------------------------------------------------------------- PinnedBuffer(std::shared_ptr ref, char* rgptr, size_t rgsz) : region(ref), regionPtr(rgptr), regionSize(rgsz) {} //---------------------------------------------------------------------------- // Constructor: Use the internal buffer, allocate N bytes //---------------------------------------------------------------------------- PinnedBuffer(size_t n) { internalBuffer.resize(n); } //---------------------------------------------------------------------------- // Constructor: Use internal buffer, store given string_view. We do a deep // copy, this object may safely outlive the given contents. //---------------------------------------------------------------------------- PinnedBuffer(std::string_view contents) : internalBuffer(contents) {} //---------------------------------------------------------------------------- // Check if we're using internal storage or not //---------------------------------------------------------------------------- bool usingInternalBuffer() const { return region == nullptr; } //---------------------------------------------------------------------------- // Check size //---------------------------------------------------------------------------- size_t size() const { if(region != nullptr) { return regionSize; } return internalBuffer.size(); } //---------------------------------------------------------------------------- // Explicit conversion to std::string_view //---------------------------------------------------------------------------- std::string_view sv() const noexcept { if(region != nullptr) { return std::string_view(regionPtr, regionSize); } return internalBuffer; } //---------------------------------------------------------------------------- // Implicit conversion to std::string_view //---------------------------------------------------------------------------- operator std::string_view() const noexcept { return this->sv(); } //---------------------------------------------------------------------------- // Return reference to data //---------------------------------------------------------------------------- char* data() { if(region) { return regionPtr; } return internalBuffer.data(); } //---------------------------------------------------------------------------- // Return const reference to data //---------------------------------------------------------------------------- const char* data() const { if(region) { return regionPtr; } return internalBuffer.data(); } //---------------------------------------------------------------------------- // Allow access and modification of contents through brackets //---------------------------------------------------------------------------- char& operator[](size_t i) { return data()[i]; } //---------------------------------------------------------------------------- // Return internal buffer //---------------------------------------------------------------------------- std::string& getInternalBuffer() { return internalBuffer; } //---------------------------------------------------------------------------- // Equality operator with std::string_view //---------------------------------------------------------------------------- bool operator==(std::string_view sv) const { return std::string_view(*this) == sv; } //---------------------------------------------------------------------------- // Equality operator - other PinnedBuffers //---------------------------------------------------------------------------- bool operator==(const PinnedBuffer &other) const { return std::string_view(*this) == std::string_view(other); } //---------------------------------------------------------------------------- // Drop last n characters //---------------------------------------------------------------------------- void remove_suffix(size_t n) { if(region) { regionSize -= n; return; } internalBuffer.erase(internalBuffer.begin()+internalBuffer.size()-n, internalBuffer.end()); } //---------------------------------------------------------------------------- // Extract substring - no sanity checking //---------------------------------------------------------------------------- PinnedBuffer substr(size_t start, size_t size) const { if(region) { return PinnedBuffer(region, regionPtr+start, size); } PinnedBuffer retval(size); retval.internalBuffer.resize(size); memcpy(retval.internalBuffer.data(), internalBuffer.data()+start, size); return retval; } //---------------------------------------------------------------------------- // Check if empty //---------------------------------------------------------------------------- bool empty() const { return size() == 0u; } private: std::shared_ptr region; char* regionPtr = nullptr; size_t regionSize = 0u; std::string internalBuffer; }; } #endif