Skip to content

Commit dfa6fc8

Browse files
author
Igor Egorov
authored
ADT (#88)
* Introduce ADT target. Implement Array over AMT * Implement Multimap * Fix CBOR decoder for AMT. Thanks to @turuslan Signed-off-by: Igor Egorov <[email protected]>
1 parent 9439be1 commit dfa6fc8

File tree

13 files changed

+516
-23
lines changed

13 files changed

+516
-23
lines changed

core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# SPDX-License-Identifier: Apache-2.0
44
#
55

6+
add_subdirectory(adt)
67
add_subdirectory(blockchain)
78
add_subdirectory(clock)
89
add_subdirectory(codec)

core/adt/CMakeLists.txt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#
2+
# Copyright Soramitsu Co., Ltd. All Rights Reserved.
3+
# SPDX-License-Identifier: Apache-2.0
4+
#
5+
6+
add_custom_target(adt
7+
DEPENDS
8+
array
9+
multimap
10+
)
11+
12+
add_library(array
13+
impl/array.cpp
14+
)
15+
target_link_libraries(array
16+
amt
17+
)
18+
19+
add_library(multimap
20+
impl/multimap.cpp
21+
)
22+
target_link_libraries(multimap
23+
array
24+
hamt
25+
)

core/adt/array.hpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/**
2+
* Copyright Soramitsu Co., Ltd. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#ifndef CPP_FILECOIN_ARRAY_HPP
7+
#define CPP_FILECOIN_ARRAY_HPP
8+
9+
#include "codec/cbor/cbor.hpp"
10+
#include "common/outcome.hpp"
11+
#include "primitives/cid/cid.hpp"
12+
#include "storage/amt/amt.hpp"
13+
#include "storage/ipfs/datastore.hpp"
14+
15+
namespace fc::adt {
16+
17+
/**
18+
* Container for storing values preserving their order of insertion.
19+
* Implementation is based on Array Mapped Trie.
20+
*/
21+
struct Array {
22+
using Value = storage::ipfs::IpfsDatastore::Value;
23+
using IndexedVisitor =
24+
std::function<outcome::result<void>(uint64_t, const Value &)>;
25+
using Visitor = std::function<outcome::result<void>(const Value &)>;
26+
27+
explicit Array(const std::shared_ptr<storage::ipfs::IpfsDatastore> &store);
28+
Array(const std::shared_ptr<storage::ipfs::IpfsDatastore> &store,
29+
const CID &root);
30+
31+
/**
32+
* Apply changes to storage
33+
* @return root CID
34+
*/
35+
outcome::result<CID> flush();
36+
37+
/// Appends a value. Does not change the store
38+
outcome::result<void> append(gsl::span<const uint8_t> value);
39+
40+
/**
41+
* Appends a value which can be CBOR-encoded.
42+
* Does not change the store immediately
43+
* @tparam T value type that supports CBOR encoding
44+
* @param value to be marshalled
45+
* @return operation result
46+
*/
47+
template <typename T>
48+
outcome::result<void> appendCbor(const T &value) {
49+
OUTCOME_TRY(bytes, codec::cbor::encode(value));
50+
return append(bytes);
51+
}
52+
53+
/// Iterate over stored elements acquiring their index
54+
outcome::result<void> visit(const IndexedVisitor &visitor);
55+
56+
/// Iterate over stored elements
57+
outcome::result<void> visit(const Visitor &visitor);
58+
59+
private:
60+
std::shared_ptr<storage::ipfs::IpfsDatastore> store_;
61+
storage::amt::Amt amt_;
62+
};
63+
64+
} // namespace fc::adt
65+
66+
#endif // CPP_FILECOIN_ARRAY_HPP

