C++程序  |  289行  |  10.8 KB

// 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 <string>
#include <vector>

#include <brillo/brillo_export.h>
#include <brillo/errors/error.h>
#include <brillo/streams/stream.h>

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<const uint8_t*>(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<T> is a read/write container based on a vector<T> pointer.
// This is a template class to allow usage of both vector<char> and
// vector<uint8_t> without duplicating the implementation.
template<typename T>
class VectorPtr : public ContiguousBufferBase {
 public:
  static_assert(sizeof(T) == 1, "Only char/byte is supported");
  explicit VectorPtr(std::vector<T>* 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<const uint8_t*>(vector_ptr_->data()) + offset;
  }
  void* GetBuffer(size_t offset, ErrorPtr* /* error */) override {
    return reinterpret_cast<uint8_t*>(vector_ptr_->data()) + offset;
  }

 protected:
  std::vector<T>* vector_ptr_;

 private:
  DISALLOW_COPY_AND_ASSIGN(VectorPtr);
};

// ReadOnlyVectorRef<T> is a read-only container based on a vector<T> reference.
// This is a template class to allow usage of both vector<char> and
// vector<uint8_t> without duplicating the implementation.
template<typename T>
class ReadOnlyVectorRef : public ContiguousReadOnlyBufferBase {
 public:
  static_assert(sizeof(T) == 1, "Only char/byte is supported");
  explicit ReadOnlyVectorRef(const std::vector<T>& vector)
      : vector_ref_(vector) {}

  const void* GetReadOnlyBuffer(size_t offset,
                                ErrorPtr* /* error */) const override {
    return reinterpret_cast<const uint8_t*>(vector_ref_.data()) + offset;
  }
  size_t GetSize() const override { return vector_ref_.size(); }

 protected:
  const std::vector<T>& vector_ref_;

 private:
  DISALLOW_COPY_AND_ASSIGN(ReadOnlyVectorRef);
};

// ReadOnlyVectorCopy<T> is a read-only container based on a copy of vector<T>.
// This container actually owns the data stored in the vector.
// This is a template class to allow usage of both vector<char> and
// vector<uint8_t> without duplicating the implementation.
template<typename T>
class ReadOnlyVectorCopy : public ContiguousReadOnlyBufferBase {
 public:
  static_assert(sizeof(T) == 1, "Only char/byte is supported");
  explicit ReadOnlyVectorCopy(std::vector<T> 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<const uint8_t*>(vector_copy_.data()) + offset;
  }
  size_t GetSize() const override { return vector_copy_.size(); }

 protected:
  std::vector<T> 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<uint8_t> {
 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_