mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[Impeller] Delete the archivist framework. (flutter/engine#50474)
It is unused and can be brought back from Git if needed. This unnecessarily adds to binary size estimates on standalone Impeller investigations.
This commit is contained in:
parent
dcf2e52abf
commit
437c939632
@ -132,7 +132,6 @@
|
||||
../../../flutter/impeller/aiks/canvas_unittests.cc
|
||||
../../../flutter/impeller/aiks/testing
|
||||
../../../flutter/impeller/aiks/trace_serializer_unittests.cc
|
||||
../../../flutter/impeller/archivist/archivist_unittests.cc
|
||||
../../../flutter/impeller/base/README.md
|
||||
../../../flutter/impeller/base/base_unittests.cc
|
||||
../../../flutter/impeller/compiler/README.md
|
||||
|
||||
@ -4961,24 +4961,6 @@ ORIGIN: ../../../flutter/impeller/aiks/picture_recorder.cc + ../../../flutter/LI
|
||||
ORIGIN: ../../../flutter/impeller/aiks/picture_recorder.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/aiks/trace_serializer.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/aiks/trace_serializer.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/archivist/archivable.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/archivist/archivable.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/archivist/archive.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/archivist/archive.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/archivist/archive_class_registration.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/archivist/archive_class_registration.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/archivist/archive_database.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/archivist/archive_database.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/archivist/archive_location.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/archivist/archive_location.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/archivist/archive_statement.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/archivist/archive_statement.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/archivist/archive_transaction.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/archivist/archive_transaction.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/archivist/archive_vector.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/archivist/archive_vector.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/archivist/archivist_fixture.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/archivist/archivist_fixture.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/base/allocation.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/base/allocation.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/base/backend_cast.h + ../../../flutter/LICENSE
|
||||
@ -7818,24 +7800,6 @@ FILE: ../../../flutter/impeller/aiks/picture_recorder.cc
|
||||
FILE: ../../../flutter/impeller/aiks/picture_recorder.h
|
||||
FILE: ../../../flutter/impeller/aiks/trace_serializer.cc
|
||||
FILE: ../../../flutter/impeller/aiks/trace_serializer.h
|
||||
FILE: ../../../flutter/impeller/archivist/archivable.cc
|
||||
FILE: ../../../flutter/impeller/archivist/archivable.h
|
||||
FILE: ../../../flutter/impeller/archivist/archive.cc
|
||||
FILE: ../../../flutter/impeller/archivist/archive.h
|
||||
FILE: ../../../flutter/impeller/archivist/archive_class_registration.cc
|
||||
FILE: ../../../flutter/impeller/archivist/archive_class_registration.h
|
||||
FILE: ../../../flutter/impeller/archivist/archive_database.cc
|
||||
FILE: ../../../flutter/impeller/archivist/archive_database.h
|
||||
FILE: ../../../flutter/impeller/archivist/archive_location.cc
|
||||
FILE: ../../../flutter/impeller/archivist/archive_location.h
|
||||
FILE: ../../../flutter/impeller/archivist/archive_statement.cc
|
||||
FILE: ../../../flutter/impeller/archivist/archive_statement.h
|
||||
FILE: ../../../flutter/impeller/archivist/archive_transaction.cc
|
||||
FILE: ../../../flutter/impeller/archivist/archive_transaction.h
|
||||
FILE: ../../../flutter/impeller/archivist/archive_vector.cc
|
||||
FILE: ../../../flutter/impeller/archivist/archive_vector.h
|
||||
FILE: ../../../flutter/impeller/archivist/archivist_fixture.cc
|
||||
FILE: ../../../flutter/impeller/archivist/archivist_fixture.h
|
||||
FILE: ../../../flutter/impeller/base/allocation.cc
|
||||
FILE: ../../../flutter/impeller/base/allocation.h
|
||||
FILE: ../../../flutter/impeller/base/backend_cast.h
|
||||
|
||||
@ -56,7 +56,6 @@ config("impeller_public_config") {
|
||||
|
||||
group("impeller") {
|
||||
public_deps = [
|
||||
"archivist",
|
||||
"base",
|
||||
"geometry",
|
||||
"tessellator",
|
||||
@ -81,7 +80,6 @@ impeller_component("impeller_unittests") {
|
||||
testonly = true
|
||||
|
||||
deps = [
|
||||
"archivist:archivist_unittests",
|
||||
"base:base_unittests",
|
||||
"compiler:compiler_unittests",
|
||||
"core:allocator_unittests",
|
||||
|
||||
@ -60,12 +60,6 @@ states of completion:
|
||||
for a specific client rendering API. The interfaces in these targets are
|
||||
meant to be private for non-WSI user targets. No Impeller sub-frameworks
|
||||
may depend on these targets.
|
||||
* **`//impeller/archivist`**: Allows persisting objects to disk as performantly
|
||||
as possible (usually on a background thread). The framework is meant to be
|
||||
used for storing frame meta-data and related profiling/instrumentation
|
||||
information. Collection of information should succeed despite process crashes
|
||||
and retrieval of traces must not use inordinate amounts of time or memory
|
||||
(which usually leads to crashes).
|
||||
* **`//impeller/geometry`**: All (or, most of) the math! This C++ mathematics
|
||||
library is used extensively by Impeller and its clients. The reasonably
|
||||
interesting bit about this library is that all types can be used
|
||||
|
||||
@ -1,51 +0,0 @@
|
||||
# Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
import("../tools/impeller.gni")
|
||||
|
||||
impeller_component("archivist") {
|
||||
public = [
|
||||
"archivable.h",
|
||||
"archive.h",
|
||||
"archive_location.h",
|
||||
]
|
||||
|
||||
sources = [
|
||||
"archivable.cc",
|
||||
"archivable.h",
|
||||
"archive.cc",
|
||||
"archive.h",
|
||||
"archive_class_registration.cc",
|
||||
"archive_class_registration.h",
|
||||
"archive_database.cc",
|
||||
"archive_database.h",
|
||||
"archive_location.cc",
|
||||
"archive_statement.cc",
|
||||
"archive_statement.h",
|
||||
"archive_transaction.cc",
|
||||
"archive_transaction.h",
|
||||
"archive_vector.cc",
|
||||
"archive_vector.h",
|
||||
]
|
||||
|
||||
public_deps = [ "../base" ]
|
||||
|
||||
deps = [
|
||||
"//flutter/fml",
|
||||
"//flutter/third_party/sqlite",
|
||||
]
|
||||
}
|
||||
|
||||
impeller_component("archivist_unittests") {
|
||||
testonly = true
|
||||
sources = [
|
||||
"archivist_fixture.cc",
|
||||
"archivist_fixture.h",
|
||||
"archivist_unittests.cc",
|
||||
]
|
||||
deps = [
|
||||
":archivist",
|
||||
"//flutter/testing",
|
||||
]
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "impeller/archivist/archivable.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
//
|
||||
|
||||
} // namespace impeller
|
||||
@ -1,41 +0,0 @@
|
||||
// Copyright 2013 The Flutter 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 FLUTTER_IMPELLER_ARCHIVIST_ARCHIVABLE_H_
|
||||
#define FLUTTER_IMPELLER_ARCHIVIST_ARCHIVABLE_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace impeller {
|
||||
|
||||
struct ArchiveDef {
|
||||
const std::string table_name;
|
||||
const std::vector<std::string> members;
|
||||
};
|
||||
|
||||
class ArchiveLocation;
|
||||
|
||||
using PrimaryKey = std::optional<int64_t>;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// @brief Instances of `Archivable`s can be read from and written to a
|
||||
/// persistent archive.
|
||||
///
|
||||
class Archivable {
|
||||
public:
|
||||
virtual ~Archivable() = default;
|
||||
|
||||
virtual PrimaryKey GetPrimaryKey() const = 0;
|
||||
|
||||
virtual bool Write(ArchiveLocation& item) const = 0;
|
||||
|
||||
virtual bool Read(ArchiveLocation& item) = 0;
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
#endif // FLUTTER_IMPELLER_ARCHIVIST_ARCHIVABLE_H_
|
||||
@ -1,172 +0,0 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "impeller/archivist/archive.h"
|
||||
|
||||
#include "flutter/fml/logging.h"
|
||||
#include "impeller/archivist/archive_class_registration.h"
|
||||
#include "impeller/archivist/archive_database.h"
|
||||
#include "impeller/archivist/archive_location.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
Archive::Archive(const std::string& path)
|
||||
: database_(std::make_unique<ArchiveDatabase>(path)) {}
|
||||
|
||||
Archive::~Archive() {
|
||||
FML_DCHECK(transaction_count_ == 0)
|
||||
<< "There must be no pending transactions";
|
||||
}
|
||||
|
||||
bool Archive::IsValid() const {
|
||||
return database_->IsValid();
|
||||
}
|
||||
|
||||
std::optional<int64_t /* row id */> Archive::ArchiveInstance(
|
||||
const ArchiveDef& definition,
|
||||
const Archivable& archivable) {
|
||||
if (!IsValid()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto transaction = database_->CreateTransaction(transaction_count_);
|
||||
|
||||
const auto* registration =
|
||||
database_->GetRegistrationForDefinition(definition);
|
||||
|
||||
if (registration == nullptr) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto statement = registration->CreateInsertStatement();
|
||||
|
||||
if (!statement.IsValid() || !statement.Reset()) {
|
||||
/*
|
||||
* Must be able to reset the statement for a new write
|
||||
*/
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto primary_key = archivable.GetPrimaryKey();
|
||||
|
||||
/*
|
||||
* The lifecycle of the archive item is tied to this scope and there is no
|
||||
* way for the user to create an instance of an archive item. So its safe
|
||||
* for its members to be references. It does not manage the lifetimes of
|
||||
* anything.
|
||||
*/
|
||||
ArchiveLocation item(*this, statement, *registration, primary_key);
|
||||
|
||||
/*
|
||||
* If the item provides its own primary key, we need to bind it now.
|
||||
* Otherwise, one will be automatically assigned to it.
|
||||
*/
|
||||
if (primary_key.has_value() &&
|
||||
!statement.WriteValue(ArchiveClassRegistration::kPrimaryKeyIndex,
|
||||
primary_key.value())) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (!archivable.Write(item)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (statement.Execute() != ArchiveStatement::Result::kDone) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
int64_t lastInsert = database_->GetLastInsertRowID();
|
||||
|
||||
if (primary_key.has_value() &&
|
||||
lastInsert != static_cast<int64_t>(primary_key.value())) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/*
|
||||
* If any of the nested calls fail, we would have already checked for the
|
||||
* failure and returned.
|
||||
*/
|
||||
transaction.MarkWritesAsReadyForCommit();
|
||||
|
||||
return lastInsert;
|
||||
}
|
||||
|
||||
bool Archive::UnarchiveInstance(const ArchiveDef& definition,
|
||||
PrimaryKey name,
|
||||
Archivable& archivable) {
|
||||
UnarchiveStep stepper = [&archivable](ArchiveLocation& item) {
|
||||
archivable.Read(item);
|
||||
return false /* no-more after single read */;
|
||||
};
|
||||
|
||||
return UnarchiveInstances(definition, stepper, name) == 1;
|
||||
}
|
||||
|
||||
size_t Archive::UnarchiveInstances(const ArchiveDef& definition,
|
||||
const Archive::UnarchiveStep& stepper,
|
||||
PrimaryKey primary_key) {
|
||||
if (!IsValid()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto* registration =
|
||||
database_->GetRegistrationForDefinition(definition);
|
||||
|
||||
if (registration == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const bool isQueryingSingle = primary_key.has_value();
|
||||
|
||||
auto statement = registration->CreateQueryStatement(isQueryingSingle);
|
||||
|
||||
if (!statement.IsValid() || !statement.Reset()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (isQueryingSingle) {
|
||||
/*
|
||||
* If a single statement is being queried for, bind the primary key as a
|
||||
* statement argument.
|
||||
*/
|
||||
if (!statement.WriteValue(ArchiveClassRegistration::kPrimaryKeyIndex,
|
||||
primary_key.value())) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (statement.GetColumnCount() !=
|
||||
registration->GetMemberCount() + 1 /* primary key */) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Acquire a transaction but never mark it successful since we will never
|
||||
* be committing any writes to the database during unarchiving.
|
||||
*/
|
||||
auto transaction = database_->CreateTransaction(transaction_count_);
|
||||
|
||||
size_t itemsRead = 0;
|
||||
|
||||
while (statement.Execute() == ArchiveStatement::Result::kRow) {
|
||||
itemsRead++;
|
||||
|
||||
/*
|
||||
* Prepare a fresh archive item for the given statement
|
||||
*/
|
||||
ArchiveLocation item(*this, statement, *registration, primary_key);
|
||||
|
||||
if (!stepper(item)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (isQueryingSingle) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return itemsRead;
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
@ -1,77 +0,0 @@
|
||||
// Copyright 2013 The Flutter 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 FLUTTER_IMPELLER_ARCHIVIST_ARCHIVE_H_
|
||||
#define FLUTTER_IMPELLER_ARCHIVIST_ARCHIVE_H_
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#include "impeller/archivist/archivable.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
class ArchiveLocation;
|
||||
class ArchiveDatabase;
|
||||
|
||||
class Archive {
|
||||
public:
|
||||
explicit Archive(const std::string& path);
|
||||
|
||||
~Archive();
|
||||
|
||||
bool IsValid() const;
|
||||
|
||||
template <class T,
|
||||
class = std::enable_if_t<std::is_base_of<Archivable, T>::value>>
|
||||
[[nodiscard]] bool Write(const T& archivable) {
|
||||
const ArchiveDef& def = T::kArchiveDefinition;
|
||||
return ArchiveInstance(def, archivable).has_value();
|
||||
}
|
||||
|
||||
template <class T,
|
||||
class = std::enable_if_t<std::is_base_of<Archivable, T>::value>>
|
||||
[[nodiscard]] bool Read(PrimaryKey name, T& archivable) {
|
||||
const ArchiveDef& def = T::kArchiveDefinition;
|
||||
return UnarchiveInstance(def, name, archivable);
|
||||
}
|
||||
|
||||
using UnarchiveStep = std::function<bool(ArchiveLocation&)>;
|
||||
|
||||
template <class T,
|
||||
class = std::enable_if_t<std::is_base_of<Archivable, T>::value>>
|
||||
[[nodiscard]] size_t Read(const UnarchiveStep& stepper) {
|
||||
const ArchiveDef& def = T::kArchiveDefinition;
|
||||
return UnarchiveInstances(def, stepper);
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<ArchiveDatabase> database_;
|
||||
int64_t transaction_count_ = 0;
|
||||
|
||||
friend class ArchiveLocation;
|
||||
|
||||
std::optional<int64_t /* row id */> ArchiveInstance(
|
||||
const ArchiveDef& definition,
|
||||
const Archivable& archivable);
|
||||
|
||||
bool UnarchiveInstance(const ArchiveDef& definition,
|
||||
PrimaryKey name,
|
||||
Archivable& archivable);
|
||||
|
||||
size_t UnarchiveInstances(const ArchiveDef& definition,
|
||||
const UnarchiveStep& stepper,
|
||||
PrimaryKey primary_key = std::nullopt);
|
||||
|
||||
Archive(const Archive&) = delete;
|
||||
|
||||
Archive& operator=(const Archive&) = delete;
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
#endif // FLUTTER_IMPELLER_ARCHIVIST_ARCHIVE_H_
|
||||
@ -1,124 +0,0 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "impeller/archivist/archive_class_registration.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "impeller/archivist/archive_database.h"
|
||||
#include "impeller/archivist/archive_statement.h"
|
||||
#include "impeller/base/validation.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
static constexpr const char* kArchivePrimaryKeyColumnName = "primary_key";
|
||||
|
||||
ArchiveClassRegistration::ArchiveClassRegistration(ArchiveDatabase& database,
|
||||
ArchiveDef definition)
|
||||
: database_(database), definition_(std::move(definition)) {
|
||||
for (size_t i = 0; i < definition_.members.size(); i++) {
|
||||
// The first index entry is the primary key. So add one to the index.
|
||||
column_map_[definition_.members[i]] = i + 1;
|
||||
}
|
||||
is_valid_ = CreateTable();
|
||||
}
|
||||
|
||||
const std::string& ArchiveClassRegistration::GetClassName() const {
|
||||
return definition_.table_name;
|
||||
}
|
||||
|
||||
size_t ArchiveClassRegistration::GetMemberCount() const {
|
||||
return column_map_.size();
|
||||
}
|
||||
|
||||
bool ArchiveClassRegistration::IsValid() const {
|
||||
return is_valid_;
|
||||
}
|
||||
|
||||
std::optional<size_t> ArchiveClassRegistration::FindColumnIndex(
|
||||
const std::string& member) const {
|
||||
auto found = column_map_.find(member);
|
||||
if (found == column_map_.end()) {
|
||||
VALIDATION_LOG << "No member named '" << member << "' in class '"
|
||||
<< definition_.table_name
|
||||
<< "'. Did you forget to register it?";
|
||||
return std::nullopt;
|
||||
}
|
||||
return found->second;
|
||||
}
|
||||
|
||||
bool ArchiveClassRegistration::CreateTable() {
|
||||
if (definition_.table_name.empty() || definition_.members.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::stringstream stream;
|
||||
|
||||
/*
|
||||
* Table names cannot participate in parameter substitution, so we prepare
|
||||
* a statement and check its validity before running.
|
||||
*/
|
||||
stream << "CREATE TABLE IF NOT EXISTS " << definition_.table_name << " ("
|
||||
<< kArchivePrimaryKeyColumnName << " INTEGER PRIMARY KEY, ";
|
||||
|
||||
for (size_t i = 0, columns = definition_.members.size(); i < columns; i++) {
|
||||
stream << definition_.members[i];
|
||||
if (i != columns - 1) {
|
||||
stream << ", ";
|
||||
}
|
||||
}
|
||||
stream << ");";
|
||||
|
||||
auto statement = database_.CreateStatement(stream.str());
|
||||
|
||||
if (!statement.IsValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!statement.Reset()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return statement.Execute() == ArchiveStatement::Result::kDone;
|
||||
}
|
||||
|
||||
ArchiveStatement ArchiveClassRegistration::CreateQueryStatement(
|
||||
bool single) const {
|
||||
std::stringstream stream;
|
||||
stream << "SELECT " << kArchivePrimaryKeyColumnName << ", ";
|
||||
for (size_t i = 0, columns = definition_.members.size(); i < columns; i++) {
|
||||
stream << definition_.members[i];
|
||||
if (i != columns - 1) {
|
||||
stream << ",";
|
||||
}
|
||||
}
|
||||
stream << " FROM " << definition_.table_name;
|
||||
|
||||
if (single) {
|
||||
stream << " WHERE " << kArchivePrimaryKeyColumnName << " = ?";
|
||||
} else {
|
||||
stream << " ORDER BY " << kArchivePrimaryKeyColumnName << " ASC";
|
||||
}
|
||||
|
||||
stream << ";";
|
||||
|
||||
return database_.CreateStatement(stream.str());
|
||||
}
|
||||
|
||||
ArchiveStatement ArchiveClassRegistration::CreateInsertStatement() const {
|
||||
std::stringstream stream;
|
||||
stream << "INSERT OR REPLACE INTO " << definition_.table_name
|
||||
<< " VALUES ( ?, ";
|
||||
for (size_t i = 0, columns = definition_.members.size(); i < columns; i++) {
|
||||
stream << "?";
|
||||
if (i != columns - 1) {
|
||||
stream << ", ";
|
||||
}
|
||||
}
|
||||
stream << ");";
|
||||
|
||||
return database_.CreateStatement(stream.str());
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
@ -1,54 +0,0 @@
|
||||
// Copyright 2013 The Flutter 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 FLUTTER_IMPELLER_ARCHIVIST_ARCHIVE_CLASS_REGISTRATION_H_
|
||||
#define FLUTTER_IMPELLER_ARCHIVIST_ARCHIVE_CLASS_REGISTRATION_H_
|
||||
|
||||
#include <map>
|
||||
#include <optional>
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "impeller/archivist/archive.h"
|
||||
#include "impeller/archivist/archive_statement.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
class ArchiveClassRegistration {
|
||||
public:
|
||||
static constexpr size_t kPrimaryKeyIndex = 0u;
|
||||
|
||||
bool IsValid() const;
|
||||
|
||||
std::optional<size_t> FindColumnIndex(const std::string& member) const;
|
||||
|
||||
const std::string& GetClassName() const;
|
||||
|
||||
size_t GetMemberCount() const;
|
||||
|
||||
ArchiveStatement CreateInsertStatement() const;
|
||||
|
||||
ArchiveStatement CreateQueryStatement(bool single) const;
|
||||
|
||||
private:
|
||||
using MemberColumnMap = std::map<std::string, size_t>;
|
||||
|
||||
friend class ArchiveDatabase;
|
||||
|
||||
ArchiveClassRegistration(ArchiveDatabase& database, ArchiveDef definition);
|
||||
|
||||
bool CreateTable();
|
||||
|
||||
ArchiveDatabase& database_;
|
||||
const ArchiveDef definition_;
|
||||
MemberColumnMap column_map_;
|
||||
bool is_valid_ = false;
|
||||
|
||||
ArchiveClassRegistration(const ArchiveClassRegistration&) = delete;
|
||||
|
||||
ArchiveClassRegistration& operator=(const ArchiveClassRegistration&) = delete;
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
#endif // FLUTTER_IMPELLER_ARCHIVIST_ARCHIVE_CLASS_REGISTRATION_H_
|
||||
@ -1,143 +0,0 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "impeller/archivist/archive_database.h"
|
||||
|
||||
#include "third_party/sqlite/sqlite3.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "impeller/archivist/archive.h"
|
||||
#include "impeller/archivist/archive_class_registration.h"
|
||||
#include "impeller/archivist/archive_statement.h"
|
||||
#include "impeller/base/validation.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
struct ArchiveDatabase::Handle {
|
||||
explicit Handle(const std::string& filename) {
|
||||
if (::sqlite3_initialize() != SQLITE_OK) {
|
||||
VALIDATION_LOG << "Could not initialize sqlite.";
|
||||
return;
|
||||
}
|
||||
|
||||
sqlite3* db = nullptr;
|
||||
auto res = ::sqlite3_open(filename.c_str(), &db);
|
||||
|
||||
if (res != SQLITE_OK || db == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
handle_ = db;
|
||||
}
|
||||
|
||||
~Handle() {
|
||||
if (handle_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
::sqlite3_close(handle_);
|
||||
}
|
||||
|
||||
::sqlite3* Get() const { return handle_; }
|
||||
|
||||
bool IsValid() const { return handle_ != nullptr; }
|
||||
|
||||
private:
|
||||
::sqlite3* handle_ = nullptr;
|
||||
|
||||
Handle(const Handle&) = delete;
|
||||
|
||||
Handle& operator=(const Handle&) = delete;
|
||||
};
|
||||
|
||||
ArchiveDatabase::ArchiveDatabase(const std::string& filename)
|
||||
: handle_(std::make_unique<Handle>(filename)) {
|
||||
if (!handle_->IsValid()) {
|
||||
handle_.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
begin_transaction_stmt_ = std::unique_ptr<ArchiveStatement>(
|
||||
new ArchiveStatement(handle_->Get(), "BEGIN TRANSACTION;"));
|
||||
|
||||
if (!begin_transaction_stmt_->IsValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
end_transaction_stmt_ = std::unique_ptr<ArchiveStatement>(
|
||||
new ArchiveStatement(handle_->Get(), "END TRANSACTION;"));
|
||||
|
||||
if (!end_transaction_stmt_->IsValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
rollback_transaction_stmt_ = std::unique_ptr<ArchiveStatement>(
|
||||
new ArchiveStatement(handle_->Get(), "ROLLBACK TRANSACTION;"));
|
||||
|
||||
if (!rollback_transaction_stmt_->IsValid()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ArchiveDatabase::~ArchiveDatabase() = default;
|
||||
|
||||
bool ArchiveDatabase::IsValid() const {
|
||||
return handle_ != nullptr;
|
||||
}
|
||||
|
||||
int64_t ArchiveDatabase::GetLastInsertRowID() {
|
||||
if (!IsValid()) {
|
||||
return 0u;
|
||||
}
|
||||
return ::sqlite3_last_insert_rowid(handle_->Get());
|
||||
}
|
||||
|
||||
static inline const ArchiveClassRegistration* RegistrationIfReady(
|
||||
const ArchiveClassRegistration* registration) {
|
||||
if (registration == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return registration->IsValid() ? registration : nullptr;
|
||||
}
|
||||
|
||||
const ArchiveClassRegistration* ArchiveDatabase::GetRegistrationForDefinition(
|
||||
const ArchiveDef& definition) {
|
||||
auto found = registrations_.find(definition.table_name);
|
||||
if (found != registrations_.end()) {
|
||||
/*
|
||||
* This class has already been registered.
|
||||
*/
|
||||
return RegistrationIfReady(found->second.get());
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize a new class registration for the given class definition.
|
||||
*/
|
||||
auto registration = std::unique_ptr<ArchiveClassRegistration>(
|
||||
new ArchiveClassRegistration(*this, definition));
|
||||
auto res =
|
||||
registrations_.emplace(definition.table_name, std::move(registration));
|
||||
|
||||
/*
|
||||
* If the new class registration is ready, return it to the caller.
|
||||
*/
|
||||
return res.second ? RegistrationIfReady((*(res.first)).second.get())
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
ArchiveStatement ArchiveDatabase::CreateStatement(
|
||||
const std::string& statementString) const {
|
||||
return ArchiveStatement{handle_ ? handle_->Get() : nullptr, statementString};
|
||||
}
|
||||
|
||||
ArchiveTransaction ArchiveDatabase::CreateTransaction(
|
||||
int64_t& transactionCount) {
|
||||
return ArchiveTransaction{transactionCount, //
|
||||
*begin_transaction_stmt_, //
|
||||
*end_transaction_stmt_, //
|
||||
*rollback_transaction_stmt_};
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
@ -1,58 +0,0 @@
|
||||
// Copyright 2013 The Flutter 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 FLUTTER_IMPELLER_ARCHIVIST_ARCHIVE_DATABASE_H_
|
||||
#define FLUTTER_IMPELLER_ARCHIVIST_ARCHIVE_DATABASE_H_
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "impeller/archivist/archive_transaction.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
class ArchiveStatement;
|
||||
class ArchiveClassRegistration;
|
||||
struct ArchiveDef;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// @brief A handle to the underlying database connection for an archive.
|
||||
///
|
||||
class ArchiveDatabase {
|
||||
public:
|
||||
explicit ArchiveDatabase(const std::string& filename);
|
||||
|
||||
~ArchiveDatabase();
|
||||
|
||||
bool IsValid() const;
|
||||
|
||||
int64_t GetLastInsertRowID();
|
||||
|
||||
const ArchiveClassRegistration* GetRegistrationForDefinition(
|
||||
const ArchiveDef& definition);
|
||||
|
||||
ArchiveTransaction CreateTransaction(int64_t& transactionCount);
|
||||
|
||||
private:
|
||||
struct Handle;
|
||||
std::unique_ptr<Handle> handle_;
|
||||
std::map<std::string, std::unique_ptr<ArchiveClassRegistration>>
|
||||
registrations_;
|
||||
std::unique_ptr<ArchiveStatement> begin_transaction_stmt_;
|
||||
std::unique_ptr<ArchiveStatement> end_transaction_stmt_;
|
||||
std::unique_ptr<ArchiveStatement> rollback_transaction_stmt_;
|
||||
|
||||
friend class ArchiveClassRegistration;
|
||||
|
||||
ArchiveStatement CreateStatement(const std::string& statementString) const;
|
||||
|
||||
ArchiveDatabase(const ArchiveDatabase&) = delete;
|
||||
|
||||
ArchiveDatabase& operator=(const ArchiveDatabase&) = delete;
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
#endif // FLUTTER_IMPELLER_ARCHIVIST_ARCHIVE_DATABASE_H_
|
||||
@ -1,143 +0,0 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "impeller/archivist/archive_location.h"
|
||||
|
||||
#include "impeller/archivist/archive_class_registration.h"
|
||||
#include "impeller/archivist/archive_vector.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
ArchiveLocation::ArchiveLocation(Archive& context,
|
||||
ArchiveStatement& statement,
|
||||
const ArchiveClassRegistration& registration,
|
||||
PrimaryKey name)
|
||||
: context_(context),
|
||||
statement_(statement),
|
||||
registration_(registration),
|
||||
primary_key_(name) {}
|
||||
|
||||
PrimaryKey ArchiveLocation::GetPrimaryKey() const {
|
||||
return primary_key_;
|
||||
}
|
||||
|
||||
bool ArchiveLocation::Write(const std::string& member,
|
||||
const std::string& item) {
|
||||
auto index = registration_.FindColumnIndex(member);
|
||||
return index.has_value() ? statement_.WriteValue(index.value(), item) : false;
|
||||
}
|
||||
|
||||
bool ArchiveLocation::WriteIntegral(const std::string& member, int64_t item) {
|
||||
auto index = registration_.FindColumnIndex(member);
|
||||
return index.has_value() ? statement_.WriteValue(index.value(), item) : false;
|
||||
}
|
||||
|
||||
bool ArchiveLocation::Write(const std::string& member, double item) {
|
||||
auto index = registration_.FindColumnIndex(member);
|
||||
return index.has_value() ? statement_.WriteValue(index.value(), item) : false;
|
||||
}
|
||||
|
||||
bool ArchiveLocation::Write(const std::string& member, const Allocation& item) {
|
||||
auto index = registration_.FindColumnIndex(member);
|
||||
return index.has_value() ? statement_.WriteValue(index.value(), item) : false;
|
||||
}
|
||||
|
||||
bool ArchiveLocation::Write(const std::string& member,
|
||||
const ArchiveDef& otherDef,
|
||||
const Archivable& other) {
|
||||
auto index = registration_.FindColumnIndex(member);
|
||||
|
||||
if (!index.has_value()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to fully archive the other instance first because it could
|
||||
* have a name that is auto assigned. In that case, we cannot ask it before
|
||||
* archival (via `other.archiveName()`).
|
||||
*/
|
||||
auto row_id = context_.ArchiveInstance(otherDef, other);
|
||||
if (!row_id.has_value()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Bind the name of the serializable
|
||||
*/
|
||||
if (!statement_.WriteValue(index.value(), row_id.value())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<int64_t> ArchiveLocation::WriteVectorKeys(
|
||||
std::vector<int64_t>&& members) {
|
||||
ArchiveVector vector(std::move(members));
|
||||
return context_.ArchiveInstance(ArchiveVector::kArchiveDefinition, vector);
|
||||
}
|
||||
|
||||
bool ArchiveLocation::ReadVectorKeys(PrimaryKey name,
|
||||
std::vector<int64_t>& members) {
|
||||
ArchiveVector vector;
|
||||
if (!context_.UnarchiveInstance(ArchiveVector::kArchiveDefinition, name,
|
||||
vector)) {
|
||||
return false;
|
||||
}
|
||||
const auto& keys = vector.GetKeys();
|
||||
std::move(keys.begin(), keys.end(), std::back_inserter(members));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArchiveLocation::Read(const std::string& member, std::string& item) {
|
||||
auto index = registration_.FindColumnIndex(member);
|
||||
return index.has_value() ? statement_.ReadValue(index.value(), item) : false;
|
||||
}
|
||||
|
||||
bool ArchiveLocation::ReadIntegral(const std::string& member, int64_t& item) {
|
||||
auto index = registration_.FindColumnIndex(member);
|
||||
return index.has_value() ? statement_.ReadValue(index.value(), item) : false;
|
||||
}
|
||||
|
||||
bool ArchiveLocation::Read(const std::string& member, double& item) {
|
||||
auto index = registration_.FindColumnIndex(member);
|
||||
return index.has_value() ? statement_.ReadValue(index.value(), item) : false;
|
||||
}
|
||||
|
||||
bool ArchiveLocation::Read(const std::string& member, Allocation& item) {
|
||||
auto index = registration_.FindColumnIndex(member);
|
||||
return index.has_value() ? statement_.ReadValue(index.value(), item) : false;
|
||||
}
|
||||
|
||||
bool ArchiveLocation::Read(const std::string& member,
|
||||
const ArchiveDef& otherDef,
|
||||
Archivable& other) {
|
||||
auto index = registration_.FindColumnIndex(member);
|
||||
|
||||
/*
|
||||
* Make sure a member is present at that column
|
||||
*/
|
||||
if (!index.has_value()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to find the foreign key in the current items row
|
||||
*/
|
||||
int64_t foreignKey = 0;
|
||||
if (!statement_.ReadValue(index.value(), foreignKey)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the other item and unarchive by this foreign key
|
||||
*/
|
||||
if (!context_.UnarchiveInstance(otherDef, foreignKey, other)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
@ -1,176 +0,0 @@
|
||||
// Copyright 2013 The Flutter 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 FLUTTER_IMPELLER_ARCHIVIST_ARCHIVE_LOCATION_H_
|
||||
#define FLUTTER_IMPELLER_ARCHIVIST_ARCHIVE_LOCATION_H_
|
||||
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
|
||||
#include "impeller/archivist/archivable.h"
|
||||
#include "impeller/archivist/archive.h"
|
||||
#include "impeller/base/allocation.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
class Archive;
|
||||
class ArchiveClassRegistration;
|
||||
class ArchiveStatement;
|
||||
|
||||
class ArchiveLocation {
|
||||
public:
|
||||
PrimaryKey GetPrimaryKey() const;
|
||||
|
||||
template <class T, class = std::enable_if_t<std::is_integral<T>::value>>
|
||||
bool Write(const std::string& member, T item) {
|
||||
return WriteIntegral(member, static_cast<int64_t>(item));
|
||||
}
|
||||
|
||||
bool Write(const std::string& member, double item);
|
||||
|
||||
bool Write(const std::string& member, const std::string& item);
|
||||
|
||||
bool Write(const std::string& member, const Allocation& allocation);
|
||||
|
||||
template <class T,
|
||||
class = std::enable_if_t<std::is_base_of<Archivable, T>::value>>
|
||||
bool WriteArchivable(const std::string& member, const T& other) {
|
||||
const ArchiveDef& otherDef = T::ArchiveDefinition;
|
||||
return Write(member, otherDef, other);
|
||||
}
|
||||
|
||||
template <class T, class = std::enable_if_t<std::is_enum<T>::value>>
|
||||
bool WriteEnum(const std::string& member, const T& item) {
|
||||
return WriteIntegral(member, static_cast<int64_t>(item));
|
||||
}
|
||||
|
||||
template <class T,
|
||||
class = std::enable_if_t<std::is_base_of<Archivable, T>::value>>
|
||||
bool Write(const std::string& member, const std::vector<T>& items) {
|
||||
/*
|
||||
* All items in the vector are individually encoded and their keys noted
|
||||
*/
|
||||
std::vector<int64_t> members;
|
||||
members.reserve(items.size());
|
||||
|
||||
const ArchiveDef& itemDefinition = T::kArchiveDefinition;
|
||||
for (const auto& item : items) {
|
||||
auto row_id = context_.ArchiveInstance(itemDefinition, item);
|
||||
if (!row_id.has_value()) {
|
||||
return false;
|
||||
}
|
||||
members.emplace_back(row_id.value());
|
||||
}
|
||||
|
||||
/*
|
||||
* The keys are flattened into the vectors table. Write to that table
|
||||
*/
|
||||
auto vectorInsert = WriteVectorKeys(std::move(members));
|
||||
|
||||
if (!vectorInsert.has_value()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return WriteIntegral(member, vectorInsert.value());
|
||||
}
|
||||
|
||||
template <class T, class = std::enable_if_t<std::is_integral<T>::value>>
|
||||
bool Read(const std::string& member, T& item) {
|
||||
int64_t decoded = 0;
|
||||
auto result = ReadIntegral(member, decoded);
|
||||
item = static_cast<T>(decoded);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Read(const std::string& member, double& item);
|
||||
|
||||
bool Read(const std::string& member, std::string& item);
|
||||
|
||||
bool Read(const std::string& member, Allocation& allocation);
|
||||
|
||||
template <class T,
|
||||
class = std::enable_if_t<std::is_base_of<Archivable, T>::value>>
|
||||
bool ReadArchivable(const std::string& member, T& other) {
|
||||
const ArchiveDef& otherDef = T::ArchiveDefinition;
|
||||
return decode(member, otherDef, other);
|
||||
}
|
||||
|
||||
template <class T, class = std::enable_if_t<std::is_enum<T>::value>>
|
||||
bool ReadEnum(const std::string& member, T& item) {
|
||||
int64_t desugared = 0;
|
||||
if (ReadIntegral(member, desugared)) {
|
||||
item = static_cast<T>(desugared);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class T,
|
||||
class = std::enable_if_t<std::is_base_of<Archivable, T>::value>>
|
||||
bool Read(const std::string& member, std::vector<T>& items) {
|
||||
/*
|
||||
* From the member, find the foreign key of the vector
|
||||
*/
|
||||
int64_t vectorForeignKey = 0;
|
||||
if (!ReadIntegral(member, vectorForeignKey)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get vector keys
|
||||
*/
|
||||
std::vector<int64_t> keys;
|
||||
if (!ReadVectorKeys(vectorForeignKey, keys)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const ArchiveDef& otherDef = T::kArchiveDefinition;
|
||||
for (const auto& key : keys) {
|
||||
items.emplace_back();
|
||||
|
||||
if (!context_.UnarchiveInstance(otherDef, key, items.back())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
Archive& context_;
|
||||
ArchiveStatement& statement_;
|
||||
const ArchiveClassRegistration& registration_;
|
||||
PrimaryKey primary_key_;
|
||||
|
||||
friend class Archive;
|
||||
|
||||
ArchiveLocation(Archive& context,
|
||||
ArchiveStatement& statement,
|
||||
const ArchiveClassRegistration& registration,
|
||||
PrimaryKey name);
|
||||
|
||||
bool WriteIntegral(const std::string& member, int64_t item);
|
||||
|
||||
bool ReadIntegral(const std::string& member, int64_t& item);
|
||||
|
||||
std::optional<int64_t> WriteVectorKeys(std::vector<int64_t>&& members);
|
||||
|
||||
bool ReadVectorKeys(PrimaryKey name, std::vector<int64_t>& members);
|
||||
|
||||
bool Write(const std::string& member,
|
||||
const ArchiveDef& otherDef,
|
||||
const Archivable& other);
|
||||
|
||||
bool Read(const std::string& member,
|
||||
const ArchiveDef& otherDef,
|
||||
Archivable& other);
|
||||
|
||||
ArchiveLocation(const ArchiveLocation&) = delete;
|
||||
|
||||
ArchiveLocation& operator=(const ArchiveLocation&) = delete;
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
#endif // FLUTTER_IMPELLER_ARCHIVIST_ARCHIVE_LOCATION_H_
|
||||
@ -1,231 +0,0 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "impeller/archivist/archive_statement.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "flutter/fml/logging.h"
|
||||
#include "third_party/sqlite/sqlite3.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
struct ArchiveStatement::Handle {
|
||||
Handle(void* db, const std::string& statememt) {
|
||||
if (db == nullptr) {
|
||||
return;
|
||||
}
|
||||
::sqlite3_stmt* handle = nullptr;
|
||||
if (::sqlite3_prepare_v2(reinterpret_cast<sqlite3*>(db), //
|
||||
statememt.c_str(), //
|
||||
static_cast<int>(statememt.size()), //
|
||||
&handle, //
|
||||
nullptr) == SQLITE_OK) {
|
||||
handle_ = handle;
|
||||
}
|
||||
}
|
||||
|
||||
~Handle() {
|
||||
if (handle_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
auto res = ::sqlite3_finalize(handle_);
|
||||
FML_CHECK(res == SQLITE_OK) << "Unable to finalize the archive.";
|
||||
}
|
||||
|
||||
bool IsValid() const { return handle_ != nullptr; }
|
||||
|
||||
::sqlite3_stmt* Get() const { return handle_; }
|
||||
|
||||
private:
|
||||
::sqlite3_stmt* handle_ = nullptr;
|
||||
|
||||
Handle(const Handle&) = delete;
|
||||
|
||||
Handle& operator=(const Handle&) = delete;
|
||||
};
|
||||
|
||||
ArchiveStatement::ArchiveStatement(void* db, const std::string& statememt)
|
||||
: statement_handle_(std::make_unique<Handle>(db, statememt)) {
|
||||
if (!statement_handle_->IsValid()) {
|
||||
statement_handle_.reset();
|
||||
}
|
||||
}
|
||||
|
||||
ArchiveStatement::~ArchiveStatement() = default;
|
||||
|
||||
bool ArchiveStatement::IsValid() const {
|
||||
return statement_handle_ != nullptr;
|
||||
}
|
||||
|
||||
bool ArchiveStatement::Reset() {
|
||||
if (!IsValid()) {
|
||||
return false;
|
||||
}
|
||||
if (::sqlite3_reset(statement_handle_->Get()) != SQLITE_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (::sqlite3_clear_bindings(statement_handle_->Get()) != SQLITE_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static constexpr int ToParam(size_t index) {
|
||||
/*
|
||||
* sqlite parameters begin from 1
|
||||
*/
|
||||
return static_cast<int>(index + 1);
|
||||
}
|
||||
|
||||
static constexpr int ToColumn(size_t index) {
|
||||
/*
|
||||
* sqlite columns begin from 0
|
||||
*/
|
||||
return static_cast<int>(index);
|
||||
}
|
||||
|
||||
size_t ArchiveStatement::GetColumnCount() {
|
||||
if (!IsValid()) {
|
||||
return 0u;
|
||||
}
|
||||
return ::sqlite3_column_count(statement_handle_->Get());
|
||||
}
|
||||
|
||||
/*
|
||||
* Bind Variants
|
||||
*/
|
||||
bool ArchiveStatement::WriteValue(size_t index, const std::string& item) {
|
||||
if (!IsValid()) {
|
||||
return false;
|
||||
}
|
||||
return ::sqlite3_bind_text(statement_handle_->Get(), //
|
||||
ToParam(index), //
|
||||
item.data(), //
|
||||
static_cast<int>(item.size()), //
|
||||
SQLITE_TRANSIENT) == SQLITE_OK;
|
||||
}
|
||||
|
||||
bool ArchiveStatement::BindIntegral(size_t index, int64_t item) {
|
||||
if (!IsValid()) {
|
||||
return false;
|
||||
}
|
||||
return ::sqlite3_bind_int64(statement_handle_->Get(), //
|
||||
ToParam(index), //
|
||||
item) == SQLITE_OK;
|
||||
}
|
||||
|
||||
bool ArchiveStatement::WriteValue(size_t index, double item) {
|
||||
if (!IsValid()) {
|
||||
return false;
|
||||
}
|
||||
return ::sqlite3_bind_double(statement_handle_->Get(), //
|
||||
ToParam(index), //
|
||||
item) == SQLITE_OK;
|
||||
}
|
||||
|
||||
bool ArchiveStatement::WriteValue(size_t index, const Allocation& item) {
|
||||
if (!IsValid()) {
|
||||
return false;
|
||||
}
|
||||
return ::sqlite3_bind_blob(statement_handle_->Get(), //
|
||||
ToParam(index), //
|
||||
item.GetBuffer(), //
|
||||
static_cast<int>(item.GetLength()), //
|
||||
SQLITE_TRANSIENT) == SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Column Variants
|
||||
*/
|
||||
bool ArchiveStatement::ColumnIntegral(size_t index, int64_t& item) {
|
||||
if (!IsValid()) {
|
||||
return false;
|
||||
}
|
||||
item = ::sqlite3_column_int64(statement_handle_->Get(), ToColumn(index));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArchiveStatement::ReadValue(size_t index, double& item) {
|
||||
if (!IsValid()) {
|
||||
return false;
|
||||
}
|
||||
item = ::sqlite3_column_double(statement_handle_->Get(), ToColumn(index));
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* For cases where byte sizes of column data is necessary, the
|
||||
* recommendations in https://www.sqlite.org/c3ref/column_blob.html regarding
|
||||
* type conversions are followed.
|
||||
*
|
||||
* TL;DR: Access blobs then bytes.
|
||||
*/
|
||||
|
||||
bool ArchiveStatement::ReadValue(size_t index, std::string& item) {
|
||||
if (!IsValid()) {
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
* Get the character data
|
||||
*/
|
||||
auto chars = reinterpret_cast<const char*>(
|
||||
::sqlite3_column_text(statement_handle_->Get(), ToColumn(index)));
|
||||
|
||||
/*
|
||||
* Get the length of the string (in bytes)
|
||||
*/
|
||||
size_t textByteSize =
|
||||
::sqlite3_column_bytes(statement_handle_->Get(), ToColumn(index));
|
||||
|
||||
std::string text(chars, textByteSize);
|
||||
item.swap(text);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArchiveStatement::ReadValue(size_t index, Allocation& item) {
|
||||
if (!IsValid()) {
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
* Get a blob pointer
|
||||
*/
|
||||
auto blob = reinterpret_cast<const uint8_t*>(
|
||||
::sqlite3_column_blob(statement_handle_->Get(), ToColumn(index)));
|
||||
|
||||
/*
|
||||
* Decode the number of bytes in the blob
|
||||
*/
|
||||
size_t byteSize =
|
||||
::sqlite3_column_bytes(statement_handle_->Get(), ToColumn(index));
|
||||
|
||||
/*
|
||||
* Reszie the host allocation and move the blob contents into it
|
||||
*/
|
||||
if (!item.Truncate(byteSize, false /* npot */)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memmove(item.GetBuffer(), blob, byteSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
ArchiveStatement::Result ArchiveStatement::Execute() {
|
||||
if (!IsValid()) {
|
||||
return Result::kFailure;
|
||||
}
|
||||
switch (::sqlite3_step(statement_handle_->Get())) {
|
||||
case SQLITE_DONE:
|
||||
return Result::kDone;
|
||||
case SQLITE_ROW:
|
||||
return Result::kRow;
|
||||
default:
|
||||
return Result::kFailure;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
@ -1,100 +0,0 @@
|
||||
// Copyright 2013 The Flutter 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 FLUTTER_IMPELLER_ARCHIVIST_ARCHIVE_STATEMENT_H_
|
||||
#define FLUTTER_IMPELLER_ARCHIVIST_ARCHIVE_STATEMENT_H_
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
#include "impeller/base/allocation.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// @brief Represents a read/write query to an archive database. Statements
|
||||
/// are expensive to create and must be cached for as long as
|
||||
/// possible.
|
||||
///
|
||||
class ArchiveStatement {
|
||||
public:
|
||||
~ArchiveStatement();
|
||||
|
||||
bool IsValid() const;
|
||||
|
||||
enum class Result {
|
||||
//--------------------------------------------------------------------------
|
||||
/// The statement is done executing.
|
||||
///
|
||||
kDone,
|
||||
//--------------------------------------------------------------------------
|
||||
/// The statement found a row of information ready for reading.
|
||||
///
|
||||
kRow,
|
||||
//--------------------------------------------------------------------------
|
||||
/// Statement execution was a failure.
|
||||
///
|
||||
kFailure,
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief Execute the given statement with the provided data.
|
||||
///
|
||||
/// @return Is the execution was succeessful.
|
||||
///
|
||||
[[nodiscard]] Result Execute();
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief All writes after the last successfull `Run` call are reset.
|
||||
/// Since statements are expensive to create, reset them for new
|
||||
/// writes instead of creating new statements.
|
||||
///
|
||||
/// @return If the statement writes were reset.
|
||||
///
|
||||
bool Reset();
|
||||
|
||||
bool WriteValue(size_t index, const std::string& item);
|
||||
|
||||
template <class T, class = std::enable_if<std::is_integral<T>::value>>
|
||||
bool WriteValue(size_t index, T item) {
|
||||
return BindIntegral(index, static_cast<int64_t>(item));
|
||||
}
|
||||
|
||||
bool WriteValue(size_t index, double item);
|
||||
|
||||
bool WriteValue(size_t index, const Allocation& item);
|
||||
|
||||
template <class T, class = std::enable_if<std::is_integral<T>::value>>
|
||||
bool ReadValue(size_t index, T& item) {
|
||||
return ColumnIntegral(index, item);
|
||||
}
|
||||
|
||||
bool ReadValue(size_t index, double& item);
|
||||
|
||||
bool ReadValue(size_t index, std::string& item);
|
||||
|
||||
bool ReadValue(size_t index, Allocation& item);
|
||||
|
||||
size_t GetColumnCount();
|
||||
|
||||
private:
|
||||
struct Handle;
|
||||
std::unique_ptr<Handle> statement_handle_;
|
||||
|
||||
friend class ArchiveDatabase;
|
||||
|
||||
ArchiveStatement(void* db, const std::string& statement);
|
||||
|
||||
bool BindIntegral(size_t index, int64_t item);
|
||||
|
||||
bool ColumnIntegral(size_t index, int64_t& item);
|
||||
|
||||
ArchiveStatement(const ArchiveStatement&) = delete;
|
||||
|
||||
ArchiveStatement& operator=(const ArchiveStatement&) = delete;
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
#endif // FLUTTER_IMPELLER_ARCHIVIST_ARCHIVE_STATEMENT_H_
|
||||
@ -1,52 +0,0 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "impeller/archivist/archive_transaction.h"
|
||||
|
||||
#include "flutter/fml/logging.h"
|
||||
#include "impeller/archivist/archive_statement.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
ArchiveTransaction::ArchiveTransaction(int64_t& transactionCount,
|
||||
ArchiveStatement& beginStatement,
|
||||
ArchiveStatement& endStatement,
|
||||
ArchiveStatement& rollbackStatement)
|
||||
: end_stmt_(endStatement),
|
||||
rollback_stmt_(rollbackStatement),
|
||||
transaction_count_(transactionCount) {
|
||||
if (transaction_count_ == 0) {
|
||||
cleanup_ = beginStatement.Execute() == ArchiveStatement::Result::kDone;
|
||||
}
|
||||
transaction_count_++;
|
||||
}
|
||||
|
||||
ArchiveTransaction::ArchiveTransaction(ArchiveTransaction&& other)
|
||||
: end_stmt_(other.end_stmt_),
|
||||
rollback_stmt_(other.rollback_stmt_),
|
||||
transaction_count_(other.transaction_count_),
|
||||
cleanup_(other.cleanup_),
|
||||
successful_(other.successful_) {
|
||||
other.abandoned_ = true;
|
||||
}
|
||||
|
||||
ArchiveTransaction::~ArchiveTransaction() {
|
||||
if (abandoned_) {
|
||||
return;
|
||||
}
|
||||
|
||||
FML_CHECK(transaction_count_ != 0);
|
||||
if (transaction_count_ == 1 && cleanup_) {
|
||||
auto res = successful_ ? end_stmt_.Execute() : rollback_stmt_.Execute();
|
||||
FML_CHECK(res == ArchiveStatement::Result::kDone)
|
||||
<< "Must be able to commit the nested transaction";
|
||||
}
|
||||
transaction_count_--;
|
||||
}
|
||||
|
||||
void ArchiveTransaction::MarkWritesAsReadyForCommit() {
|
||||
successful_ = true;
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
@ -1,52 +0,0 @@
|
||||
// Copyright 2013 The Flutter 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 FLUTTER_IMPELLER_ARCHIVIST_ARCHIVE_TRANSACTION_H_
|
||||
#define FLUTTER_IMPELLER_ARCHIVIST_ARCHIVE_TRANSACTION_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace impeller {
|
||||
|
||||
class ArchiveStatement;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// @brief All writes made to the archive within a transaction that is not
|
||||
/// marked as ready for commit will be rolled back with the
|
||||
/// transaction ends.
|
||||
///
|
||||
/// All transactions are obtained from the `ArchiveDatabase`.
|
||||
///
|
||||
/// @see `ArchiveDatabase`
|
||||
///
|
||||
class ArchiveTransaction {
|
||||
public:
|
||||
ArchiveTransaction(ArchiveTransaction&& transaction);
|
||||
|
||||
~ArchiveTransaction();
|
||||
|
||||
void MarkWritesAsReadyForCommit();
|
||||
|
||||
private:
|
||||
ArchiveStatement& end_stmt_;
|
||||
ArchiveStatement& rollback_stmt_;
|
||||
int64_t& transaction_count_;
|
||||
bool cleanup_ = false;
|
||||
bool successful_ = false;
|
||||
bool abandoned_ = false;
|
||||
|
||||
friend class ArchiveDatabase;
|
||||
|
||||
ArchiveTransaction(int64_t& transactionCount,
|
||||
ArchiveStatement& beginStatement,
|
||||
ArchiveStatement& endStatement,
|
||||
ArchiveStatement& rollbackStatement);
|
||||
|
||||
ArchiveTransaction(const ArchiveTransaction&) = delete;
|
||||
|
||||
ArchiveTransaction& operator=(const ArchiveTransaction&) = delete;
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
#endif // FLUTTER_IMPELLER_ARCHIVIST_ARCHIVE_TRANSACTION_H_
|
||||
@ -1,61 +0,0 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "impeller/archivist/archive_vector.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "impeller/archivist/archive_location.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
ArchiveVector::ArchiveVector(std::vector<int64_t> keys)
|
||||
: keys_(std::move(keys)) {}
|
||||
|
||||
ArchiveVector::ArchiveVector() {}
|
||||
|
||||
static constexpr const char* kVectorKeys = "keys";
|
||||
|
||||
ArchiveDef ArchiveVector::kArchiveDefinition = {
|
||||
.table_name = "IPLR_vectors",
|
||||
.members = {kVectorKeys},
|
||||
};
|
||||
|
||||
PrimaryKey ArchiveVector::GetPrimaryKey() const {
|
||||
// Archive definition says the keys will be auto assigned.
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const std::vector<int64_t> ArchiveVector::GetKeys() const {
|
||||
return keys_;
|
||||
}
|
||||
|
||||
bool ArchiveVector::Write(ArchiveLocation& item) const {
|
||||
std::stringstream stream;
|
||||
for (size_t i = 0, count = keys_.size(); i < count; i++) {
|
||||
stream << keys_[i];
|
||||
if (i != count - 1) {
|
||||
stream << ",";
|
||||
}
|
||||
}
|
||||
return item.Write(kVectorKeys, stream.str());
|
||||
}
|
||||
|
||||
bool ArchiveVector::Read(ArchiveLocation& item) {
|
||||
std::string flattened;
|
||||
if (!item.Read(kVectorKeys, flattened)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::stringstream stream(flattened);
|
||||
int64_t single = 0;
|
||||
while (stream >> single) {
|
||||
keys_.emplace_back(single);
|
||||
stream.ignore();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
@ -1,40 +0,0 @@
|
||||
// Copyright 2013 The Flutter 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 FLUTTER_IMPELLER_ARCHIVIST_ARCHIVE_VECTOR_H_
|
||||
#define FLUTTER_IMPELLER_ARCHIVIST_ARCHIVE_VECTOR_H_
|
||||
|
||||
#include "impeller/archivist/archive.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
class ArchiveVector : public Archivable {
|
||||
public:
|
||||
static ArchiveDef kArchiveDefinition;
|
||||
|
||||
PrimaryKey GetPrimaryKey() const override;
|
||||
|
||||
const std::vector<int64_t> GetKeys() const;
|
||||
|
||||
bool Write(ArchiveLocation& item) const override;
|
||||
|
||||
bool Read(ArchiveLocation& item) override;
|
||||
|
||||
private:
|
||||
std::vector<int64_t> keys_;
|
||||
|
||||
friend class ArchiveLocation;
|
||||
|
||||
ArchiveVector();
|
||||
|
||||
explicit ArchiveVector(std::vector<int64_t> keys);
|
||||
|
||||
ArchiveVector(const ArchiveVector&) = delete;
|
||||
|
||||
ArchiveVector& operator=(const ArchiveVector&) = delete;
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
#endif // FLUTTER_IMPELLER_ARCHIVIST_ARCHIVE_VECTOR_H_
|
||||
@ -1,41 +0,0 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "impeller/archivist/archivist_fixture.h"
|
||||
|
||||
#include "flutter/fml/paths.h"
|
||||
|
||||
namespace impeller {
|
||||
namespace testing {
|
||||
|
||||
ArchivistFixture::ArchivistFixture() {
|
||||
std::stringstream stream;
|
||||
stream << "Test" << flutter::testing::GetCurrentTestName() << ".db";
|
||||
archive_file_name_ = stream.str();
|
||||
}
|
||||
|
||||
ArchivistFixture::~ArchivistFixture() = default;
|
||||
|
||||
const std::string ArchivistFixture::GetArchiveFileName() const {
|
||||
return fml::paths::JoinPaths(
|
||||
{flutter::testing::GetFixturesPath(), archive_file_name_});
|
||||
}
|
||||
|
||||
void ArchivistFixture::SetUp() {
|
||||
DeleteArchiveFile();
|
||||
}
|
||||
|
||||
void ArchivistFixture::TearDown() {
|
||||
DeleteArchiveFile();
|
||||
}
|
||||
|
||||
void ArchivistFixture::DeleteArchiveFile() const {
|
||||
auto fixtures = flutter::testing::OpenFixturesDirectory();
|
||||
if (fml::FileExists(fixtures, archive_file_name_.c_str())) {
|
||||
fml::UnlinkFile(fixtures, archive_file_name_.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace impeller
|
||||
@ -1,41 +0,0 @@
|
||||
// Copyright 2013 The Flutter 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 FLUTTER_IMPELLER_ARCHIVIST_ARCHIVIST_FIXTURE_H_
|
||||
#define FLUTTER_IMPELLER_ARCHIVIST_ARCHIVIST_FIXTURE_H_
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "flutter/testing/testing.h"
|
||||
|
||||
namespace impeller {
|
||||
namespace testing {
|
||||
|
||||
class ArchivistFixture : public ::testing::Test {
|
||||
public:
|
||||
ArchivistFixture();
|
||||
|
||||
~ArchivistFixture();
|
||||
|
||||
// |::testing::Test|
|
||||
void SetUp() override;
|
||||
|
||||
// |::testing::Test|
|
||||
void TearDown() override;
|
||||
|
||||
const std::string GetArchiveFileName() const;
|
||||
|
||||
private:
|
||||
std::string archive_file_name_;
|
||||
|
||||
void DeleteArchiveFile() const;
|
||||
|
||||
ArchivistFixture(const ArchivistFixture&) = delete;
|
||||
|
||||
ArchivistFixture& operator=(const ArchivistFixture&) = delete;
|
||||
};
|
||||
|
||||
} // namespace testing
|
||||
} // namespace impeller
|
||||
|
||||
#endif // FLUTTER_IMPELLER_ARCHIVIST_ARCHIVIST_FIXTURE_H_
|
||||
@ -1,209 +0,0 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <cstdio>
|
||||
#include <thread>
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "flutter/testing/testing.h"
|
||||
#include "impeller/archivist/archive.h"
|
||||
#include "impeller/archivist/archive_location.h"
|
||||
#include "impeller/archivist/archivist_fixture.h"
|
||||
|
||||
// TODO(zanderso): https://github.com/flutter/flutter/issues/127701
|
||||
// NOLINTBEGIN(bugprone-unchecked-optional-access)
|
||||
|
||||
namespace impeller {
|
||||
namespace testing {
|
||||
|
||||
static int64_t LastSample = 0;
|
||||
|
||||
class Sample : public Archivable {
|
||||
public:
|
||||
explicit Sample(uint64_t count = 42) : some_data_(count) {}
|
||||
|
||||
Sample(Sample&&) = default;
|
||||
|
||||
uint64_t GetSomeData() const { return some_data_; }
|
||||
|
||||
// |Archivable|
|
||||
PrimaryKey GetPrimaryKey() const override { return name_; }
|
||||
|
||||
// |Archivable|
|
||||
bool Write(ArchiveLocation& item) const override {
|
||||
return item.Write("some_data", some_data_);
|
||||
};
|
||||
|
||||
// |Archivable|
|
||||
bool Read(ArchiveLocation& item) override {
|
||||
name_ = item.GetPrimaryKey();
|
||||
return item.Read("some_data", some_data_);
|
||||
};
|
||||
|
||||
static const ArchiveDef kArchiveDefinition;
|
||||
|
||||
private:
|
||||
uint64_t some_data_;
|
||||
PrimaryKey name_ = ++LastSample;
|
||||
|
||||
Sample(const Sample&) = delete;
|
||||
|
||||
Sample& operator=(const Sample&) = delete;
|
||||
};
|
||||
|
||||
const ArchiveDef Sample::kArchiveDefinition = {
|
||||
.table_name = "Sample",
|
||||
.members = {"some_data"},
|
||||
};
|
||||
|
||||
class SampleWithVector : public Archivable {
|
||||
public:
|
||||
SampleWithVector() = default;
|
||||
|
||||
// |Archivable|
|
||||
PrimaryKey GetPrimaryKey() const override { return std::nullopt; }
|
||||
|
||||
// |Archivable|
|
||||
bool Write(ArchiveLocation& item) const override {
|
||||
std::vector<Sample> samples;
|
||||
for (size_t i = 0; i < 50u; i++) {
|
||||
samples.emplace_back(Sample{1988 + i});
|
||||
}
|
||||
return item.Write("hello", "world") && item.Write("samples", samples);
|
||||
};
|
||||
|
||||
// |Archivable|
|
||||
bool Read(ArchiveLocation& item) override {
|
||||
std::string str;
|
||||
auto str_result = item.Read("hello", str);
|
||||
std::vector<Sample> samples;
|
||||
auto vec_result = item.Read("samples", samples);
|
||||
|
||||
if (!str_result || str != "world" || !vec_result || samples.size() != 50) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t current = 1988;
|
||||
for (const auto& sample : samples) {
|
||||
if (sample.GetSomeData() != current++) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
static const ArchiveDef kArchiveDefinition;
|
||||
|
||||
private:
|
||||
std::vector<Sample> samples_;
|
||||
SampleWithVector(const SampleWithVector&) = delete;
|
||||
|
||||
SampleWithVector& operator=(const SampleWithVector&) = delete;
|
||||
};
|
||||
|
||||
const ArchiveDef SampleWithVector::kArchiveDefinition = {
|
||||
.table_name = "SampleWithVector",
|
||||
.members = {"hello", "samples"},
|
||||
};
|
||||
|
||||
using ArchiveTest = ArchivistFixture;
|
||||
|
||||
TEST_F(ArchiveTest, SimpleInitialization) {
|
||||
Archive archive(GetArchiveFileName().c_str());
|
||||
ASSERT_TRUE(archive.IsValid());
|
||||
}
|
||||
|
||||
TEST_F(ArchiveTest, AddStorageClass) {
|
||||
Archive archive(GetArchiveFileName().c_str());
|
||||
ASSERT_TRUE(archive.IsValid());
|
||||
}
|
||||
|
||||
TEST_F(ArchiveTest, AddData) {
|
||||
Archive archive(GetArchiveFileName().c_str());
|
||||
ASSERT_TRUE(archive.IsValid());
|
||||
Sample sample;
|
||||
ASSERT_TRUE(archive.Write(sample));
|
||||
}
|
||||
|
||||
TEST_F(ArchiveTest, AddDataMultiple) {
|
||||
Archive archive(GetArchiveFileName().c_str());
|
||||
ASSERT_TRUE(archive.IsValid());
|
||||
|
||||
for (size_t i = 0; i < 100; i++) {
|
||||
Sample sample(i + 1);
|
||||
ASSERT_TRUE(archive.Write(sample));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ArchiveTest, ReadData) {
|
||||
Archive archive(GetArchiveFileName().c_str());
|
||||
ASSERT_TRUE(archive.IsValid());
|
||||
|
||||
size_t count = 50;
|
||||
|
||||
std::vector<PrimaryKey::value_type> keys;
|
||||
std::vector<uint64_t> values;
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
Sample sample(i + 1);
|
||||
keys.push_back(sample.GetPrimaryKey().value());
|
||||
values.push_back(sample.GetSomeData());
|
||||
ASSERT_TRUE(archive.Write(sample));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
Sample sample;
|
||||
ASSERT_TRUE(archive.Read(keys[i], sample));
|
||||
ASSERT_EQ(values[i], sample.GetSomeData());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ArchiveTest, ReadDataWithNames) {
|
||||
Archive archive(GetArchiveFileName().c_str());
|
||||
ASSERT_TRUE(archive.IsValid());
|
||||
|
||||
size_t count = 8;
|
||||
|
||||
std::vector<PrimaryKey::value_type> keys;
|
||||
std::vector<uint64_t> values;
|
||||
|
||||
keys.reserve(count);
|
||||
values.reserve(count);
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
Sample sample(i + 1);
|
||||
keys.push_back(sample.GetPrimaryKey().value());
|
||||
values.push_back(sample.GetSomeData());
|
||||
ASSERT_TRUE(archive.Write(sample));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
Sample sample;
|
||||
ASSERT_TRUE(archive.Read(keys[i], sample));
|
||||
ASSERT_EQ(values[i], sample.GetSomeData());
|
||||
ASSERT_EQ(keys[i], sample.GetPrimaryKey());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ArchiveTest, CanReadWriteVectorOfArchivables) {
|
||||
Archive archive(GetArchiveFileName().c_str());
|
||||
ASSERT_TRUE(archive.IsValid());
|
||||
|
||||
SampleWithVector sample_with_vector;
|
||||
ASSERT_TRUE(archive.Write(sample_with_vector));
|
||||
bool read_success = false;
|
||||
ASSERT_EQ(
|
||||
archive.Read<SampleWithVector>([&](ArchiveLocation& location) -> bool {
|
||||
SampleWithVector other_sample_with_vector;
|
||||
read_success = other_sample_with_vector.Read(location);
|
||||
return true; // Always keep continuing but assert that we only get one.
|
||||
}),
|
||||
1u);
|
||||
ASSERT_TRUE(read_success);
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace impeller
|
||||
|
||||
// NOLINTEND(bugprone-unchecked-optional-access)
|
||||
@ -233,7 +233,6 @@ impeller_component("entity") {
|
||||
":entity_shaders",
|
||||
":framebuffer_blend_entity_shaders",
|
||||
":modern_entity_shaders",
|
||||
"../archivist",
|
||||
"../image:image_skia_backend",
|
||||
"../renderer",
|
||||
"../typographer",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user