core/adt/impl/array.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/**
2+
* Copyright Soramitsu Co., Ltd. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#include "adt/array.hpp"
7+
8+
namespace fc::adt {
9+
10+
Array::Array(const std::shared_ptr<storage::ipfs::IpfsDatastore> &store)
11+
: store_(store), amt_(store) {}
12+
13+
Array::Array(const std::shared_ptr<storage::ipfs::IpfsDatastore> &store,
14+
const CID &root)
15+
: store_(store), amt_(store, root) {}
16+
17+
outcome::result<CID> Array::flush() {
18+
return amt_.flush();
19+
}
20+
21+
outcome::result<void> Array::append(gsl::span<const uint8_t> value) {
22+
OUTCOME_TRY(count, amt_.count());
23+
return amt_.set(count, value);
24+
}
25+
26+
outcome::result<void> Array::visit(const Array::IndexedVisitor &visitor) {
27+
return amt_.visit(visitor);
28+
}
29+
30+
outcome::result<void> Array::visit(const Array::Visitor &visitor) {
31+
return amt_.visit(
32+
[&visitor](auto, const Value &value) { return visitor(value); });
33+
}
34+
35+
} // namespace fc::adt

core/adt/impl/multimap.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/**
2+
* Copyright Soramitsu Co., Ltd. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#include "adt/multimap.hpp"
7+
8+
#include "adt/array.hpp"
9+
10+
namespace fc::adt {
11+
12+
Multimap::Multimap(const std::shared_ptr<storage::ipfs::IpfsDatastore> &store)
13+
: store_(store), hamt_(store) {}
14+
15+
Multimap::Multimap(const std::shared_ptr<storage::ipfs::IpfsDatastore> &store,
16+
const CID &root)
17+
: store_(store), hamt_(store, root) {}
18+
19+
outcome::result<CID> Multimap::flush() {
20+
return hamt_.flush();
21+
}
22+
23+
outcome::result<void> Multimap::add(const std::string &key,
24+
gsl::span<const uint8_t> value) {
25+
using storage::hamt::HamtError;
26+
boost::optional<Array> array{boost::none};
27+
auto found = hamt_.getCbor<CID>(key);
28+
29+
if (found) {
30+
array = Array(store_, found.value());
31+
} else {
32+
if (HamtError::NOT_FOUND == found.error()) {
33+
array = Array(store_);
34+
} else {
35+
return found.error();
36+
}
37+
}
38+
39+
OUTCOME_TRY(array->append(value));
40+
OUTCOME_TRY(array_root, array->flush());
41+
return hamt_.setCbor<CID>(key, array_root);
42+
}
43+
44+
outcome::result<void> Multimap::removeAll(const std::string &key) {
45+
return hamt_.remove(key);
46+
}
47+
48+
outcome::result<void> Multimap::visit(const std::string &key,
49+
const Multimap::Visitor &visitor) {
50+
OUTCOME_TRY(array_root, hamt_.getCbor<CID>(key));
51+
return Array{store_, array_root}.visit(visitor);
52+
}
53+
54+
} // namespace fc::adt

core/adt/multimap.hpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/**
2+
* Copyright Soramitsu Co., Ltd. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#ifndef CPP_FILECOIN_MULTIMAP_HPP
7+
#define CPP_FILECOIN_MULTIMAP_HPP
8+
9+
#include "common/outcome.hpp"
10+
#include "primitives/cid/cid.hpp"
11+
#include "storage/hamt/hamt.hpp"
12+
#include "storage/ipfs/datastore.hpp"
13+
14+
namespace fc::adt {
15+
16+
/**
17+
* Container for storing multiple values per key.
18+
* Implemented over a HAMT of AMTs.
19+
* The order of values by the same key is preserved.
20+
*/
21+
struct Multimap {
22+
using Value = storage::ipfs::IpfsDatastore::Value;
23+
using Visitor = std::function<outcome::result<void>(const Value &)>;
24+
25+
explicit Multimap(
26+
const std::shared_ptr<storage::ipfs::IpfsDatastore> &store);
27+
Multimap(const std::shared_ptr<storage::ipfs::IpfsDatastore> &store,
28+
const CID &root);
29+
30+
/**
31+
* Apply changes to storage
32+
* @return root CID
33+
*/
34+
outcome::result<CID> flush();
35+
36+
/// Adds a value by key to the end of array. Does not change the store
37+
outcome::result<void> add(const std::string &key,
38+
gsl::span<const uint8_t> value);
39+
40+
/**
41+
* Adds a value which can be CBOR-encoded.
42+
* Does not change the store immediately
43+
* @tparam T value type that supports CBOR encoding
44+
* @param value to be marshalled
45+
* @return operation result
46+
*/
47+
template <typename T>
48+
outcome::result<void> addCbor(const std::string &key, const T &value) {
49+
OUTCOME_TRY(bytes, codec::cbor::encode(value));
50+
return add(key, bytes);
51+
}
52+
53+
/// Removes array under the key
54+
outcome::result<void> removeAll(const std::string &key);
55+
56+
/// Iterates over stored values by key
57+
outcome::result<void> visit(const std::string &key, const Visitor &visitor);
58+
59+
private:
60+
std::shared_ptr<storage::ipfs::IpfsDatastore> store_;
61+
storage::hamt::Hamt hamt_;
62+
};
63+
} // namespace fc::adt
64+
65+
#endif // CPP_FILECOIN_MULTIMAP_HPP

