mirror of
https://github.com/lubosz/overte.git
synced 2025-08-07 19:21:16 +02:00
Adding abstracted storage for in-memory or file backed data
This commit is contained in:
parent
b4745657e0
commit
d1b91cb436
4 changed files with 258 additions and 0 deletions
86
libraries/shared/src/shared/Storage.cpp
Normal file
86
libraries/shared/src/shared/Storage.cpp
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
//
|
||||||
|
// Created by Bradley Austin Davis on 2016/02/17
|
||||||
|
// Copyright 2013-2017 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "Storage.h"
|
||||||
|
|
||||||
|
#include <QFileInfo>
|
||||||
|
|
||||||
|
using namespace storage;
|
||||||
|
|
||||||
|
MemoryStoragePointer Storage::toMemoryStorage() const {
|
||||||
|
return std::make_unique<MemoryStorage>(size(), data());
|
||||||
|
}
|
||||||
|
|
||||||
|
FileStoragePointer Storage::toFileStorage(const QString& filename) const {
|
||||||
|
return FileStorage::create(filename, size(), data());
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryStorage::MemoryStorage(size_t size, const uint8_t* data) {
|
||||||
|
_data.resize(size);
|
||||||
|
memcpy(_data.data(), data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t* MemoryStorage::data() const {
|
||||||
|
return _data.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MemoryStorage::size() const {
|
||||||
|
return _data.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
FileStoragePointer FileStorage::create(const QString& filename, size_t size, const uint8_t* data) {
|
||||||
|
QFile file(filename);
|
||||||
|
if (!file.open(QFile::ReadWrite | QIODevice::Truncate)) {
|
||||||
|
throw std::runtime_error("Unable to open file for writing");
|
||||||
|
}
|
||||||
|
if (!file.resize(size)) {
|
||||||
|
throw std::runtime_error("Unable to resize file");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto mapped = file.map(0, size);
|
||||||
|
if (!mapped) {
|
||||||
|
throw std::runtime_error("Unable to map file");
|
||||||
|
}
|
||||||
|
memcpy(mapped, data, size);
|
||||||
|
if (!file.unmap(mapped)) {
|
||||||
|
throw std::runtime_error("Unable to unmap file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
return std::make_unique<FileStorage>(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
FileStorage::FileStorage(const QString& filename) : _file(filename) {
|
||||||
|
if (!_file.open(QFile::ReadOnly)) {
|
||||||
|
throw std::runtime_error("Unable to open file");
|
||||||
|
}
|
||||||
|
_mapped = _file.map(0, _file.size());
|
||||||
|
if (!_mapped) {
|
||||||
|
throw std::runtime_error("Unable to map file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FileStorage::~FileStorage() {
|
||||||
|
if (_mapped) {
|
||||||
|
if (!_file.unmap(_mapped)) {
|
||||||
|
throw std::runtime_error("Unable to unmap file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_file.isOpen()) {
|
||||||
|
_file.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const uint8_t* FileStorage::data() const {
|
||||||
|
return _mapped;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t FileStorage::size() const {
|
||||||
|
return _file.size();
|
||||||
|
}
|
65
libraries/shared/src/shared/Storage.h
Normal file
65
libraries/shared/src/shared/Storage.h
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
//
|
||||||
|
// Created by Bradley Austin Davis on 2016/02/17
|
||||||
|
// Copyright 2013-2017 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef hifi_Storage_h
|
||||||
|
#define hifi_Storage_h
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
namespace storage {
|
||||||
|
class Storage;
|
||||||
|
using StoragePointer = std::unique_ptr<Storage>;
|
||||||
|
class MemoryStorage;
|
||||||
|
using MemoryStoragePointer = std::unique_ptr<MemoryStorage>;
|
||||||
|
class FileStorage;
|
||||||
|
using FileStoragePointer = std::unique_ptr<FileStorage>;
|
||||||
|
|
||||||
|
class Storage {
|
||||||
|
public:
|
||||||
|
virtual ~Storage() {}
|
||||||
|
virtual const uint8_t* data() const = 0;
|
||||||
|
virtual size_t size() const = 0;
|
||||||
|
|
||||||
|
FileStoragePointer toFileStorage(const QString& filename) const;
|
||||||
|
MemoryStoragePointer toMemoryStorage() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MemoryStorage : public Storage {
|
||||||
|
public:
|
||||||
|
MemoryStorage(size_t size, const uint8_t* data);
|
||||||
|
const uint8_t* data() const override;
|
||||||
|
size_t size() const override;
|
||||||
|
private:
|
||||||
|
std::vector<uint8_t> _data;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FileStorage : public Storage {
|
||||||
|
public:
|
||||||
|
static FileStoragePointer create(const QString& filename, size_t size, const uint8_t* data);
|
||||||
|
FileStorage(const QString& filename);
|
||||||
|
~FileStorage();
|
||||||
|
// Prevent copying
|
||||||
|
FileStorage(const FileStorage& other) = delete;
|
||||||
|
FileStorage& operator=(const FileStorage& other) = delete;
|
||||||
|
|
||||||
|
const uint8_t* data() const override;
|
||||||
|
size_t size() const override;
|
||||||
|
private:
|
||||||
|
QFile _file;
|
||||||
|
uint8_t* _mapped { nullptr };
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // hifi_Storage_h
|
75
tests/shared/src/StorageTests.cpp
Normal file
75
tests/shared/src/StorageTests.cpp
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
//
|
||||||
|
// Created by Bradley Austin Davis on 2016/02/17
|
||||||
|
// Copyright 2013-2017 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "StorageTests.h"
|
||||||
|
|
||||||
|
QTEST_MAIN(StorageTests)
|
||||||
|
|
||||||
|
using namespace storage;
|
||||||
|
|
||||||
|
StorageTests::StorageTests() {
|
||||||
|
for (size_t i = 0; i < _testData.size(); ++i) {
|
||||||
|
_testData[i] = (uint8_t)rand();
|
||||||
|
}
|
||||||
|
_testFile = QDir::tempPath() + "/" + QUuid::createUuid().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
StorageTests::~StorageTests() {
|
||||||
|
QFileInfo fileInfo(_testFile);
|
||||||
|
if (fileInfo.exists()) {
|
||||||
|
QFile(_testFile).remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void StorageTests::testConversion() {
|
||||||
|
{
|
||||||
|
QFileInfo fileInfo(_testFile);
|
||||||
|
QCOMPARE(fileInfo.exists(), false);
|
||||||
|
}
|
||||||
|
StoragePointer storagePointer = std::make_unique<MemoryStorage>(_testData.size(), _testData.data());
|
||||||
|
QCOMPARE(storagePointer->size(), (quint64)_testData.size());
|
||||||
|
QCOMPARE(memcmp(_testData.data(), storagePointer->data(), _testData.size()), 0);
|
||||||
|
// Convert to a file
|
||||||
|
storagePointer = storagePointer->toFileStorage(_testFile);
|
||||||
|
{
|
||||||
|
QFileInfo fileInfo(_testFile);
|
||||||
|
QCOMPARE(fileInfo.exists(), true);
|
||||||
|
QCOMPARE(fileInfo.size(), (qint64)_testData.size());
|
||||||
|
}
|
||||||
|
QCOMPARE(storagePointer->size(), (quint64)_testData.size());
|
||||||
|
QCOMPARE(memcmp(_testData.data(), storagePointer->data(), _testData.size()), 0);
|
||||||
|
|
||||||
|
// Convert to memory
|
||||||
|
storagePointer = storagePointer->toMemoryStorage();
|
||||||
|
QCOMPARE(storagePointer->size(), (quint64)_testData.size());
|
||||||
|
QCOMPARE(memcmp(_testData.data(), storagePointer->data(), _testData.size()), 0);
|
||||||
|
{
|
||||||
|
// ensure the file is unaffected
|
||||||
|
QFileInfo fileInfo(_testFile);
|
||||||
|
QCOMPARE(fileInfo.exists(), true);
|
||||||
|
QCOMPARE(fileInfo.size(), (qint64)_testData.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// truncate the data as a new memory object
|
||||||
|
auto newSize = _testData.size() / 2;
|
||||||
|
storagePointer = std::make_unique<MemoryStorage>(newSize, storagePointer->data());
|
||||||
|
QCOMPARE(storagePointer->size(), (quint64)newSize);
|
||||||
|
QCOMPARE(memcmp(_testData.data(), storagePointer->data(), newSize), 0);
|
||||||
|
|
||||||
|
// Convert back to file
|
||||||
|
storagePointer = storagePointer->toFileStorage(_testFile);
|
||||||
|
QCOMPARE(storagePointer->size(), (quint64)newSize);
|
||||||
|
QCOMPARE(memcmp(_testData.data(), storagePointer->data(), newSize), 0);
|
||||||
|
{
|
||||||
|
// ensure the file is truncated
|
||||||
|
QFileInfo fileInfo(_testFile);
|
||||||
|
QCOMPARE(fileInfo.exists(), true);
|
||||||
|
QCOMPARE(fileInfo.size(), (qint64)newSize);
|
||||||
|
}
|
||||||
|
}
|
32
tests/shared/src/StorageTests.h
Normal file
32
tests/shared/src/StorageTests.h
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
//
|
||||||
|
// Created by Bradley Austin Davis on 2016/02/17
|
||||||
|
// Copyright 2013-2017 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_StorageTests_h
|
||||||
|
#define hifi_StorageTests_h
|
||||||
|
|
||||||
|
#include <QtTest/QtTest>
|
||||||
|
|
||||||
|
#include <shared/Storage.h>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
class StorageTests : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
StorageTests();
|
||||||
|
~StorageTests();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void testConversion();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::array<uint8_t, 1025> _testData;
|
||||||
|
QString _testFile;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_StorageTests_h
|
Loading…
Reference in a new issue