// Copyright 2015 The Chromium OS Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef LIBBRILLO_BRILLO_STREAMS_MEMORY_CONTAINERS_H_ #define LIBBRILLO_BRILLO_STREAMS_MEMORY_CONTAINERS_H_ #include #include #include #include #include namespace brillo { namespace data_container { // MemoryStream class relies on helper classes defined below to support data // storage in various types of containers. // A particular implementation of container type (e.g. based on raw memory // buffers, std::vector, std::string or others) need to implement the container // interface provided by data_container::DataContainerInterface. // Low-level functionality such as reading data from and writing data to the // container, getting and changing the buffer size, and so on, must be provided. // Not all methods must be provided. For example, for read-only containers, only // read operations can be provided. class BRILLO_EXPORT DataContainerInterface { public: DataContainerInterface() = default; virtual ~DataContainerInterface() = default; // Read the data from the container into |buffer|. Up to |size_to_read| bytes // must be read at a time. The container can return fewer bytes. The actual // size of data read is provided in |size_read|. // If the read operation fails, the function must return false and provide // additional information about the error in |error| object. virtual bool Read(void* buffer, size_t size_to_read, size_t offset, size_t* size_read, ErrorPtr* error) = 0; // Writes |size_to_write| bytes of data from |buffer| into the container. // The container may accept fewer bytes of data. The actual size of data // written is provided in |size_written|. // If the read operation fails, the function must return false and provide // additional information about the error in |error| object. virtual bool Write(const void* buffer, size_t size_to_write, size_t offset, size_t* size_written, ErrorPtr* error) = 0; // Resizes the container to the new size specified in |new_size|. virtual bool Resize(size_t new_size, ErrorPtr* error) = 0; // Returns the current size of the container. virtual size_t GetSize() const = 0; // Returns true if the container is read-only. virtual bool IsReadOnly() const = 0; private: DISALLOW_COPY_AND_ASSIGN(DataContainerInterface); }; // ContiguousBufferBase is a helper base class for memory containers that // employ contiguous memory for all of their data. This class provides the // default implementation for Read() and Write() functions and requires the // implementations to provide GetBuffer() and/or ReadOnlyBuffer() functions. class BRILLO_EXPORT ContiguousBufferBase : public DataContainerInterface { public: ContiguousBufferBase() = default; // Implementation of DataContainerInterface::Read(). bool Read(void* buffer, size_t size_to_read, size_t offset, size_t* size_read, ErrorPtr* error) override; // Implementation of DataContainerInterface::Write(). bool Write(const void* buffer, size_t size_to_write, size_t offset, size_t* size_written, ErrorPtr* error) override; // Overload to provide the pointer to the read-only data for the container at // the specified |offset|. In case of an error, this function must return // nullptr and provide error details in |error| object if provided. virtual const void* GetReadOnlyBuffer(size_t offset, ErrorPtr* error) const = 0; // Overload to provide the pointer to the read/write data for the container at // the specified |offset|. In case of an error, this function must return // nullptr and provide error details in |error| object if provided. virtual void* GetBuffer(size_t offset, ErrorPtr* error) = 0; protected: // Wrapper around memcpy which can be mocked out in tests. virtual void CopyMemoryBlock(void* dest, const void* src, size_t size) const; private: DISALLOW_COPY_AND_ASSIGN(ContiguousBufferBase); }; // ContiguousReadOnlyBufferBase is a specialization of ContiguousBufferBase for // read-only containers. class BRILLO_EXPORT ContiguousReadOnlyBufferBase : public ContiguousBufferBase { public: ContiguousReadOnlyBufferBase() = default; // Fails with an error "operation_not_supported" (Stream is read-only) error. bool Write(const void* buffer, size_t size_to_write, size_t offset, size_t* size_written, ErrorPtr* error) override; // Fails with an error "operation_not_supported" (Stream is read-only) error. bool Resize(size_t new_size, ErrorPtr* error) override; // Fails with an error "operation_not_supported" (Stream is read-only) error. bool IsReadOnly() const override { return true; } // Fails with an error "operation_not_supported" (Stream is read-only) error. void* GetBuffer(size_t offset, ErrorPtr* error) override; private: DISALLOW_COPY_AND_ASSIGN(ContiguousReadOnlyBufferBase); }; // ReadOnlyBuffer implements a read-only container based on raw memory block. class BRILLO_EXPORT ReadOnlyBuffer : public ContiguousReadOnlyBufferBase { public: // Constructs the container based at the pointer to memory |buffer| and its // |size|. The pointer to the memory must be valid throughout life-time of // the stream using this container. ReadOnlyBuffer(const void* buffer, size_t size) : buffer_(buffer), size_(size) {} // Returns the pointer to data at |offset|. const void* GetReadOnlyBuffer(size_t offset, ErrorPtr* /* error */) const override { return reinterpret_cast(buffer_) + offset; } // Returns the size of the container. size_t GetSize() const override { return size_; } private: // Raw memory pointer to the data block and its size. const void* buffer_; size_t size_; DISALLOW_COPY_AND_ASSIGN(ReadOnlyBuffer); }; // VectorPtr is a read/write container based on a vector pointer. // This is a template class to allow usage of both vector and // vector without duplicating the implementation. template class VectorPtr : public ContiguousBufferBase { public: static_assert(sizeof(T) == 1, "Only char/byte is supported"); explicit VectorPtr(std::vector* vector) : vector_ptr_(vector) {} bool Resize(size_t new_size, ErrorPtr* /* error */) override { vector_ptr_->resize(new_size); return true; } size_t GetSize() const override { return vector_ptr_->size(); } bool IsReadOnly() const override { return false; } const void* GetReadOnlyBuffer(size_t offset, ErrorPtr* /* error */) const override { return reinterpret_cast(vector_ptr_->data()) + offset; } void* GetBuffer(size_t offset, ErrorPtr* /* error */) override { return reinterpret_cast(vector_ptr_->data()) + offset; } protected: std::vector* vector_ptr_; private: DISALLOW_COPY_AND_ASSIGN(VectorPtr); }; // ReadOnlyVectorRef is a read-only container based on a vector reference. // This is a template class to allow usage of both vector and // vector without duplicating the implementation. template class ReadOnlyVectorRef : public ContiguousReadOnlyBufferBase { public: static_assert(sizeof(T) == 1, "Only char/byte is supported"); explicit ReadOnlyVectorRef(const std::vector& vector) : vector_ref_(vector) {} const void* GetReadOnlyBuffer(size_t offset, ErrorPtr* /* error */) const override { return reinterpret_cast(vector_ref_.data()) + offset; } size_t GetSize() const override { return vector_ref_.size(); } protected: const std::vector& vector_ref_; private: DISALLOW_COPY_AND_ASSIGN(ReadOnlyVectorRef); }; // ReadOnlyVectorCopy is a read-only container based on a copy of vector. // This container actually owns the data stored in the vector. // This is a template class to allow usage of both vector and // vector without duplicating the implementation. template class ReadOnlyVectorCopy : public ContiguousReadOnlyBufferBase { public: static_assert(sizeof(T) == 1, "Only char/byte is supported"); explicit ReadOnlyVectorCopy(std::vector vector) : vector_copy_(std::move(vector)) {} ReadOnlyVectorCopy(const T* buffer, size_t size) : vector_copy_(buffer, buffer + size) {} const void* GetReadOnlyBuffer(size_t offset, ErrorPtr* /* error */) const override { return reinterpret_cast(vector_copy_.data()) + offset; } size_t GetSize() const override { return vector_copy_.size(); } protected: std::vector vector_copy_; private: DISALLOW_COPY_AND_ASSIGN(ReadOnlyVectorCopy); }; // ByteBuffer is a read/write container that manages the data and underlying // storage. class BRILLO_EXPORT ByteBuffer : public VectorPtr { public: explicit ByteBuffer(size_t reserve_size); ~ByteBuffer() override; private: DISALLOW_COPY_AND_ASSIGN(ByteBuffer); }; // StringPtr is a read/write container based on external std::string storage. class BRILLO_EXPORT StringPtr : public ContiguousBufferBase { public: explicit StringPtr(std::string* string); bool Resize(size_t new_size, ErrorPtr* error) override; size_t GetSize() const override { return string_ptr_->size(); } bool IsReadOnly() const override { return false; } const void* GetReadOnlyBuffer(size_t offset, ErrorPtr* error) const override; void* GetBuffer(size_t offset, ErrorPtr* error) override; protected: std::string* string_ptr_; private: DISALLOW_COPY_AND_ASSIGN(StringPtr); }; // ReadOnlyStringRef is a read-only container based on external std::string. class BRILLO_EXPORT ReadOnlyStringRef : public ContiguousReadOnlyBufferBase { public: explicit ReadOnlyStringRef(const std::string& string); const void* GetReadOnlyBuffer(size_t offset, ErrorPtr* error) const override; size_t GetSize() const override { return string_ref_.size(); } protected: const std::string& string_ref_; private: DISALLOW_COPY_AND_ASSIGN(ReadOnlyStringRef); }; // ReadOnlyStringCopy is a read-only container based on a copy of a std::string. // This container actually owns the data stored in the string. class BRILLO_EXPORT ReadOnlyStringCopy : public ReadOnlyStringRef { public: explicit ReadOnlyStringCopy(std::string string); protected: std::string string_copy_; private: DISALLOW_COPY_AND_ASSIGN(ReadOnlyStringCopy); }; } // namespace data_container } // namespace brillo #endif // LIBBRILLO_BRILLO_STREAMS_MEMORY_CONTAINERS_H_