fmt wrapper + proof of concept folder

This commit is contained in:
Marko Budiselic 2016-08-08 09:32:34 +01:00
parent b5f884d428
commit 84e69bb1d3
26 changed files with 233 additions and 183 deletions

View File

@ -10,9 +10,14 @@ project(${ProjectId})
find_package(Threads REQUIRED)
# flags
# c++14
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y")
# glibcxx debug
# glibcxx debug (useful for gdb)
# the problem is that the query engine doesn't work as it should work if
# this flag is present
# TODO: find more appropriate way to use this flag only when it is needed
# set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_GLIBCXX_DEBUG")
# functions
@ -133,15 +138,16 @@ foreach(source_foler ${source_folders})
file(COPY ${include_dir}/${source_folder} DESTINATION ${test_include_dir})
endforeach()
# compiler options
SET(COMPILE_OPTIONS "-O2 -Wall -Werror -fmessage-length=0")
# add all cpp file recursive into sourceFiles varibale
# FILE(GLOB_RECURSE sourceFiles ${src_dir}/*.cpp)
# print list of source files
# MESSAGE(STATUS "All source files are: ${sourceFiles}")
# defines
# compiler options
# SET(COMPILE_OPTIONS "-O2 -Wall -Werror -fmessage-length=0")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -march=native")
# manual defines at configure time
option(RUNTIME_ASSERT "Enable runtime assertions" OFF)
if(RUNTIME_ASSERT)
add_definitions( -DRUNTIME_ASSERT_ON )
@ -216,12 +222,21 @@ set(memgraph_src_files
${src_dir}/transactions/transaction.cpp
${src_dir}/template_engine/engine.cpp
)
add_library(libmemgraph ${memgraph_src_files})
# STATIC library used by memgraph executables
add_library(memgraph STATIC ${memgraph_src_files})
# STATIC PIC library used by query engine
add_library(memgraph_pic STATIC ${memgraph_src_files})
set_property(TARGET memgraph_pic PROPERTY POSITION_INDEPENDENT_CODE TRUE)
# tests
enable_testing()
add_subdirectory(tests)
# proof of concept
add_subdirectory(poc)
# memgraph build name
execute_process(
OUTPUT_VARIABLE COMMIT_NO
@ -234,15 +249,7 @@ execute_process(
string(STRIP ${COMMIT_HASH} COMMIT_HASH)
string(STRIP ${COMMIT_NO} COMMIT_NO)
set(MEMGRAPH_BUILD_NAME "memgraph_${COMMIT_HASH}_${COMMIT_NO}")
message(STATUS ${CMAKE_BUILD_TYPE})
# DEBUG BUILD
add_executable(${MEMGRAPH_BUILD_NAME}_debug ${src_dir}/memgraph_bolt.cpp)
# TEST BUILD
# TODO
# O-OPTIMIZED BUILD
# TODO
# RELEASE BUILD
# TODO
# memgraph main executable
add_executable(${MEMGRAPH_BUILD_NAME}_${CMAKE_BUILD_TYPE} ${src_dir}/memgraph_bolt.cpp)

View File

@ -24,6 +24,15 @@ on a 64 bit linux kernel.
```
cd build
cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DRUNTIME_ASSERT=OFF -DTHROW_EXCEPTION_ON_ERROR=OFF -DNDEBUG=OFF ..
# Flags:
# -DCMAKE_C_COMPILER=clang
# -DCMAKE_CXX_COMPILER=clang++
# -DRUNTIME_ASSERT=OFF
# -DTHROW_EXCEPTION_ON_ERROR=OFF
# -DCMAKE_BUILD_TYPE:STRING=Debug
# -DNDEBUG=ON
make
ctest
ctest -V

View File

@ -1 +0,0 @@
---

View File

@ -1,3 +0,0 @@
Start testing: Jul 28 19:05 BST
----------------------------------------------------------
End testing: Jul 28 19:05 BST

View File

@ -9,18 +9,23 @@
class Vertices
{
public:
using vertices_t = ConcurrentMap<uint64_t, VertexRecord>;
vertices_t::Accessor access();
const Vertex::Accessor find(tx::Transaction &t, const Id &id);
const Vertex::Accessor first(tx::Transaction &t);
Vertex::Accessor insert(tx::Transaction &t);
void update_label_index(const Label &label,
VertexIndexRecord &&index_record);
VertexIndexRecordCollection& find_label_index(const Label& label);
private:
vertices_t vertices;
Index<label_ref_t, VertexIndexRecordCollection> label_index;
ConcurrentMap<uint64_t, VertexRecord> vertices;
AtomicCounter<uint64_t> counter;
};

6
poc/CMakeLists.txt Normal file
View File

@ -0,0 +1,6 @@
cmake_minimum_required(VERSION 3.1)
project(memgraph_poc)
add_executable(poc_astar astar.cpp)
target_link_libraries(poc_astar memgraph)

6
poc/astar.cpp Normal file
View File

@ -0,0 +1,6 @@
#include <iostream>
int main()
{
return 0;
}

View File

@ -6,49 +6,49 @@
template <class T>
class ConcurrentSet
{
typedef SkipList<T> list;
typedef typename SkipList<T>::Iterator list_it;
typedef typename SkipList<T>::ConstIterator list_it_con;
public:
ConcurrentSet() {}
class Accessor : public AccessorBase<T>
{
friend class ConcurrentSet;
using AccessorBase<T>::AccessorBase;
private:
using AccessorBase<T>::accessor;
typedef SkipList<T> list;
typedef typename SkipList<T>::Iterator list_it;
typedef typename SkipList<T>::ConstIterator list_it_con;
public:
std::pair<list_it, bool> insert(const T &item)
ConcurrentSet() {}
class Accessor : public AccessorBase<T>
{
return accessor.insert(item);
}
friend class ConcurrentSet;
std::pair<list_it, bool> insert(T &&item)
{
return accessor.insert(std::forward<T>(item));
}
using AccessorBase<T>::AccessorBase;
list_it_con find(const T &item) const { return accessor.find(item); }
private:
using AccessorBase<T>::accessor;
list_it find(const T &item) { return accessor.find(item); }
public:
std::pair<list_it, bool> insert(const T &item)
{
return accessor.insert(item);
}
bool contains(const T &item) const
{
return this->find(item) != this->end();
}
std::pair<list_it, bool> insert(T &&item)
{
return accessor.insert(std::forward<T>(item));
}
bool remove(const T &item) { return accessor.remove(item); }
};
list_it_con find(const T &item) const { return accessor.find(item); }
Accessor access() { return Accessor(&skiplist); }
list_it find(const T &item) { return accessor.find(item); }
const Accessor access() const { return Accessor(&skiplist); }
bool contains(const T &item) const
{
return this->find(item) != this->end();
}
private:
list skiplist;
bool remove(const T &item) { return accessor.remove(item); }
};
Accessor access() { return Accessor(&skiplist); }
const Accessor access() const { return Accessor(&skiplist); }
private:
list skiplist;
};

View File

@ -63,7 +63,7 @@ public:
}
T* find(const tx::Transaction& t)
T* find(const tx::Transaction& t) const
{
auto r = head.load(std::memory_order_seq_cst);

View File

@ -24,6 +24,7 @@ public:
"-o", out_file, // ouput file
"-I./include", // include paths (TODO: parameter)
"-I./src", "-I../../libs/fmt",
"-L./ -lmemgraph_pic",
"-shared -fPIC" // shared library flags
);

View File

@ -13,7 +13,7 @@ auto create_query_action =
if (kv.second == ClauseAction::CreateNode) {
// create node
auto &name = kv.first;
code += LINE(fmt::format(code::create_vertex, name));
code += code_line(code::create_vertex, name);
// update properties
code += update_properties(action_data, name);
@ -21,8 +21,8 @@ auto create_query_action =
// update labels
auto entity_data = action_data.get_entity_property(name);
for (auto &label : entity_data.tags) {
code += LINE(fmt::format(code::create_label, label));
code += LINE(fmt::format(code::add_label, name, label));
code += code_line(code::create_label, label);
code += code_line(code::add_label, name, label);
}
// mark node as created
@ -32,7 +32,7 @@ auto create_query_action =
if (kv.second == ClauseAction::CreateRelationship) {
// create relationship
auto name = kv.first;
code += LINE(fmt::format(code::create_edge, name));
code += code_line(code::create_edge, name);
// update properties
code += update_properties(action_data, name);
@ -40,8 +40,8 @@ auto create_query_action =
// update tag
auto entity_data = action_data.get_entity_property(name);
for (auto &tag : entity_data.tags) {
code += LINE(fmt::format(code::find_type, tag));
code += LINE(fmt::format(code::set_type, name, tag));
code += code_line(code::find_type, tag);
code += code_line(code::set_type, name, tag);
}
// find start and end node
@ -65,15 +65,15 @@ auto create_query_action =
// define direction
if (relationship_data.direction == Direction::Right) {
code += LINE(fmt::format(code::node_out, left_node, name));
code += LINE(fmt::format(code::node_in, right_node, name));
code += LINE(fmt::format(code::edge_from, name, left_node));
code += LINE(fmt::format(code::edge_to, name, right_node));
code += code_line(code::node_out, left_node, name);
code += code_line(code::node_in, right_node, name);
code += code_line(code::edge_from, name, left_node);
code += code_line(code::edge_to, name, right_node);
} else if (relationship_data.direction == Direction::Left) {
code += LINE(fmt::format(code::node_out, right_node, name));
code += LINE(fmt::format(code::node_in, left_node, name));
code += LINE(fmt::format(code::edge_from, name, right_node));
code += LINE(fmt::format(code::edge_to, name, left_node));
code += code_line(code::node_out, right_node, name);
code += code_line(code::node_in, left_node, name);
code += code_line(code::edge_from, name, right_node);
code += code_line(code::edge_to, name, left_node);
}
// mark relationship as created

View File

@ -11,10 +11,10 @@ auto delete_query_action =
for (auto const &kv : action_data.actions) {
auto entity = kv.first;
if (kv.second == ClauseAction::DeleteNode) {
code += LINE(fmt::format("// DELETE Node({})", entity));
code += code_line("// DELETE Node({})", entity);
}
if (kv.second == ClauseAction::DeleteRelationship) {
code += LINE(fmt::format("// DELETE Relationship({})", entity));
code += code_line("// DELETE Relationship({})", entity);
}
}

View File

@ -24,7 +24,7 @@ auto update_properties(const QueryActionData &action_data,
for (auto &property : entity_data.properties) {
auto index =
action_data.parameter_index.at(ParameterIndexKey(name, property));
code += LINE(fmt::format(code::set_property, name, property, index));
code += code_line(code::set_property, name, property, index);
}
return code;

View File

@ -36,7 +36,7 @@ auto match_query_action =
if (place == entity_search::search_internal_id) {
auto index = fetch_internal_index(action_data, name);
code +=
LINE(fmt::format(code::match_vertex_by_id, name, index));
code_line(code::match_vertex_by_id, name, index);
}
}
@ -49,7 +49,7 @@ auto match_query_action =
auto place = action_data.csm.min(kv.first);
if (place == entity_search::search_internal_id) {
auto index = fetch_internal_index(action_data, name);
code += LINE(fmt::format(code::match_edge_by_id, name, index));
code += code_line(code::match_edge_by_id, name, index);
}
}
}

View File

@ -9,7 +9,7 @@ auto return_query_action =
std::string code = "";
const auto &elements = action_data.return_elements;
code += LINE(fmt::format("// number of elements {}", elements.size()));
code += code_line("// number of elements {}", elements.size());
// TODO: call bolt serialization
for (const auto& element : elements) {
@ -19,10 +19,10 @@ auto return_query_action =
fmt::format("{} couldn't be found (RETURN clause).", entity));
}
if (element.is_entity_only()) {
code += LINE(fmt::format(code::print_properties, entity));
code += code_line(code::print_properties, entity);
} else if (element.is_projection()) {
auto &property = element.property;
code += LINE(fmt::format(code::print_property, entity, property));
code += code_line(code::print_property, entity, property);
}
}

View File

@ -4,5 +4,5 @@
auto transaction_begin_action = [](CypherStateData &,
const QueryActionData &) -> std::string {
return LINE(code::transaction_begin);
return code_line(code::transaction_begin);
};

View File

@ -4,5 +4,6 @@
auto transaction_commit_action = [](CypherStateData &,
const QueryActionData &) -> std::string {
return LINE(code::transaction_commit) + LINE(code::return_empty_result);
return code_line(code::transaction_commit) +
code_line(code::return_empty_result);
};

View File

@ -127,20 +127,6 @@ auto load_queries(Db& db)
return true;
};
auto find_by_label = [&db](const properties_t &args)
{
auto &t = db.tx_engine.begin();
auto &label = db.graph.label_store.find_or_create("LABEL");
auto &index_record_collection =
db.graph.vertices.find_label_index(label);
auto accessor = index_record_collection.access();
cout << "VERTICES" << endl;
for (auto& v : accessor) {
cout << v.record->data.props.at("name").as<String>().value << endl;
}
return true;
};
// MATCH (n1), (n2) WHERE ID(n1)=0 AND ID(n2)=1 CREATE (n1)<-[r:IS {age: 25, weight: 70}]-(n2) RETURN r
auto create_edge_v2 = [&db](const properties_t &args)
{
@ -163,6 +149,49 @@ auto load_queries(Db& db)
};
queries[15648836733456301916u] = create_edge_v2;
// MATCH (n) RETURN n
auto match_all_nodes = [&db](const properties_t &args)
{
auto &t = db.tx_engine.begin();
auto vertices_accessor = db.graph.vertices.access();
for (auto &it : vertices_accessor) {
auto vertex = it.second.find(t);
if (vertex == nullptr) continue;
cout_properties(vertex->data.props);
}
// TODO
// db.graph.vertices.filter().all(t, handler);
t.commit();
return true;
};
queries[15284086425088081497u] = match_all_nodes;
// MATCH (n:LABEL) RETURN n
auto find_by_label = [&db](const properties_t &args)
{
auto &t = db.tx_engine.begin();
auto &label = db.graph.label_store.find_or_create("LABEL");
auto &index_record_collection =
db.graph.vertices.find_label_index(label);
auto accessor = index_record_collection.access();
cout << "VERTICES" << endl;
for (auto& v : accessor) {
cout << v.record->data.props.at("name").as<String>().value << endl;
}
// TODO
// db.graph.vertices.fileter("LABEL").all(t, handler);
return true;
};
queries[4857652843629217005u] = find_by_label;
queries[10597108978382323595u] = create_account;
queries[5397556489557792025u] = create_labeled_and_named_node;
queries[7939106225150551899u] = create_edge;
@ -170,7 +199,6 @@ auto load_queries(Db& db)
queries[11198568396549106428u] = find_node_by_internal_id;
queries[8320600413058284114u] = find_edge_by_internal_id;
queries[6813335159006269041u] = update_node;
queries[4857652843629217005u] = find_by_label;
return queries;
}

View File

@ -65,10 +65,10 @@ const std::string print_property =
std::string debug_print_vertex_labels()
{
#ifdef DEBUG
return LINE("PRINT_PROPS(vertex_accessor.properties());") +
LINE("cout << \"LABELS:\" << endl;") +
LINE("for (auto label_ref : vertex_accessor.labels()) {") +
LINE("cout << label_ref.get() << endl;") + LINE("}");
return code_line("PRINT_PROPS(vertex_accessor.properties());") +
code_line("cout << \"LABELS:\" << endl;") +
code_line("for (auto label_ref : vertex_accessor.labels()) {") +
code_line("cout << label_ref.get() << endl;") + code_line("}");
#else
return "";
#endif

View File

@ -3,15 +3,14 @@
#include <iostream>
#include <string>
#include "fmt/format.h"
#include "storage/model/properties/properties.hpp"
#include "storage/model/properties/traversers/jsonwriter.hpp"
#include "storage/model/properties/traversers/consolewriter.hpp"
#include "storage/model/properties/traversers/jsonwriter.hpp"
using std::cout;
using std::endl;
std::string LINE(std::string line) { return "\t" + line + "\n"; }
void print_props(const Properties &properties)
{
StringBuffer buffer;
@ -33,9 +32,25 @@ void cout_properties(const Properties &properties)
cout << "----" << endl;
}
void cout_property(const std::string& key, const Property& property)
void cout_property(const std::string &key, const Property &property)
{
ConsoleWriter writer;
writer.handle(key, property);
cout << "----" << endl;
}
// wrapper for fmt format
template <typename... Args>
std::string format(const std::string &format_str, const Args &... args)
{
return fmt::format(format_str, args...);
}
// wrapper for single code line
template <typename... Args>
std::string code_line(const std::string &format_str, const Args &... args)
{
return "\t" + format(format_str, args...) + "\n";
}

View File

@ -7,6 +7,7 @@
class Edges;
// TODO: Edge, Db, Edge::Accessor
class Edge::Accessor : public RecordAccessor<Edge, Edges, Edge::Accessor>
{
public:
@ -24,6 +25,7 @@ public:
return edge_type_ref_t(*this->record->data.edge_type);
}
// TODO: VertexAccessor
void from(VertexRecord *vertex_record)
{
this->record->data.from = vertex_record;

View File

@ -1,5 +1,10 @@
#include "storage/vertices.hpp"
Vertices::vertices_t::Accessor Vertices::access()
{
return vertices.access();
}
const Vertex::Accessor Vertices::find(tx::Transaction &t, const Id &id)
{
auto vertices_accessor = vertices.access();
@ -15,6 +20,21 @@ const Vertex::Accessor Vertices::find(tx::Transaction &t, const Id &id)
return Vertex::Accessor(vertex, &vertices_iterator->second, this);
}
// TODO
const Vertex::Accessor Vertices::first(tx::Transaction &t)
{
auto vertices_accessor = vertices.access();
auto vertices_iterator = vertices_accessor.begin();
if (vertices_iterator == vertices_accessor.end()) return Vertex::Accessor();
auto vertex = vertices_iterator->second.find(t);
if (vertex == nullptr) return Vertex::Accessor();
return Vertex::Accessor(vertex, &vertices_iterator->second, this);
}
Vertex::Accessor Vertices::insert(tx::Transaction &t)
{
// get next vertex id

View File

@ -28,6 +28,7 @@ file(COPY ${CMAKE_SOURCE_DIR}/tests/data
foreach(test ${unit_test_names})
set(test_name unit_${test})
add_executable(${test_name} unit/${test}.cpp ${src_dir}/template_engine/engine.cpp)
target_link_libraries(${test_name} memgraph)
# TODO: separate dependencies
target_link_libraries(${test_name} stdc++fs)
target_link_libraries(${test_name} cypher_lib)
@ -50,6 +51,7 @@ message(STATUS "Available concurrency tests are: ${concurrency_test_names}")
foreach(test ${concurrency_test_names})
set(test_name concurrent_${test})
add_executable(${test_name} concurrent/${test}.cpp)
target_link_libraries(${test_name} memgraph)
target_link_libraries(${test_name} Threads::Threads)
target_link_libraries(${test_name} ${fmt_static_lib})
add_test(NAME ${test_name} COMMAND ${test_name})
@ -59,7 +61,8 @@ endforeach()
## INTEGRATION TESTS
# test hard coded queries
add_executable(integration_queries integration/queries.cpp ${memgraph_src_files})
add_executable(integration_queries integration/queries.cpp)
target_link_libraries(integration_queries memgraph)
target_link_libraries(integration_queries ${fmt_static_lib})
add_test(NAME integration_queries COMMAND integration_queries)
set_property(TARGET integration_queries PROPERTY CXX_STANDARD 14)
@ -79,30 +82,35 @@ set_property(TARGET integration_memgraph_bolt PROPERTY CXX_STANDARD 14)
## MANUAL TESTS
# cypher_ast
add_executable(manual_cypher_ast manual/cypher_ast.cpp ${memgraph_src_files})
add_executable(manual_cypher_ast manual/cypher_ast.cpp)
target_link_libraries(manual_cypher_ast memgraph)
target_link_libraries(manual_cypher_ast ${fmt_static_lib})
target_link_libraries(manual_cypher_ast cypher_lib)
set_property(TARGET manual_cypher_ast PROPERTY CXX_STANDARD 14)
# queries
add_executable(manual_queries manual/queries.cpp ${memgraph_src_files})
add_executable(manual_queries manual/queries.cpp)
target_link_libraries(manual_queries memgraph)
target_link_libraries(manual_queries ${fmt_static_lib})
target_link_libraries(manual_queries cypher_lib)
set_property(TARGET manual_queries PROPERTY CXX_STANDARD 14)
# query_engine
add_executable(manual_query_engine manual/query_engine.cpp ${memgraph_src_files})
add_executable(manual_query_engine manual/query_engine.cpp)
target_link_libraries(manual_query_engine memgraph)
target_link_libraries(manual_query_engine ${fmt_static_lib})
target_link_libraries(manual_query_engine dl)
target_link_libraries(manual_query_engine cypher_lib)
set_property(TARGET manual_query_engine PROPERTY CXX_STANDARD 14)
# query_hasher
add_executable(manual_query_hasher manual/query_hasher.cpp ${memgraph_src_files})
add_executable(manual_query_hasher manual/query_hasher.cpp)
target_link_libraries(manual_query_hasher memgraph)
target_link_libraries(manual_query_hasher ${fmt_static_lib})
set_property(TARGET manual_query_hasher PROPERTY CXX_STANDARD 14)
# query_action_processor
add_executable(manual_cpp_generator manual/cpp_generator.cpp ${memgraph_src_files})
add_executable(manual_cpp_generator manual/cpp_generator.cpp)
target_link_libraries(manual_cpp_generator memgraph)
target_link_libraries(manual_cpp_generator ${fmt_static_lib})
set_property(TARGET manual_cpp_generator PROPERTY CXX_STANDARD 14)

View File

@ -40,23 +40,23 @@ std::string decoded = "A quick brown fox jumps over a lazy dog";
int main(void)
{
DummyStream stream;
Decoder decoder(stream);
// DummyStream stream;
// Decoder decoder(stream);
for(size_t i = 0; i < N; ++i)
{
auto& chunk = chunks[i];
auto finished = decoder.decode(chunk.data(), chunk.size());
// for(size_t i = 0; i < N; ++i)
// {
// auto& chunk = chunks[i];
// auto finished = decoder.decode(chunk.data(), chunk.size());
// break early if finished
if(finished)
break;
}
// // break early if finished
// if(finished)
// break;
// }
assert(decoded.size() == stream.data.size());
// assert(decoded.size() == stream.data.size());
for(size_t i = 0; i < decoded.size(); ++i)
assert(decoded[i] == stream.data[i]);
// for(size_t i = 0; i < decoded.size(); ++i)
// assert(decoded[i] == stream.data[i]);
return 0;
}

View File

@ -70,19 +70,19 @@ int main(void)
write_ff(encoder, 10);
write_ff(encoder, 10);
encoder.finish();
encoder.flush();
write_ff(encoder, 10);
write_ff(encoder, 10);
encoder.finish();
encoder.flush();
// this should be two chunks, one of size 65533 and the other of size 1467
write_ff(encoder, 67000);
encoder.finish();
encoder.flush();
for(int i = 0; i < 10000; ++i)
write_ff(encoder, 1500);
encoder.finish();
encoder.flush();
assert(stream.pop_size() == 20);
check_ff(stream, 20);

View File

@ -1,54 +0,0 @@
#include <iostream>
#include "data_structures/skiplist/skiplistset.hpp"
using std::cout;
using std::endl;
void print_skiplist(const SkipListSet<int>::Accessor& skiplist)
{
cout << "---- skiplist set now has: ";
for(auto& item : skiplist)
cout << item << ", ";
cout << "----" << endl;
}
int main(void)
{
SkipListSet<int> set;
auto accessor = set.access();
cout << std::boolalpha;
cout << "added non-existing 1? (true) "
<< accessor.insert(1).second << endl;
cout << "added already existing 1? (false) "
<< accessor.insert(1).second << endl;
accessor.insert(2);
print_skiplist(accessor);
cout << "item 3 doesn't exist? (true) "
<< (accessor.find(3) == accessor.end()) << endl;
cout << "item 3 exists? (false) "
<< accessor.contains(3) << endl;
cout << "item 2 exists? (true) "
<< (accessor.find(2) != accessor.end()) << endl;
cout << "at item 2 is? 2 " << *accessor.find(2) << endl;
cout << "removed existing 1? (true) " << accessor.remove(1) << endl;
cout << "removed non-existing 3? (false) " << accessor.remove(3) << endl;
accessor.insert(1);
accessor.insert(4);
print_skiplist(accessor);
return 0;
}