core/codec/cbor/cbor_decode_stream.cpp

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ namespace fc::codec::cbor {
1111
parser_(std::make_shared<CborParser>()) {
1212
if (CborNoError
1313
!= cbor_parser_init(
14-
data_->data(), data_->size(), 0, parser_.get(), &value_)) {
14+
data_->data(), data_->size(), 0, parser_.get(), &value_)) {
1515
outcome::raise(CborDecodeError::INVALID_CBOR);
1616
}
1717
value_.remaining = UINT32_MAX;
@@ -55,8 +55,7 @@ namespace fc::codec::cbor {
5555
return *this;
5656
}
5757

58-
CborDecodeStream &CborDecodeStream::operator>>(
59-
CID &cid) {
58+
CborDecodeStream &CborDecodeStream::operator>>(CID &cid) {
6059
if (!cbor_value_is_tag(&value_)) {
6160
outcome::raise(CborDecodeError::INVALID_CBOR_CID);
6261
}
@@ -148,11 +147,10 @@ namespace fc::codec::cbor {
148147
return length;
149148
}
150149

151-
std::vector<uint8_t> CborDecodeStream::raw() const {
152-
auto stream = *this;
153-
auto begin = stream.value_.ptr;
154-
stream.next();
155-
return {begin, stream.value_.ptr};
150+
std::vector<uint8_t> CborDecodeStream::raw() {
151+
auto begin = value_.ptr;
152+
next();
153+
return {begin, value_.ptr};
156154
}
157155

158156
std::map<std::string, CborDecodeStream> CborDecodeStream::map() {

core/codec/cbor/cbor_decode_stream.hpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ namespace fc::codec::cbor {
9292
template <typename T>
9393
CborDecodeStream &operator>>(std::map<std::string, T> &items) {
9494
for (auto &m : map()) {
95-
m.second >> items[m.first];
95+
m.second >> items[m.first];
9696
}
9797
return *this;
9898
}
@@ -116,8 +116,9 @@ namespace fc::codec::cbor {
116116
bool isNull() const;
117117
/** Returns count of items in current element list container */
118118
size_t listLength() const;
119-
/** Returns CBOR bytes of current element */
120-
std::vector<uint8_t> raw() const;
119+
/** Reads CBOR bytes of current element (and advances to the next element)
120+
*/
121+
std::vector<uint8_t> raw();
121122
/** Creates map container decode substream map */
122123
std::map<std::string, CborDecodeStream> map();
123124

test/core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# SPDX-License-Identifier: Apache-2.0
44
#
55

6+
add_subdirectory(adt)
67
add_subdirectory(blockchain)
78
add_subdirectory(clock)
89
add_subdirectory(codec)

test/core/adt/CMakeLists.txt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#
2+
# Copyright Soramitsu Co., Ltd. All Rights Reserved.
3+
# SPDX-License-Identifier: Apache-2.0
4+
#
5+
6+
addtest(array_test
7+
array_test.cpp
8+
)
9+
target_link_libraries(array_test
10+
amt
11+
array
12+
ipfs_datastore_in_memory
13+
)
14+
15+
16+
addtest(multimap_test
17+
multimap_test.cpp
18+
)
19+
target_link_libraries(multimap_test
20+
hamt
21+
multimap
22+
ipfs_datastore_in_memory
23+
)

0 commit comments

Comments
 (0)