From fe90d6f0f91e35457d0c234e32d17ada5b2f4965 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Fri, 16 Jun 2023 09:20:03 +0800 Subject: [PATCH 01/48] Init implementation for demo_storage --- demo_storage/CMakeLists.txt | 160 + demo_storage/misc/cpplint.py | 6901 ++++++++++++++++++++++++++++++++++ demo_storage/predefine.h | 923 +++++ demo_storage/src/storage.cc | 176 + demo_storage/src/storage.h | 577 +++ 5 files changed, 8737 insertions(+) create mode 100644 demo_storage/CMakeLists.txt create mode 100755 demo_storage/misc/cpplint.py create mode 100644 demo_storage/predefine.h create mode 100644 demo_storage/src/storage.cc create mode 100644 demo_storage/src/storage.h diff --git a/demo_storage/CMakeLists.txt b/demo_storage/CMakeLists.txt new file mode 100644 index 0000000..d48653a --- /dev/null +++ b/demo_storage/CMakeLists.txt @@ -0,0 +1,160 @@ +cmake_minimum_required(VERSION 2.8) + +if(POLICY CMP0026) + cmake_policy(SET CMP0026 OLD) +endif() + +if(POLICY CMP0048) + cmake_policy(SET CMP0048 NEW) +endif() + +if(POLICY CMP0069) + cmake_policy(SET CMP0069 NEW) +endif() + +set(GRIN_MAJOR_VERSION 0) +set(GRIN_MINOR_VERSION 1) +set(GRIN_PATCH_VERSION 0) +set(GRIN_VERSION ${GRIN_MAJOR_VERSION}.${GRIN_MINOR_VERSION}.${GRIN_PATCH_VERSION}) +project(grin-demo-storage LANGUAGES C CXX VERSION ${GRIN_VERSION}) + +option(BUILD_TESTS "Build unit tests" ON) +option(USE_LTO "Using IPO/LTO support for link-time optimization" OFF) + +# ------------------------------------------------------------------------------ +# setting default cmake type to Release +# ------------------------------------------------------------------------------ +set(DEFAULT_BUILD_TYPE "Release") +if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message(STATUS "Setting build type to '${DEFAULT_BUILD_TYPE}' as none was specified.") + set(CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}" CACHE + STRING "Choose the type of build." FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Release" "MinSizeRel" "RelWithDebInfo") +endif () + +if(NOT (CMAKE_CXX_COMPILER_LAUNCHER MATCHES "ccache") AND NOT (CMAKE_C_COMPILER_LAUNCHER MATCHES "ccache")) + find_program(ccache_EXECUTABLE ccache) + if(ccache_EXECUTABLE) + set(CMAKE_C_COMPILER_LAUNCHER ${ccache_EXECUTABLE}) + set(CMAKE_CXX_COMPILER_LAUNCHER ${ccache_EXECUTABLE}) + add_custom_target(grin-ccache-stats + COMMAND ${ccache_EXECUTABLE} --show-stats + ) + else() + add_custom_target(grin-ccache-stats + COMMAND echo "ccache not found." + ) + endif(ccache_EXECUTABLE) +endif() + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -Wall") + +if (APPLE) + set(CMAKE_MACOSX_RPATH ON) +else () + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath,$ORIGIN") +endif () + +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 -g -fno-omit-frame-pointer -fsanitize=address") +set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address") +set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -g") + +message(STATUS "[demo-storage] will build in type: ${CMAKE_BUILD_TYPE}") + +# ------------------------------------------------------------------------------ +# cmake configs +# ------------------------------------------------------------------------------ +include(CheckLibraryExists) +include(GNUInstallDirs) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) +add_library(${PROJECT_NAME} INTERFACE) +target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_17) +target_include_directories( + ${PROJECT_NAME} + INTERFACE + $ + $ +) + +# ------------------------------------------------------------------------------ +# build demo-storage +# ------------------------------------------------------------------------------ + +find_package(Protobuf REQUIRED) + +find_package(glog REQUIRED) + +file(GLOB_RECURSE DEMO_GRIN_SRC_FILES "src/*.cc") + +message(${DEMO_GRIN_SRC_FILES}) + +add_library(demo-grin SHARED ${DEMO_GRIN_SRC_FILES}) + +target_compile_features(demo-grin PUBLIC cxx_std_17) + +target_include_directories(demo-grin SYSTEM BEFORE PUBLIC ${PROJECT_SOURCE_DIR}/../include ${Protobuf_INCLUDE_DIRS}) + +target_link_libraries(demo-grin PUBLIC ${Protobuf_LIBRARIES} glog::glog) + +# ------------------------------------------------------------------------------ +# complile protobuf to generate cpp files +# ------------------------------------------------------------------------------ +set(DST_DIR "${PROJECT_SOURCE_DIR}/src/common/") + +list(APPEND PROTO_FLAGS -I${PROJECT_SOURCE_DIR}/../proto/) + +file(GLOB PROTO_FILES RELATIVE "${PROJECT_SOURCE_DIR}/../proto" "${PROJECT_SOURCE_DIR}/../proto/*.proto") + +set(PROTO_SRCS "") +set(PROTO_HDRS "") + +foreach(f ${PROTO_FILES}) + message(STATUS "Found proto - " ${f}) + get_filename_component(FIL_WE ${f} NAME_WE) + list(APPEND PROTO_SRCS "${DST_DIR}/${FIL_WE}.pb.cc") + list(APPEND PROTO_HDRS "${DST_DIR}/${FIL_WE}.pb.h") + + execute_process(COMMAND ${Protobuf_PROTOC_EXECUTABLE} ${PROTO_FLAGS} --cpp_out=${DST_DIR} ${f}) +endforeach() + +set_source_files_properties(${PROTO_SRCS} ${PROTO_HDRS} PROPERTIES GENERATED TRUE) + +# ------------------------------------------------------------------------------ +# build tests +# ------------------------------------------------------------------------------ +if (BUILD_TESTS) + file(GLOB TEST_FILES RELATIVE "${PROJECT_SOURCE_DIR}/test" "${PROJECT_SOURCE_DIR}/test/*.cc") + + foreach(f ${TEST_FILES}) + string(REGEX MATCH "^(.*)\\.[^.]*$" dummy ${f}) + set(E_NAME ${CMAKE_MATCH_1}) + message(STATUS "Found test for demo storage - " ${E_NAME}) + add_executable(${E_NAME} test/${E_NAME}.cc) + target_include_directories(${E_NAME} SYSTEM BEFORE PRIVATE ${PROJECT_SOURCE_DIR}/../include ${Protobuf_INCLUDE_DIRS}) + target_link_libraries(${E_NAME} PRIVATE demo-grin Threads::Threads ${CMAKE_DL_LIBS} ${Protobuf_LIBRARIES} glog::glog) + endforeach() +endif() + +# ------------------------------------------------------------------------------ +# Format code & cpplint +# ------------------------------------------------------------------------------ +file(GLOB_RECURSE FILES_NEED_FORMAT "src/*.h" "src/*.cc" + "test/*.h" "test/*.cc") +list(REMOVE_ITEM FILES_NEED_FORMAT "${PROJECT_SOURCE_DIR}/src/common/graph.pb.h" "${PROJECT_SOURCE_DIR}/src/common/graph.pb.cc") + +file(GLOB_RECURSE FILES_NEED_LINT "src/*.h" "src/*.cc" + "test/*.h" "test/*.cc") +list(REMOVE_ITEM FILES_NEED_LINT "${PROJECT_SOURCE_DIR}/src/common/graph.pb.h" "${PROJECT_SOURCE_DIR}/src/common/graph.pb.cc") + +add_custom_target(grin-clformat + COMMAND clang-format-8 --style=file -i ${FILES_NEED_FORMAT} + COMMENT "Running clang-format." + VERBATIM) + +add_custom_target(grin-cpplint + COMMAND ${PROJECT_SOURCE_DIR}/misc/cpplint.py --root=${PROJECT_SOURCE_DIR} ${FILES_NEED_LINT} + COMMENT "Running cpplint check." + VERBATIM) diff --git a/demo_storage/misc/cpplint.py b/demo_storage/misc/cpplint.py new file mode 100755 index 0000000..7685762 --- /dev/null +++ b/demo_storage/misc/cpplint.py @@ -0,0 +1,6901 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2009 Google Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Does google-lint on c++ files. + +The goal of this script is to identify places in the code that *may* +be in non-compliance with google style. It does not attempt to fix +up these problems -- the point is to educate. It does also not +attempt to find all problems, or to ensure that everything it does +find is legitimately a problem. + +In particular, we can get very confused by /* and // inside strings! +We do a small hack, which is to ignore //'s with "'s after them on the +same line, but it is far from perfect (in either direction). +""" + +import codecs +import copy +import getopt +import glob +import itertools +import math # for log +import os +import re +import sre_compile +import string +import sys +import sysconfig +import unicodedata +import xml.etree.ElementTree + +# if empty, use defaults +_valid_extensions = set([]) + +__VERSION__ = '1.5.4' + +try: + xrange # Python 2 +except NameError: + # -- pylint: disable=redefined-builtin + xrange = range # Python 3 + + +_USAGE = """ +Syntax: cpplint.py [--verbose=#] [--output=emacs|eclipse|vs7|junit|sed|gsed] + [--filter=-x,+y,...] + [--counting=total|toplevel|detailed] [--root=subdir] + [--repository=path] + [--linelength=digits] [--headers=x,y,...] + [--recursive] + [--exclude=path] + [--extensions=hpp,cpp,...] + [--includeorder=default|standardcfirst] + [--quiet] + [--version] + [file] ... + + Style checker for C/C++ source files. + This is a fork of the Google style checker with minor extensions. + + The style guidelines this tries to follow are those in + https://google.github.io/styleguide/cppguide.html + + Every problem is given a confidence score from 1-5, with 5 meaning we are + certain of the problem, and 1 meaning it could be a legitimate construct. + This will miss some errors, and is not a substitute for a code review. + + To suppress false-positive errors of a certain category, add a + 'NOLINT(category)' comment to the line. NOLINT or NOLINT(*) + suppresses errors of all categories on that line. + + The files passed in will be linted; at least one file must be provided. + Default linted extensions are %s. + Other file types will be ignored. + Change the extensions with the --extensions flag. + + Flags: + + output=emacs|eclipse|vs7|junit|sed|gsed + By default, the output is formatted to ease emacs parsing. Visual Studio + compatible output (vs7) may also be used. Further support exists for + eclipse (eclipse), and JUnit (junit). XML parsers such as those used + in Jenkins and Bamboo may also be used. + The sed format outputs sed commands that should fix some of the errors. + Note that this requires gnu sed. If that is installed as gsed on your + system (common e.g. on macOS with homebrew) you can use the gsed output + format. Sed commands are written to stdout, not stderr, so you should be + able to pipe output straight to a shell to run the fixes. + + verbose=# + Specify a number 0-5 to restrict errors to certain verbosity levels. + Errors with lower verbosity levels have lower confidence and are more + likely to be false positives. + + quiet + Don't print anything if no errors are found. + + filter=-x,+y,... + Specify a comma-separated list of category-filters to apply: only + error messages whose category names pass the filters will be printed. + (Category names are printed with the message and look like + "[whitespace/indent]".) Filters are evaluated left to right. + "-FOO" and "FOO" means "do not print categories that start with FOO". + "+FOO" means "do print categories that start with FOO". + + Examples: --filter=-whitespace,+whitespace/braces + --filter=whitespace,runtime/printf,+runtime/printf_format + --filter=-,+build/include_what_you_use + + To see a list of all the categories used in cpplint, pass no arg: + --filter= + + counting=total|toplevel|detailed + The total number of errors found is always printed. If + 'toplevel' is provided, then the count of errors in each of + the top-level categories like 'build' and 'whitespace' will + also be printed. If 'detailed' is provided, then a count + is provided for each category like 'build/class'. + + repository=path + The top level directory of the repository, used to derive the header + guard CPP variable. By default, this is determined by searching for a + path that contains .git, .hg, or .svn. When this flag is specified, the + given path is used instead. This option allows the header guard CPP + variable to remain consistent even if members of a team have different + repository root directories (such as when checking out a subdirectory + with SVN). In addition, users of non-mainstream version control systems + can use this flag to ensure readable header guard CPP variables. + + Examples: + Assuming that Alice checks out ProjectName and Bob checks out + ProjectName/trunk and trunk contains src/chrome/ui/browser.h, then + with no --repository flag, the header guard CPP variable will be: + + Alice => TRUNK_SRC_CHROME_BROWSER_UI_BROWSER_H_ + Bob => SRC_CHROME_BROWSER_UI_BROWSER_H_ + + If Alice uses the --repository=trunk flag and Bob omits the flag or + uses --repository=. then the header guard CPP variable will be: + + Alice => SRC_CHROME_BROWSER_UI_BROWSER_H_ + Bob => SRC_CHROME_BROWSER_UI_BROWSER_H_ + + root=subdir + The root directory used for deriving header guard CPP variable. + This directory is relative to the top level directory of the repository + which by default is determined by searching for a directory that contains + .git, .hg, or .svn but can also be controlled with the --repository flag. + If the specified directory does not exist, this flag is ignored. + + Examples: + Assuming that src is the top level directory of the repository (and + cwd=top/src), the header guard CPP variables for + src/chrome/browser/ui/browser.h are: + + No flag => CHROME_BROWSER_UI_BROWSER_H_ + --root=chrome => BROWSER_UI_BROWSER_H_ + --root=chrome/browser => UI_BROWSER_H_ + --root=.. => SRC_CHROME_BROWSER_UI_BROWSER_H_ + + linelength=digits + This is the allowed line length for the project. The default value is + 80 characters. + + Examples: + --linelength=120 + + recursive + Search for files to lint recursively. Each directory given in the list + of files to be linted is replaced by all files that descend from that + directory. Files with extensions not in the valid extensions list are + excluded. + + exclude=path + Exclude the given path from the list of files to be linted. Relative + paths are evaluated relative to the current directory and shell globbing + is performed. This flag can be provided multiple times to exclude + multiple files. + + Examples: + --exclude=one.cc + --exclude=src/*.cc + --exclude=src/*.cc --exclude=test/*.cc + + extensions=extension,extension,... + The allowed file extensions that cpplint will check + + Examples: + --extensions=%s + + includeorder=default|standardcfirst + For the build/include_order rule, the default is to blindly assume angle + bracket includes with file extension are c-system-headers (default), + even knowing this will have false classifications. + The default is established at google. + standardcfirst means to instead use an allow-list of known c headers and + treat all others as separate group of "other system headers". The C headers + included are those of the C-standard lib and closely related ones. + + headers=x,y,... + The header extensions that cpplint will treat as .h in checks. Values are + automatically added to --extensions list. + (by default, only files with extensions %s will be assumed to be headers) + + Examples: + --headers=%s + --headers=hpp,hxx + --headers=hpp + + cpplint.py supports per-directory configurations specified in CPPLINT.cfg + files. CPPLINT.cfg file can contain a number of key=value pairs. + Currently the following options are supported: + + set noparent + filter=+filter1,-filter2,... + exclude_files=regex + linelength=80 + root=subdir + headers=x,y,... + + "set noparent" option prevents cpplint from traversing directory tree + upwards looking for more .cfg files in parent directories. This option + is usually placed in the top-level project directory. + + The "filter" option is similar in function to --filter flag. It specifies + message filters in addition to the |_DEFAULT_FILTERS| and those specified + through --filter command-line flag. + + "exclude_files" allows to specify a regular expression to be matched against + a file name. If the expression matches, the file is skipped and not run + through the linter. + + "linelength" allows to specify the allowed line length for the project. + + The "root" option is similar in function to the --root flag (see example + above). Paths are relative to the directory of the CPPLINT.cfg. + + The "headers" option is similar in function to the --headers flag + (see example above). + + CPPLINT.cfg has an effect on files in the same directory and all + sub-directories, unless overridden by a nested configuration file. + + Example file: + filter=-build/include_order,+build/include_alpha + exclude_files=.*\\.cc + + The above example disables build/include_order warning and enables + build/include_alpha as well as excludes all .cc from being + processed by linter, in the current directory (where the .cfg + file is located) and all sub-directories. +""" + +# We categorize each error message we print. Here are the categories. +# We want an explicit list so we can list them all in cpplint --filter=. +# If you add a new error message with a new category, add it to the list +# here! cpplint_unittest.py should tell you if you forget to do this. +_ERROR_CATEGORIES = [ + 'build/class', + 'build/c++11', + 'build/c++14', + 'build/c++tr1', + 'build/deprecated', + 'build/endif_comment', + 'build/explicit_make_pair', + 'build/forward_decl', + 'build/header_guard', + 'build/include', + 'build/include_subdir', + 'build/include_alpha', + 'build/include_order', + 'build/include_what_you_use', + 'build/namespaces_headers', + 'build/namespaces_literals', + 'build/namespaces', + 'build/printf_format', + 'build/storage_class', + 'legal/copyright', + 'readability/alt_tokens', + 'readability/braces', + 'readability/casting', + 'readability/check', + 'readability/constructors', + 'readability/fn_size', + 'readability/inheritance', + 'readability/multiline_comment', + 'readability/multiline_string', + 'readability/namespace', + 'readability/nolint', + 'readability/nul', + 'readability/strings', + 'readability/todo', + 'readability/utf8', + 'runtime/arrays', + 'runtime/casting', + 'runtime/explicit', + 'runtime/int', + 'runtime/init', + 'runtime/invalid_increment', + 'runtime/member_string_references', + 'runtime/memset', + 'runtime/indentation_namespace', + 'runtime/operator', + 'runtime/printf', + 'runtime/printf_format', + 'runtime/references', + 'runtime/string', + 'runtime/threadsafe_fn', + 'runtime/vlog', + 'whitespace/blank_line', + 'whitespace/braces', + 'whitespace/comma', + 'whitespace/comments', + 'whitespace/empty_conditional_body', + 'whitespace/empty_if_body', + 'whitespace/empty_loop_body', + 'whitespace/end_of_line', + 'whitespace/ending_newline', + 'whitespace/forcolon', + 'whitespace/indent', + 'whitespace/line_length', + 'whitespace/newline', + 'whitespace/operators', + 'whitespace/parens', + 'whitespace/semicolon', + 'whitespace/tab', + 'whitespace/todo', + ] + +# keywords to use with --outputs which generate stdout for machine processing +_MACHINE_OUTPUTS = [ + 'junit', + 'sed', + 'gsed' +] + +# These error categories are no longer enforced by cpplint, but for backwards- +# compatibility they may still appear in NOLINT comments. +_LEGACY_ERROR_CATEGORIES = [ + 'readability/streams', + 'readability/function', + ] + +# The default state of the category filter. This is overridden by the --filter= +# flag. By default all errors are on, so only add here categories that should be +# off by default (i.e., categories that must be enabled by the --filter= flags). +# All entries here should start with a '-' or '+', as in the --filter= flag. +_DEFAULT_FILTERS = ['-build/include_alpha'] + +# The default list of categories suppressed for C (not C++) files. +_DEFAULT_C_SUPPRESSED_CATEGORIES = [ + 'readability/casting', + ] + +# The default list of categories suppressed for Linux Kernel files. +_DEFAULT_KERNEL_SUPPRESSED_CATEGORIES = [ + 'whitespace/tab', + ] + +# We used to check for high-bit characters, but after much discussion we +# decided those were OK, as long as they were in UTF-8 and didn't represent +# hard-coded international strings, which belong in a separate i18n file. + +# C++ headers +_CPP_HEADERS = frozenset([ + # Legacy + 'algobase.h', + 'algo.h', + 'alloc.h', + 'builtinbuf.h', + 'bvector.h', + 'complex.h', + 'defalloc.h', + 'deque.h', + 'editbuf.h', + 'fstream.h', + 'function.h', + 'hash_map', + 'hash_map.h', + 'hash_set', + 'hash_set.h', + 'hashtable.h', + 'heap.h', + 'indstream.h', + 'iomanip.h', + 'iostream.h', + 'istream.h', + 'iterator.h', + 'list.h', + 'map.h', + 'multimap.h', + 'multiset.h', + 'ostream.h', + 'pair.h', + 'parsestream.h', + 'pfstream.h', + 'procbuf.h', + 'pthread_alloc', + 'pthread_alloc.h', + 'rope', + 'rope.h', + 'ropeimpl.h', + 'set.h', + 'slist', + 'slist.h', + 'stack.h', + 'stdiostream.h', + 'stl_alloc.h', + 'stl_relops.h', + 'streambuf.h', + 'stream.h', + 'strfile.h', + 'strstream.h', + 'tempbuf.h', + 'tree.h', + 'type_traits.h', + 'vector.h', + # 17.6.1.2 C++ library headers + 'algorithm', + 'array', + 'atomic', + 'bitset', + 'chrono', + 'codecvt', + 'complex', + 'condition_variable', + 'deque', + 'exception', + 'forward_list', + 'fstream', + 'functional', + 'future', + 'initializer_list', + 'iomanip', + 'ios', + 'iosfwd', + 'iostream', + 'istream', + 'iterator', + 'limits', + 'list', + 'locale', + 'map', + 'memory', + 'mutex', + 'new', + 'numeric', + 'ostream', + 'queue', + 'random', + 'ratio', + 'regex', + 'scoped_allocator', + 'set', + 'sstream', + 'stack', + 'stdexcept', + 'streambuf', + 'string', + 'strstream', + 'system_error', + 'thread', + 'tuple', + 'typeindex', + 'typeinfo', + 'type_traits', + 'unordered_map', + 'unordered_set', + 'utility', + 'valarray', + 'vector', + # 17.6.1.2 C++14 headers + 'shared_mutex', + # 17.6.1.2 C++17 headers + 'any', + 'charconv', + 'codecvt', + 'execution', + 'filesystem', + 'memory_resource', + 'optional', + 'string_view', + 'variant', + # 17.6.1.2 C++ headers for C library facilities + 'cassert', + 'ccomplex', + 'cctype', + 'cerrno', + 'cfenv', + 'cfloat', + 'cinttypes', + 'ciso646', + 'climits', + 'clocale', + 'cmath', + 'csetjmp', + 'csignal', + 'cstdalign', + 'cstdarg', + 'cstdbool', + 'cstddef', + 'cstdint', + 'cstdio', + 'cstdlib', + 'cstring', + 'ctgmath', + 'ctime', + 'cuchar', + 'cwchar', + 'cwctype', + ]) + +# C headers +_C_HEADERS = frozenset([ + # System C headers + 'assert.h', + 'complex.h', + 'ctype.h', + 'errno.h', + 'fenv.h', + 'float.h', + 'inttypes.h', + 'iso646.h', + 'limits.h', + 'locale.h', + 'math.h', + 'setjmp.h', + 'signal.h', + 'stdalign.h', + 'stdarg.h', + 'stdatomic.h', + 'stdbool.h', + 'stddef.h', + 'stdint.h', + 'stdio.h', + 'stdlib.h', + 'stdnoreturn.h', + 'string.h', + 'tgmath.h', + 'threads.h', + 'time.h', + 'uchar.h', + 'wchar.h', + 'wctype.h', + # additional POSIX C headers + 'aio.h', + 'arpa/inet.h', + 'cpio.h', + 'dirent.h', + 'dlfcn.h', + 'fcntl.h', + 'fmtmsg.h', + 'fnmatch.h', + 'ftw.h', + 'glob.h', + 'grp.h', + 'iconv.h', + 'langinfo.h', + 'libgen.h', + 'monetary.h', + 'mqueue.h', + 'ndbm.h', + 'net/if.h', + 'netdb.h', + 'netinet/in.h', + 'netinet/tcp.h', + 'nl_types.h', + 'poll.h', + 'pthread.h', + 'pwd.h', + 'regex.h', + 'sched.h', + 'search.h', + 'semaphore.h', + 'setjmp.h', + 'signal.h', + 'spawn.h', + 'strings.h', + 'stropts.h', + 'syslog.h', + 'tar.h', + 'termios.h', + 'trace.h', + 'ulimit.h', + 'unistd.h', + 'utime.h', + 'utmpx.h', + 'wordexp.h', + # additional GNUlib headers + 'a.out.h', + 'aliases.h', + 'alloca.h', + 'ar.h', + 'argp.h', + 'argz.h', + 'byteswap.h', + 'crypt.h', + 'endian.h', + 'envz.h', + 'err.h', + 'error.h', + 'execinfo.h', + 'fpu_control.h', + 'fstab.h', + 'fts.h', + 'getopt.h', + 'gshadow.h', + 'ieee754.h', + 'ifaddrs.h', + 'libintl.h', + 'mcheck.h', + 'mntent.h', + 'obstack.h', + 'paths.h', + 'printf.h', + 'pty.h', + 'resolv.h', + 'shadow.h', + 'sysexits.h', + 'ttyent.h', + # Additional linux glibc headers + 'dlfcn.h', + 'elf.h', + 'features.h', + 'gconv.h', + 'gnu-versions.h', + 'lastlog.h', + 'libio.h', + 'link.h', + 'malloc.h', + 'memory.h', + 'netash/ash.h', + 'netatalk/at.h', + 'netax25/ax25.h', + 'neteconet/ec.h', + 'netipx/ipx.h', + 'netiucv/iucv.h', + 'netpacket/packet.h', + 'netrom/netrom.h', + 'netrose/rose.h', + 'nfs/nfs.h', + 'nl_types.h', + 'nss.h', + 're_comp.h', + 'regexp.h', + 'sched.h', + 'sgtty.h', + 'stab.h', + 'stdc-predef.h', + 'stdio_ext.h', + 'syscall.h', + 'termio.h', + 'thread_db.h', + 'ucontext.h', + 'ustat.h', + 'utmp.h', + 'values.h', + 'wait.h', + 'xlocale.h', + # Hardware specific headers + 'arm_neon.h', + 'emmintrin.h', + 'xmmintin.h', + ]) + +# Folders of C libraries so commonly used in C++, +# that they have parity with standard C libraries. +C_STANDARD_HEADER_FOLDERS = frozenset([ + # standard C library + "sys", + # glibc for linux + "arpa", + "asm-generic", + "bits", + "gnu", + "net", + "netinet", + "protocols", + "rpc", + "rpcsvc", + "scsi", + # linux kernel header + "drm", + "linux", + "misc", + "mtd", + "rdma", + "sound", + "video", + "xen", + ]) + +# Type names +_TYPES = re.compile( + r'^(?:' + # [dcl.type.simple] + r'(char(16_t|32_t)?)|wchar_t|' + r'bool|short|int|long|signed|unsigned|float|double|' + # [support.types] + r'(ptrdiff_t|size_t|max_align_t|nullptr_t)|' + # [cstdint.syn] + r'(u?int(_fast|_least)?(8|16|32|64)_t)|' + r'(u?int(max|ptr)_t)|' + r')$') + + +# These headers are excluded from [build/include] and [build/include_order] +# checks: +# - Anything not following google file name conventions (containing an +# uppercase character, such as Python.h or nsStringAPI.h, for example). +# - Lua headers. +_THIRD_PARTY_HEADERS_PATTERN = re.compile( + r'^(?:[^/]*[A-Z][^/]*\.h|lua\.h|lauxlib\.h|lualib\.h)$') + +# Pattern for matching FileInfo.BaseName() against test file name +_test_suffixes = ['_test', '_regtest', '_unittest'] +_TEST_FILE_SUFFIX = '(' + '|'.join(_test_suffixes) + r')$' + +# Pattern that matches only complete whitespace, possibly across multiple lines. +_EMPTY_CONDITIONAL_BODY_PATTERN = re.compile(r'^\s*$', re.DOTALL) + +# Assertion macros. These are defined in base/logging.h and +# testing/base/public/gunit.h. +_CHECK_MACROS = [ + 'DCHECK', 'CHECK', + 'EXPECT_TRUE', 'ASSERT_TRUE', + 'EXPECT_FALSE', 'ASSERT_FALSE', + ] + +# Replacement macros for CHECK/DCHECK/EXPECT_TRUE/EXPECT_FALSE +_CHECK_REPLACEMENT = dict([(macro_var, {}) for macro_var in _CHECK_MACROS]) + +for op, replacement in [('==', 'EQ'), ('!=', 'NE'), + ('>=', 'GE'), ('>', 'GT'), + ('<=', 'LE'), ('<', 'LT')]: + _CHECK_REPLACEMENT['DCHECK'][op] = 'DCHECK_%s' % replacement + _CHECK_REPLACEMENT['CHECK'][op] = 'CHECK_%s' % replacement + _CHECK_REPLACEMENT['EXPECT_TRUE'][op] = 'EXPECT_%s' % replacement + _CHECK_REPLACEMENT['ASSERT_TRUE'][op] = 'ASSERT_%s' % replacement + +for op, inv_replacement in [('==', 'NE'), ('!=', 'EQ'), + ('>=', 'LT'), ('>', 'LE'), + ('<=', 'GT'), ('<', 'GE')]: + _CHECK_REPLACEMENT['EXPECT_FALSE'][op] = 'EXPECT_%s' % inv_replacement + _CHECK_REPLACEMENT['ASSERT_FALSE'][op] = 'ASSERT_%s' % inv_replacement + +# Alternative tokens and their replacements. For full list, see section 2.5 +# Alternative tokens [lex.digraph] in the C++ standard. +# +# Digraphs (such as '%:') are not included here since it's a mess to +# match those on a word boundary. +_ALT_TOKEN_REPLACEMENT = { + 'and': '&&', + 'bitor': '|', + 'or': '||', + 'xor': '^', + 'compl': '~', + 'bitand': '&', + 'and_eq': '&=', + 'or_eq': '|=', + 'xor_eq': '^=', + 'not': '!', + 'not_eq': '!=' + } + +# Compile regular expression that matches all the above keywords. The "[ =()]" +# bit is meant to avoid matching these keywords outside of boolean expressions. +# +# False positives include C-style multi-line comments and multi-line strings +# but those have always been troublesome for cpplint. +_ALT_TOKEN_REPLACEMENT_PATTERN = re.compile( + r'[ =()](' + ('|'.join(_ALT_TOKEN_REPLACEMENT.keys())) + r')(?=[ (]|$)') + + +# These constants define types of headers for use with +# _IncludeState.CheckNextIncludeOrder(). +_C_SYS_HEADER = 1 +_CPP_SYS_HEADER = 2 +_OTHER_SYS_HEADER = 3 +_LIKELY_MY_HEADER = 4 +_POSSIBLE_MY_HEADER = 5 +_OTHER_HEADER = 6 + +# These constants define the current inline assembly state +_NO_ASM = 0 # Outside of inline assembly block +_INSIDE_ASM = 1 # Inside inline assembly block +_END_ASM = 2 # Last line of inline assembly block +_BLOCK_ASM = 3 # The whole block is an inline assembly block + +# Match start of assembly blocks +_MATCH_ASM = re.compile(r'^\s*(?:asm|_asm|__asm|__asm__)' + r'(?:\s+(volatile|__volatile__))?' + r'\s*[{(]') + +# Match strings that indicate we're working on a C (not C++) file. +_SEARCH_C_FILE = re.compile(r'\b(?:LINT_C_FILE|' + r'vim?:\s*.*(\s*|:)filetype=c(\s*|:|$))') + +# Match string that indicates we're working on a Linux Kernel file. +_SEARCH_KERNEL_FILE = re.compile(r'\b(?:LINT_KERNEL_FILE)') + +# Commands for sed to fix the problem +_SED_FIXUPS = { + 'Remove spaces around =': r's/ = /=/', + 'Remove spaces around !=': r's/ != /!=/', + 'Remove space before ( in if (': r's/if (/if(/', + 'Remove space before ( in for (': r's/for (/for(/', + 'Remove space before ( in while (': r's/while (/while(/', + 'Remove space before ( in switch (': r's/switch (/switch(/', + 'Should have a space between // and comment': r's/\/\//\/\/ /', + 'Missing space before {': r's/\([^ ]\){/\1 {/', + 'Tab found, replace by spaces': r's/\t/ /g', + 'Line ends in whitespace. Consider deleting these extra spaces.': r's/\s*$//', + 'You don\'t need a ; after a }': r's/};/}/', + 'Missing space after ,': r's/,\([^ ]\)/, \1/g', +} + +_regexp_compile_cache = {} + +# {str, set(int)}: a map from error categories to sets of linenumbers +# on which those errors are expected and should be suppressed. +_error_suppressions = {} + +# The root directory used for deriving header guard CPP variable. +# This is set by --root flag. +_root = None +_root_debug = False + +# The top level repository directory. If set, _root is calculated relative to +# this directory instead of the directory containing version control artifacts. +# This is set by the --repository flag. +_repository = None + +# Files to exclude from linting. This is set by the --exclude flag. +_excludes = None + +# Whether to supress all PrintInfo messages, UNRELATED to --quiet flag +_quiet = False + +# The allowed line length of files. +# This is set by --linelength flag. +_line_length = 80 + +# This allows to use different include order rule than default +_include_order = "default" + +try: + unicode +except NameError: + # -- pylint: disable=redefined-builtin + basestring = unicode = str + +try: + long +except NameError: + # -- pylint: disable=redefined-builtin + long = int + +if sys.version_info < (3,): + # -- pylint: disable=no-member + # BINARY_TYPE = str + itervalues = dict.itervalues + iteritems = dict.iteritems +else: + # BINARY_TYPE = bytes + itervalues = dict.values + iteritems = dict.items + +def unicode_escape_decode(x): + if sys.version_info < (3,): + return codecs.unicode_escape_decode(x)[0] + else: + return x + +# Treat all headers starting with 'h' equally: .h, .hpp, .hxx etc. +# This is set by --headers flag. +_hpp_headers = set([]) + +# {str, bool}: a map from error categories to booleans which indicate if the +# category should be suppressed for every line. +_global_error_suppressions = {} + +def ProcessHppHeadersOption(val): + global _hpp_headers + try: + _hpp_headers = {ext.strip() for ext in val.split(',')} + except ValueError: + PrintUsage('Header extensions must be comma separated list.') + +def ProcessIncludeOrderOption(val): + if val is None or val == "default": + pass + elif val == "standardcfirst": + global _include_order + _include_order = val + else: + PrintUsage('Invalid includeorder value %s. Expected default|standardcfirst') + +def IsHeaderExtension(file_extension): + return file_extension in GetHeaderExtensions() + +def GetHeaderExtensions(): + if _hpp_headers: + return _hpp_headers + if _valid_extensions: + return {h for h in _valid_extensions if 'h' in h} + return set(['h', 'hh', 'hpp', 'hxx', 'h++', 'cuh']) + +# The allowed extensions for file names +# This is set by --extensions flag +def GetAllExtensions(): + return GetHeaderExtensions().union(_valid_extensions or set( + ['c', 'cc', 'cpp', 'cxx', 'c++', 'cu'])) + +def ProcessExtensionsOption(val): + global _valid_extensions + try: + extensions = [ext.strip() for ext in val.split(',')] + _valid_extensions = set(extensions) + except ValueError: + PrintUsage('Extensions should be a comma-separated list of values;' + 'for example: extensions=hpp,cpp\n' + 'This could not be parsed: "%s"' % (val,)) + +def GetNonHeaderExtensions(): + return GetAllExtensions().difference(GetHeaderExtensions()) + +def ParseNolintSuppressions(filename, raw_line, linenum, error): + """Updates the global list of line error-suppressions. + + Parses any NOLINT comments on the current line, updating the global + error_suppressions store. Reports an error if the NOLINT comment + was malformed. + + Args: + filename: str, the name of the input file. + raw_line: str, the line of input text, with comments. + linenum: int, the number of the current line. + error: function, an error handler. + """ + matched = Search(r'\bNOLINT(NEXTLINE)?\b(\([^)]+\))?', raw_line) + if matched: + if matched.group(1): + suppressed_line = linenum + 1 + else: + suppressed_line = linenum + category = matched.group(2) + if category in (None, '(*)'): # => "suppress all" + _error_suppressions.setdefault(None, set()).add(suppressed_line) + else: + if category.startswith('(') and category.endswith(')'): + category = category[1:-1] + if category in _ERROR_CATEGORIES: + _error_suppressions.setdefault(category, set()).add(suppressed_line) + elif category not in _LEGACY_ERROR_CATEGORIES: + error(filename, linenum, 'readability/nolint', 5, + 'Unknown NOLINT error category: %s' % category) + + +def ProcessGlobalSuppresions(lines): + """Updates the list of global error suppressions. + + Parses any lint directives in the file that have global effect. + + Args: + lines: An array of strings, each representing a line of the file, with the + last element being empty if the file is terminated with a newline. + """ + for line in lines: + if _SEARCH_C_FILE.search(line): + for category in _DEFAULT_C_SUPPRESSED_CATEGORIES: + _global_error_suppressions[category] = True + if _SEARCH_KERNEL_FILE.search(line): + for category in _DEFAULT_KERNEL_SUPPRESSED_CATEGORIES: + _global_error_suppressions[category] = True + + +def ResetNolintSuppressions(): + """Resets the set of NOLINT suppressions to empty.""" + _error_suppressions.clear() + _global_error_suppressions.clear() + + +def IsErrorSuppressedByNolint(category, linenum): + """Returns true if the specified error category is suppressed on this line. + + Consults the global error_suppressions map populated by + ParseNolintSuppressions/ProcessGlobalSuppresions/ResetNolintSuppressions. + + Args: + category: str, the category of the error. + linenum: int, the current line number. + Returns: + bool, True iff the error should be suppressed due to a NOLINT comment or + global suppression. + """ + return (_global_error_suppressions.get(category, False) or + linenum in _error_suppressions.get(category, set()) or + linenum in _error_suppressions.get(None, set())) + + +def Match(pattern, s): + """Matches the string with the pattern, caching the compiled regexp.""" + # The regexp compilation caching is inlined in both Match and Search for + # performance reasons; factoring it out into a separate function turns out + # to be noticeably expensive. + if pattern not in _regexp_compile_cache: + _regexp_compile_cache[pattern] = sre_compile.compile(pattern) + return _regexp_compile_cache[pattern].match(s) + + +def ReplaceAll(pattern, rep, s): + """Replaces instances of pattern in a string with a replacement. + + The compiled regex is kept in a cache shared by Match and Search. + + Args: + pattern: regex pattern + rep: replacement text + s: search string + + Returns: + string with replacements made (or original string if no replacements) + """ + if pattern not in _regexp_compile_cache: + _regexp_compile_cache[pattern] = sre_compile.compile(pattern) + return _regexp_compile_cache[pattern].sub(rep, s) + + +def Search(pattern, s): + """Searches the string for the pattern, caching the compiled regexp.""" + if pattern not in _regexp_compile_cache: + _regexp_compile_cache[pattern] = sre_compile.compile(pattern) + return _regexp_compile_cache[pattern].search(s) + + +def _IsSourceExtension(s): + """File extension (excluding dot) matches a source file extension.""" + return s in GetNonHeaderExtensions() + + +class _IncludeState(object): + """Tracks line numbers for includes, and the order in which includes appear. + + include_list contains list of lists of (header, line number) pairs. + It's a lists of lists rather than just one flat list to make it + easier to update across preprocessor boundaries. + + Call CheckNextIncludeOrder() once for each header in the file, passing + in the type constants defined above. Calls in an illegal order will + raise an _IncludeError with an appropriate error message. + + """ + # self._section will move monotonically through this set. If it ever + # needs to move backwards, CheckNextIncludeOrder will raise an error. + _INITIAL_SECTION = 0 + _MY_H_SECTION = 1 + _C_SECTION = 2 + _CPP_SECTION = 3 + _OTHER_SYS_SECTION = 4 + _OTHER_H_SECTION = 5 + + _TYPE_NAMES = { + _C_SYS_HEADER: 'C system header', + _CPP_SYS_HEADER: 'C++ system header', + _OTHER_SYS_HEADER: 'other system header', + _LIKELY_MY_HEADER: 'header this file implements', + _POSSIBLE_MY_HEADER: 'header this file may implement', + _OTHER_HEADER: 'other header', + } + _SECTION_NAMES = { + _INITIAL_SECTION: "... nothing. (This can't be an error.)", + _MY_H_SECTION: 'a header this file implements', + _C_SECTION: 'C system header', + _CPP_SECTION: 'C++ system header', + _OTHER_SYS_SECTION: 'other system header', + _OTHER_H_SECTION: 'other header', + } + + def __init__(self): + self.include_list = [[]] + self._section = None + self._last_header = None + self.ResetSection('') + + def FindHeader(self, header): + """Check if a header has already been included. + + Args: + header: header to check. + Returns: + Line number of previous occurrence, or -1 if the header has not + been seen before. + """ + for section_list in self.include_list: + for f in section_list: + if f[0] == header: + return f[1] + return -1 + + def ResetSection(self, directive): + """Reset section checking for preprocessor directive. + + Args: + directive: preprocessor directive (e.g. "if", "else"). + """ + # The name of the current section. + self._section = self._INITIAL_SECTION + # The path of last found header. + self._last_header = '' + + # Update list of includes. Note that we never pop from the + # include list. + if directive in ('if', 'ifdef', 'ifndef'): + self.include_list.append([]) + elif directive in ('else', 'elif'): + self.include_list[-1] = [] + + def SetLastHeader(self, header_path): + self._last_header = header_path + + def CanonicalizeAlphabeticalOrder(self, header_path): + """Returns a path canonicalized for alphabetical comparison. + + - replaces "-" with "_" so they both cmp the same. + - removes '-inl' since we don't require them to be after the main header. + - lowercase everything, just in case. + + Args: + header_path: Path to be canonicalized. + + Returns: + Canonicalized path. + """ + return header_path.replace('-inl.h', '.h').replace('-', '_').lower() + + def IsInAlphabeticalOrder(self, clean_lines, linenum, header_path): + """Check if a header is in alphabetical order with the previous header. + + Args: + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + header_path: Canonicalized header to be checked. + + Returns: + Returns true if the header is in alphabetical order. + """ + # If previous section is different from current section, _last_header will + # be reset to empty string, so it's always less than current header. + # + # If previous line was a blank line, assume that the headers are + # intentionally sorted the way they are. + if (self._last_header > header_path and + Match(r'^\s*#\s*include\b', clean_lines.elided[linenum - 1])): + return False + return True + + def CheckNextIncludeOrder(self, header_type): + """Returns a non-empty error message if the next header is out of order. + + This function also updates the internal state to be ready to check + the next include. + + Args: + header_type: One of the _XXX_HEADER constants defined above. + + Returns: + The empty string if the header is in the right order, or an + error message describing what's wrong. + + """ + error_message = ('Found %s after %s' % + (self._TYPE_NAMES[header_type], + self._SECTION_NAMES[self._section])) + + last_section = self._section + + if header_type == _C_SYS_HEADER: + if self._section <= self._C_SECTION: + self._section = self._C_SECTION + else: + self._last_header = '' + return error_message + elif header_type == _CPP_SYS_HEADER: + if self._section <= self._CPP_SECTION: + self._section = self._CPP_SECTION + else: + self._last_header = '' + return error_message + elif header_type == _OTHER_SYS_HEADER: + if self._section <= self._OTHER_SYS_SECTION: + self._section = self._OTHER_SYS_SECTION + else: + self._last_header = '' + return error_message + elif header_type == _LIKELY_MY_HEADER: + if self._section <= self._MY_H_SECTION: + self._section = self._MY_H_SECTION + else: + self._section = self._OTHER_H_SECTION + elif header_type == _POSSIBLE_MY_HEADER: + if self._section <= self._MY_H_SECTION: + self._section = self._MY_H_SECTION + else: + # This will always be the fallback because we're not sure + # enough that the header is associated with this file. + self._section = self._OTHER_H_SECTION + else: + assert header_type == _OTHER_HEADER + self._section = self._OTHER_H_SECTION + + if last_section != self._section: + self._last_header = '' + + return '' + + +class _CppLintState(object): + """Maintains module-wide state..""" + + def __init__(self): + self.verbose_level = 1 # global setting. + self.error_count = 0 # global count of reported errors + # filters to apply when emitting error messages + self.filters = _DEFAULT_FILTERS[:] + # backup of filter list. Used to restore the state after each file. + self._filters_backup = self.filters[:] + self.counting = 'total' # In what way are we counting errors? + self.errors_by_category = {} # string to int dict storing error counts + self.quiet = False # Suppress non-error messagess? + + # output format: + # "emacs" - format that emacs can parse (default) + # "eclipse" - format that eclipse can parse + # "vs7" - format that Microsoft Visual Studio 7 can parse + # "junit" - format that Jenkins, Bamboo, etc can parse + # "sed" - returns a gnu sed command to fix the problem + # "gsed" - like sed, but names the command gsed, e.g. for macOS homebrew users + self.output_format = 'emacs' + + # For JUnit output, save errors and failures until the end so that they + # can be written into the XML + self._junit_errors = [] + self._junit_failures = [] + + def SetOutputFormat(self, output_format): + """Sets the output format for errors.""" + self.output_format = output_format + + def SetQuiet(self, quiet): + """Sets the module's quiet settings, and returns the previous setting.""" + last_quiet = self.quiet + self.quiet = quiet + return last_quiet + + def SetVerboseLevel(self, level): + """Sets the module's verbosity, and returns the previous setting.""" + last_verbose_level = self.verbose_level + self.verbose_level = level + return last_verbose_level + + def SetCountingStyle(self, counting_style): + """Sets the module's counting options.""" + self.counting = counting_style + + def SetFilters(self, filters): + """Sets the error-message filters. + + These filters are applied when deciding whether to emit a given + error message. + + Args: + filters: A string of comma-separated filters (eg "+whitespace/indent"). + Each filter should start with + or -; else we die. + + Raises: + ValueError: The comma-separated filters did not all start with '+' or '-'. + E.g. "-,+whitespace,-whitespace/indent,whitespace/badfilter" + """ + # Default filters always have less priority than the flag ones. + self.filters = _DEFAULT_FILTERS[:] + self.AddFilters(filters) + + def AddFilters(self, filters): + """ Adds more filters to the existing list of error-message filters. """ + for filt in filters.split(','): + clean_filt = filt.strip() + if clean_filt: + self.filters.append(clean_filt) + for filt in self.filters: + if not (filt.startswith('+') or filt.startswith('-')): + raise ValueError('Every filter in --filters must start with + or -' + ' (%s does not)' % filt) + + def BackupFilters(self): + """ Saves the current filter list to backup storage.""" + self._filters_backup = self.filters[:] + + def RestoreFilters(self): + """ Restores filters previously backed up.""" + self.filters = self._filters_backup[:] + + def ResetErrorCounts(self): + """Sets the module's error statistic back to zero.""" + self.error_count = 0 + self.errors_by_category = {} + + def IncrementErrorCount(self, category): + """Bumps the module's error statistic.""" + self.error_count += 1 + if self.counting in ('toplevel', 'detailed'): + if self.counting != 'detailed': + category = category.split('/')[0] + if category not in self.errors_by_category: + self.errors_by_category[category] = 0 + self.errors_by_category[category] += 1 + + def PrintErrorCounts(self): + """Print a summary of errors by category, and the total.""" + for category, count in sorted(iteritems(self.errors_by_category)): + self.PrintInfo('Category \'%s\' errors found: %d\n' % + (category, count)) + if self.error_count > 0: + self.PrintInfo('Total errors found: %d\n' % self.error_count) + + def PrintInfo(self, message): + # _quiet does not represent --quiet flag. + # Hide infos from stdout to keep stdout pure for machine consumption + if not _quiet and self.output_format not in _MACHINE_OUTPUTS: + sys.stdout.write(message) + + def PrintError(self, message): + if self.output_format == 'junit': + self._junit_errors.append(message) + else: + sys.stderr.write(message) + + def AddJUnitFailure(self, filename, linenum, message, category, confidence): + self._junit_failures.append((filename, linenum, message, category, + confidence)) + + def FormatJUnitXML(self): + num_errors = len(self._junit_errors) + num_failures = len(self._junit_failures) + + testsuite = xml.etree.ElementTree.Element('testsuite') + testsuite.attrib['errors'] = str(num_errors) + testsuite.attrib['failures'] = str(num_failures) + testsuite.attrib['name'] = 'cpplint' + + if num_errors == 0 and num_failures == 0: + testsuite.attrib['tests'] = str(1) + xml.etree.ElementTree.SubElement(testsuite, 'testcase', name='passed') + + else: + testsuite.attrib['tests'] = str(num_errors + num_failures) + if num_errors > 0: + testcase = xml.etree.ElementTree.SubElement(testsuite, 'testcase') + testcase.attrib['name'] = 'errors' + error = xml.etree.ElementTree.SubElement(testcase, 'error') + error.text = '\n'.join(self._junit_errors) + if num_failures > 0: + # Group failures by file + failed_file_order = [] + failures_by_file = {} + for failure in self._junit_failures: + failed_file = failure[0] + if failed_file not in failed_file_order: + failed_file_order.append(failed_file) + failures_by_file[failed_file] = [] + failures_by_file[failed_file].append(failure) + # Create a testcase for each file + for failed_file in failed_file_order: + failures = failures_by_file[failed_file] + testcase = xml.etree.ElementTree.SubElement(testsuite, 'testcase') + testcase.attrib['name'] = failed_file + failure = xml.etree.ElementTree.SubElement(testcase, 'failure') + template = '{0}: {1} [{2}] [{3}]' + texts = [template.format(f[1], f[2], f[3], f[4]) for f in failures] + failure.text = '\n'.join(texts) + + xml_decl = '\n' + return xml_decl + xml.etree.ElementTree.tostring(testsuite, 'utf-8').decode('utf-8') + + +_cpplint_state = _CppLintState() + + +def _OutputFormat(): + """Gets the module's output format.""" + return _cpplint_state.output_format + + +def _SetOutputFormat(output_format): + """Sets the module's output format.""" + _cpplint_state.SetOutputFormat(output_format) + +def _Quiet(): + """Return's the module's quiet setting.""" + return _cpplint_state.quiet + +def _SetQuiet(quiet): + """Set the module's quiet status, and return previous setting.""" + return _cpplint_state.SetQuiet(quiet) + + +def _VerboseLevel(): + """Returns the module's verbosity setting.""" + return _cpplint_state.verbose_level + + +def _SetVerboseLevel(level): + """Sets the module's verbosity, and returns the previous setting.""" + return _cpplint_state.SetVerboseLevel(level) + + +def _SetCountingStyle(level): + """Sets the module's counting options.""" + _cpplint_state.SetCountingStyle(level) + + +def _Filters(): + """Returns the module's list of output filters, as a list.""" + return _cpplint_state.filters + + +def _SetFilters(filters): + """Sets the module's error-message filters. + + These filters are applied when deciding whether to emit a given + error message. + + Args: + filters: A string of comma-separated filters (eg "whitespace/indent"). + Each filter should start with + or -; else we die. + """ + _cpplint_state.SetFilters(filters) + +def _AddFilters(filters): + """Adds more filter overrides. + + Unlike _SetFilters, this function does not reset the current list of filters + available. + + Args: + filters: A string of comma-separated filters (eg "whitespace/indent"). + Each filter should start with + or -; else we die. + """ + _cpplint_state.AddFilters(filters) + +def _BackupFilters(): + """ Saves the current filter list to backup storage.""" + _cpplint_state.BackupFilters() + +def _RestoreFilters(): + """ Restores filters previously backed up.""" + _cpplint_state.RestoreFilters() + +class _FunctionState(object): + """Tracks current function name and the number of lines in its body.""" + + _NORMAL_TRIGGER = 250 # for --v=0, 500 for --v=1, etc. + _TEST_TRIGGER = 400 # about 50% more than _NORMAL_TRIGGER. + + def __init__(self): + self.in_a_function = False + self.lines_in_function = 0 + self.current_function = '' + + def Begin(self, function_name): + """Start analyzing function body. + + Args: + function_name: The name of the function being tracked. + """ + self.in_a_function = True + self.lines_in_function = 0 + self.current_function = function_name + + def Count(self): + """Count line in current function body.""" + if self.in_a_function: + self.lines_in_function += 1 + + def Check(self, error, filename, linenum): + """Report if too many lines in function body. + + Args: + error: The function to call with any errors found. + filename: The name of the current file. + linenum: The number of the line to check. + """ + if not self.in_a_function: + return + + if Match(r'T(EST|est)', self.current_function): + base_trigger = self._TEST_TRIGGER + else: + base_trigger = self._NORMAL_TRIGGER + trigger = base_trigger * 2**_VerboseLevel() + + if self.lines_in_function > trigger: + error_level = int(math.log(self.lines_in_function / base_trigger, 2)) + # 50 => 0, 100 => 1, 200 => 2, 400 => 3, 800 => 4, 1600 => 5, ... + if error_level > 5: + error_level = 5 + error(filename, linenum, 'readability/fn_size', error_level, + 'Small and focused functions are preferred:' + ' %s has %d non-comment lines' + ' (error triggered by exceeding %d lines).' % ( + self.current_function, self.lines_in_function, trigger)) + + def End(self): + """Stop analyzing function body.""" + self.in_a_function = False + + +class _IncludeError(Exception): + """Indicates a problem with the include order in a file.""" + pass + + +class FileInfo(object): + """Provides utility functions for filenames. + + FileInfo provides easy access to the components of a file's path + relative to the project root. + """ + + def __init__(self, filename): + self._filename = filename + + def FullName(self): + """Make Windows paths like Unix.""" + return os.path.abspath(self._filename).replace('\\', '/') + + def RepositoryName(self): + r"""FullName after removing the local path to the repository. + + If we have a real absolute path name here we can try to do something smart: + detecting the root of the checkout and truncating /path/to/checkout from + the name so that we get header guards that don't include things like + "C:\\Documents and Settings\\..." or "/home/username/..." in them and thus + people on different computers who have checked the source out to different + locations won't see bogus errors. + """ + fullname = self.FullName() + + if os.path.exists(fullname): + project_dir = os.path.dirname(fullname) + + # If the user specified a repository path, it exists, and the file is + # contained in it, use the specified repository path + if _repository: + repo = FileInfo(_repository).FullName() + root_dir = project_dir + while os.path.exists(root_dir): + # allow case insensitive compare on Windows + if os.path.normcase(root_dir) == os.path.normcase(repo): + return os.path.relpath(fullname, root_dir).replace('\\', '/') + one_up_dir = os.path.dirname(root_dir) + if one_up_dir == root_dir: + break + root_dir = one_up_dir + + if os.path.exists(os.path.join(project_dir, ".svn")): + # If there's a .svn file in the current directory, we recursively look + # up the directory tree for the top of the SVN checkout + root_dir = project_dir + one_up_dir = os.path.dirname(root_dir) + while os.path.exists(os.path.join(one_up_dir, ".svn")): + root_dir = os.path.dirname(root_dir) + one_up_dir = os.path.dirname(one_up_dir) + + prefix = os.path.commonprefix([root_dir, project_dir]) + return fullname[len(prefix) + 1:] + + # Not SVN <= 1.6? Try to find a git, hg, or svn top level directory by + # searching up from the current path. + root_dir = current_dir = os.path.dirname(fullname) + while current_dir != os.path.dirname(current_dir): + if (os.path.exists(os.path.join(current_dir, ".git")) or + os.path.exists(os.path.join(current_dir, ".hg")) or + os.path.exists(os.path.join(current_dir, ".svn"))): + root_dir = current_dir + current_dir = os.path.dirname(current_dir) + + if (os.path.exists(os.path.join(root_dir, ".git")) or + os.path.exists(os.path.join(root_dir, ".hg")) or + os.path.exists(os.path.join(root_dir, ".svn"))): + prefix = os.path.commonprefix([root_dir, project_dir]) + return fullname[len(prefix) + 1:] + + # Don't know what to do; header guard warnings may be wrong... + return fullname + + def Split(self): + """Splits the file into the directory, basename, and extension. + + For 'chrome/browser/browser.cc', Split() would + return ('chrome/browser', 'browser', '.cc') + + Returns: + A tuple of (directory, basename, extension). + """ + + googlename = self.RepositoryName() + project, rest = os.path.split(googlename) + return (project,) + os.path.splitext(rest) + + def BaseName(self): + """File base name - text after the final slash, before the final period.""" + return self.Split()[1] + + def Extension(self): + """File extension - text following the final period, includes that period.""" + return self.Split()[2] + + def NoExtension(self): + """File has no source file extension.""" + return '/'.join(self.Split()[0:2]) + + def IsSource(self): + """File has a source file extension.""" + return _IsSourceExtension(self.Extension()[1:]) + + +def _ShouldPrintError(category, confidence, linenum): + """If confidence >= verbose, category passes filter and is not suppressed.""" + + # There are three ways we might decide not to print an error message: + # a "NOLINT(category)" comment appears in the source, + # the verbosity level isn't high enough, or the filters filter it out. + if IsErrorSuppressedByNolint(category, linenum): + return False + + if confidence < _cpplint_state.verbose_level: + return False + + is_filtered = False + for one_filter in _Filters(): + if one_filter.startswith('-'): + if category.startswith(one_filter[1:]): + is_filtered = True + elif one_filter.startswith('+'): + if category.startswith(one_filter[1:]): + is_filtered = False + else: + assert False # should have been checked for in SetFilter. + if is_filtered: + return False + + return True + + +def Error(filename, linenum, category, confidence, message): + """Logs the fact we've found a lint error. + + We log where the error was found, and also our confidence in the error, + that is, how certain we are this is a legitimate style regression, and + not a misidentification or a use that's sometimes justified. + + False positives can be suppressed by the use of + "cpplint(category)" comments on the offending line. These are + parsed into _error_suppressions. + + Args: + filename: The name of the file containing the error. + linenum: The number of the line containing the error. + category: A string used to describe the "category" this bug + falls under: "whitespace", say, or "runtime". Categories + may have a hierarchy separated by slashes: "whitespace/indent". + confidence: A number from 1-5 representing a confidence score for + the error, with 5 meaning that we are certain of the problem, + and 1 meaning that it could be a legitimate construct. + message: The error message. + """ + if _ShouldPrintError(category, confidence, linenum): + _cpplint_state.IncrementErrorCount(category) + if _cpplint_state.output_format == 'vs7': + _cpplint_state.PrintError('%s(%s): error cpplint: [%s] %s [%d]\n' % ( + filename, linenum, category, message, confidence)) + elif _cpplint_state.output_format == 'eclipse': + sys.stderr.write('%s:%s: warning: %s [%s] [%d]\n' % ( + filename, linenum, message, category, confidence)) + elif _cpplint_state.output_format == 'junit': + _cpplint_state.AddJUnitFailure(filename, linenum, message, category, + confidence) + elif _cpplint_state.output_format in ['sed', 'gsed']: + if message in _SED_FIXUPS: + sys.stdout.write(_cpplint_state.output_format + " -i '%s%s' %s # %s [%s] [%d]\n" % ( + linenum, _SED_FIXUPS[message], filename, message, category, confidence)) + else: + sys.stderr.write('# %s:%s: "%s" [%s] [%d]\n' % ( + filename, linenum, message, category, confidence)) + else: + final_message = '%s:%s: %s [%s] [%d]\n' % ( + filename, linenum, message, category, confidence) + sys.stderr.write(final_message) + +# Matches standard C++ escape sequences per 2.13.2.3 of the C++ standard. +_RE_PATTERN_CLEANSE_LINE_ESCAPES = re.compile( + r'\\([abfnrtv?"\\\']|\d+|x[0-9a-fA-F]+)') +# Match a single C style comment on the same line. +_RE_PATTERN_C_COMMENTS = r'/\*(?:[^*]|\*(?!/))*\*/' +# Matches multi-line C style comments. +# This RE is a little bit more complicated than one might expect, because we +# have to take care of space removals tools so we can handle comments inside +# statements better. +# The current rule is: We only clear spaces from both sides when we're at the +# end of the line. Otherwise, we try to remove spaces from the right side, +# if this doesn't work we try on left side but only if there's a non-character +# on the right. +_RE_PATTERN_CLEANSE_LINE_C_COMMENTS = re.compile( + r'(\s*' + _RE_PATTERN_C_COMMENTS + r'\s*$|' + + _RE_PATTERN_C_COMMENTS + r'\s+|' + + r'\s+' + _RE_PATTERN_C_COMMENTS + r'(?=\W)|' + + _RE_PATTERN_C_COMMENTS + r')') + + +def IsCppString(line): + """Does line terminate so, that the next symbol is in string constant. + + This function does not consider single-line nor multi-line comments. + + Args: + line: is a partial line of code starting from the 0..n. + + Returns: + True, if next character appended to 'line' is inside a + string constant. + """ + + line = line.replace(r'\\', 'XX') # after this, \\" does not match to \" + return ((line.count('"') - line.count(r'\"') - line.count("'\"'")) & 1) == 1 + + +def CleanseRawStrings(raw_lines): + """Removes C++11 raw strings from lines. + + Before: + static const char kData[] = R"( + multi-line string + )"; + + After: + static const char kData[] = "" + (replaced by blank line) + ""; + + Args: + raw_lines: list of raw lines. + + Returns: + list of lines with C++11 raw strings replaced by empty strings. + """ + + delimiter = None + lines_without_raw_strings = [] + for line in raw_lines: + if delimiter: + # Inside a raw string, look for the end + end = line.find(delimiter) + if end >= 0: + # Found the end of the string, match leading space for this + # line and resume copying the original lines, and also insert + # a "" on the last line. + leading_space = Match(r'^(\s*)\S', line) + line = leading_space.group(1) + '""' + line[end + len(delimiter):] + delimiter = None + else: + # Haven't found the end yet, append a blank line. + line = '""' + + # Look for beginning of a raw string, and replace them with + # empty strings. This is done in a loop to handle multiple raw + # strings on the same line. + while delimiter is None: + # Look for beginning of a raw string. + # See 2.14.15 [lex.string] for syntax. + # + # Once we have matched a raw string, we check the prefix of the + # line to make sure that the line is not part of a single line + # comment. It's done this way because we remove raw strings + # before removing comments as opposed to removing comments + # before removing raw strings. This is because there are some + # cpplint checks that requires the comments to be preserved, but + # we don't want to check comments that are inside raw strings. + matched = Match(r'^(.*?)\b(?:R|u8R|uR|UR|LR)"([^\s\\()]*)\((.*)$', line) + if (matched and + not Match(r'^([^\'"]|\'(\\.|[^\'])*\'|"(\\.|[^"])*")*//', + matched.group(1))): + delimiter = ')' + matched.group(2) + '"' + + end = matched.group(3).find(delimiter) + if end >= 0: + # Raw string ended on same line + line = (matched.group(1) + '""' + + matched.group(3)[end + len(delimiter):]) + delimiter = None + else: + # Start of a multi-line raw string + line = matched.group(1) + '""' + else: + break + + lines_without_raw_strings.append(line) + + # TODO(unknown): if delimiter is not None here, we might want to + # emit a warning for unterminated string. + return lines_without_raw_strings + + +def FindNextMultiLineCommentStart(lines, lineix): + """Find the beginning marker for a multiline comment.""" + while lineix < len(lines): + if lines[lineix].strip().startswith('/*'): + # Only return this marker if the comment goes beyond this line + if lines[lineix].strip().find('*/', 2) < 0: + return lineix + lineix += 1 + return len(lines) + + +def FindNextMultiLineCommentEnd(lines, lineix): + """We are inside a comment, find the end marker.""" + while lineix < len(lines): + if lines[lineix].strip().endswith('*/'): + return lineix + lineix += 1 + return len(lines) + + +def RemoveMultiLineCommentsFromRange(lines, begin, end): + """Clears a range of lines for multi-line comments.""" + # Having // comments makes the lines non-empty, so we will not get + # unnecessary blank line warnings later in the code. + for i in range(begin, end): + lines[i] = '/**/' + + +def RemoveMultiLineComments(filename, lines, error): + """Removes multiline (c-style) comments from lines.""" + lineix = 0 + while lineix < len(lines): + lineix_begin = FindNextMultiLineCommentStart(lines, lineix) + if lineix_begin >= len(lines): + return + lineix_end = FindNextMultiLineCommentEnd(lines, lineix_begin) + if lineix_end >= len(lines): + error(filename, lineix_begin + 1, 'readability/multiline_comment', 5, + 'Could not find end of multi-line comment') + return + RemoveMultiLineCommentsFromRange(lines, lineix_begin, lineix_end + 1) + lineix = lineix_end + 1 + + +def CleanseComments(line): + """Removes //-comments and single-line C-style /* */ comments. + + Args: + line: A line of C++ source. + + Returns: + The line with single-line comments removed. + """ + commentpos = line.find('//') + if commentpos != -1 and not IsCppString(line[:commentpos]): + line = line[:commentpos].rstrip() + # get rid of /* ... */ + return _RE_PATTERN_CLEANSE_LINE_C_COMMENTS.sub('', line) + + +class CleansedLines(object): + """Holds 4 copies of all lines with different preprocessing applied to them. + + 1) elided member contains lines without strings and comments. + 2) lines member contains lines without comments. + 3) raw_lines member contains all the lines without processing. + 4) lines_without_raw_strings member is same as raw_lines, but with C++11 raw + strings removed. + All these members are of , and of the same length. + """ + + def __init__(self, lines): + self.elided = [] + self.lines = [] + self.raw_lines = lines + self.num_lines = len(lines) + self.lines_without_raw_strings = CleanseRawStrings(lines) + for linenum in range(len(self.lines_without_raw_strings)): + self.lines.append(CleanseComments( + self.lines_without_raw_strings[linenum])) + elided = self._CollapseStrings(self.lines_without_raw_strings[linenum]) + self.elided.append(CleanseComments(elided)) + + def NumLines(self): + """Returns the number of lines represented.""" + return self.num_lines + + @staticmethod + def _CollapseStrings(elided): + """Collapses strings and chars on a line to simple "" or '' blocks. + + We nix strings first so we're not fooled by text like '"http://"' + + Args: + elided: The line being processed. + + Returns: + The line with collapsed strings. + """ + if _RE_PATTERN_INCLUDE.match(elided): + return elided + + # Remove escaped characters first to make quote/single quote collapsing + # basic. Things that look like escaped characters shouldn't occur + # outside of strings and chars. + elided = _RE_PATTERN_CLEANSE_LINE_ESCAPES.sub('', elided) + + # Replace quoted strings and digit separators. Both single quotes + # and double quotes are processed in the same loop, otherwise + # nested quotes wouldn't work. + collapsed = '' + while True: + # Find the first quote character + match = Match(r'^([^\'"]*)([\'"])(.*)$', elided) + if not match: + collapsed += elided + break + head, quote, tail = match.groups() + + if quote == '"': + # Collapse double quoted strings + second_quote = tail.find('"') + if second_quote >= 0: + collapsed += head + '""' + elided = tail[second_quote + 1:] + else: + # Unmatched double quote, don't bother processing the rest + # of the line since this is probably a multiline string. + collapsed += elided + break + else: + # Found single quote, check nearby text to eliminate digit separators. + # + # There is no special handling for floating point here, because + # the integer/fractional/exponent parts would all be parsed + # correctly as long as there are digits on both sides of the + # separator. So we are fine as long as we don't see something + # like "0.'3" (gcc 4.9.0 will not allow this literal). + if Search(r'\b(?:0[bBxX]?|[1-9])[0-9a-fA-F]*$', head): + match_literal = Match(r'^((?:\'?[0-9a-zA-Z_])*)(.*)$', "'" + tail) + collapsed += head + match_literal.group(1).replace("'", '') + elided = match_literal.group(2) + else: + second_quote = tail.find('\'') + if second_quote >= 0: + collapsed += head + "''" + elided = tail[second_quote + 1:] + else: + # Unmatched single quote + collapsed += elided + break + + return collapsed + + +def FindEndOfExpressionInLine(line, startpos, stack): + """Find the position just after the end of current parenthesized expression. + + Args: + line: a CleansedLines line. + startpos: start searching at this position. + stack: nesting stack at startpos. + + Returns: + On finding matching end: (index just after matching end, None) + On finding an unclosed expression: (-1, None) + Otherwise: (-1, new stack at end of this line) + """ + for i in xrange(startpos, len(line)): + char = line[i] + if char in '([{': + # Found start of parenthesized expression, push to expression stack + stack.append(char) + elif char == '<': + # Found potential start of template argument list + if i > 0 and line[i - 1] == '<': + # Left shift operator + if stack and stack[-1] == '<': + stack.pop() + if not stack: + return (-1, None) + elif i > 0 and Search(r'\boperator\s*$', line[0:i]): + # operator<, don't add to stack + continue + else: + # Tentative start of template argument list + stack.append('<') + elif char in ')]}': + # Found end of parenthesized expression. + # + # If we are currently expecting a matching '>', the pending '<' + # must have been an operator. Remove them from expression stack. + while stack and stack[-1] == '<': + stack.pop() + if not stack: + return (-1, None) + if ((stack[-1] == '(' and char == ')') or + (stack[-1] == '[' and char == ']') or + (stack[-1] == '{' and char == '}')): + stack.pop() + if not stack: + return (i + 1, None) + else: + # Mismatched parentheses + return (-1, None) + elif char == '>': + # Found potential end of template argument list. + + # Ignore "->" and operator functions + if (i > 0 and + (line[i - 1] == '-' or Search(r'\boperator\s*$', line[0:i - 1]))): + continue + + # Pop the stack if there is a matching '<'. Otherwise, ignore + # this '>' since it must be an operator. + if stack: + if stack[-1] == '<': + stack.pop() + if not stack: + return (i + 1, None) + elif char == ';': + # Found something that look like end of statements. If we are currently + # expecting a '>', the matching '<' must have been an operator, since + # template argument list should not contain statements. + while stack and stack[-1] == '<': + stack.pop() + if not stack: + return (-1, None) + + # Did not find end of expression or unbalanced parentheses on this line + return (-1, stack) + + +def CloseExpression(clean_lines, linenum, pos): + """If input points to ( or { or [ or <, finds the position that closes it. + + If lines[linenum][pos] points to a '(' or '{' or '[' or '<', finds the + linenum/pos that correspond to the closing of the expression. + + TODO(unknown): cpplint spends a fair bit of time matching parentheses. + Ideally we would want to index all opening and closing parentheses once + and have CloseExpression be just a simple lookup, but due to preprocessor + tricks, this is not so easy. + + Args: + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + pos: A position on the line. + + Returns: + A tuple (line, linenum, pos) pointer *past* the closing brace, or + (line, len(lines), -1) if we never find a close. Note we ignore + strings and comments when matching; and the line we return is the + 'cleansed' line at linenum. + """ + + line = clean_lines.elided[linenum] + if (line[pos] not in '({[<') or Match(r'<[<=]', line[pos:]): + return (line, clean_lines.NumLines(), -1) + + # Check first line + (end_pos, stack) = FindEndOfExpressionInLine(line, pos, []) + if end_pos > -1: + return (line, linenum, end_pos) + + # Continue scanning forward + while stack and linenum < clean_lines.NumLines() - 1: + linenum += 1 + line = clean_lines.elided[linenum] + (end_pos, stack) = FindEndOfExpressionInLine(line, 0, stack) + if end_pos > -1: + return (line, linenum, end_pos) + + # Did not find end of expression before end of file, give up + return (line, clean_lines.NumLines(), -1) + + +def FindStartOfExpressionInLine(line, endpos, stack): + """Find position at the matching start of current expression. + + This is almost the reverse of FindEndOfExpressionInLine, but note + that the input position and returned position differs by 1. + + Args: + line: a CleansedLines line. + endpos: start searching at this position. + stack: nesting stack at endpos. + + Returns: + On finding matching start: (index at matching start, None) + On finding an unclosed expression: (-1, None) + Otherwise: (-1, new stack at beginning of this line) + """ + i = endpos + while i >= 0: + char = line[i] + if char in ')]}': + # Found end of expression, push to expression stack + stack.append(char) + elif char == '>': + # Found potential end of template argument list. + # + # Ignore it if it's a "->" or ">=" or "operator>" + if (i > 0 and + (line[i - 1] == '-' or + Match(r'\s>=\s', line[i - 1:]) or + Search(r'\boperator\s*$', line[0:i]))): + i -= 1 + else: + stack.append('>') + elif char == '<': + # Found potential start of template argument list + if i > 0 and line[i - 1] == '<': + # Left shift operator + i -= 1 + else: + # If there is a matching '>', we can pop the expression stack. + # Otherwise, ignore this '<' since it must be an operator. + if stack and stack[-1] == '>': + stack.pop() + if not stack: + return (i, None) + elif char in '([{': + # Found start of expression. + # + # If there are any unmatched '>' on the stack, they must be + # operators. Remove those. + while stack and stack[-1] == '>': + stack.pop() + if not stack: + return (-1, None) + if ((char == '(' and stack[-1] == ')') or + (char == '[' and stack[-1] == ']') or + (char == '{' and stack[-1] == '}')): + stack.pop() + if not stack: + return (i, None) + else: + # Mismatched parentheses + return (-1, None) + elif char == ';': + # Found something that look like end of statements. If we are currently + # expecting a '<', the matching '>' must have been an operator, since + # template argument list should not contain statements. + while stack and stack[-1] == '>': + stack.pop() + if not stack: + return (-1, None) + + i -= 1 + + return (-1, stack) + + +def ReverseCloseExpression(clean_lines, linenum, pos): + """If input points to ) or } or ] or >, finds the position that opens it. + + If lines[linenum][pos] points to a ')' or '}' or ']' or '>', finds the + linenum/pos that correspond to the opening of the expression. + + Args: + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + pos: A position on the line. + + Returns: + A tuple (line, linenum, pos) pointer *at* the opening brace, or + (line, 0, -1) if we never find the matching opening brace. Note + we ignore strings and comments when matching; and the line we + return is the 'cleansed' line at linenum. + """ + line = clean_lines.elided[linenum] + if line[pos] not in ')}]>': + return (line, 0, -1) + + # Check last line + (start_pos, stack) = FindStartOfExpressionInLine(line, pos, []) + if start_pos > -1: + return (line, linenum, start_pos) + + # Continue scanning backward + while stack and linenum > 0: + linenum -= 1 + line = clean_lines.elided[linenum] + (start_pos, stack) = FindStartOfExpressionInLine(line, len(line) - 1, stack) + if start_pos > -1: + return (line, linenum, start_pos) + + # Did not find start of expression before beginning of file, give up + return (line, 0, -1) + + +def CheckForCopyright(filename, lines, error): + """Logs an error if no Copyright message appears at the top of the file.""" + + # We'll say it should occur by line 10. Don't forget there's a + # placeholder line at the front. + for line in xrange(1, min(len(lines), 11)): + if re.search(r'Copyright', lines[line], re.I): break + else: # means no copyright line was found + error(filename, 0, 'legal/copyright', 5, + 'No copyright message found. ' + 'You should have a line: "Copyright [year] "') + + +def GetIndentLevel(line): + """Return the number of leading spaces in line. + + Args: + line: A string to check. + + Returns: + An integer count of leading spaces, possibly zero. + """ + indent = Match(r'^( *)\S', line) + if indent: + return len(indent.group(1)) + else: + return 0 + +def PathSplitToList(path): + """Returns the path split into a list by the separator. + + Args: + path: An absolute or relative path (e.g. '/a/b/c/' or '../a') + + Returns: + A list of path components (e.g. ['a', 'b', 'c]). + """ + lst = [] + while True: + (head, tail) = os.path.split(path) + if head == path: # absolute paths end + lst.append(head) + break + if tail == path: # relative paths end + lst.append(tail) + break + + path = head + lst.append(tail) + + lst.reverse() + return lst + +def GetHeaderGuardCPPVariable(filename): + """Returns the CPP variable that should be used as a header guard. + + Args: + filename: The name of a C++ header file. + + Returns: + The CPP variable that should be used as a header guard in the + named file. + + """ + + # Restores original filename in case that cpplint is invoked from Emacs's + # flymake. + filename = re.sub(r'_flymake\.h$', '.h', filename) + filename = re.sub(r'/\.flymake/([^/]*)$', r'/\1', filename) + # Replace 'c++' with 'cpp'. + filename = filename.replace('C++', 'cpp').replace('c++', 'cpp') + + fileinfo = FileInfo(filename) + file_path_from_root = fileinfo.RepositoryName() + + def FixupPathFromRoot(): + if _root_debug: + sys.stderr.write("\n_root fixup, _root = '%s', repository name = '%s'\n" + % (_root, fileinfo.RepositoryName())) + + # Process the file path with the --root flag if it was set. + if not _root: + if _root_debug: + sys.stderr.write("_root unspecified\n") + return file_path_from_root + + def StripListPrefix(lst, prefix): + # f(['x', 'y'], ['w, z']) -> None (not a valid prefix) + if lst[:len(prefix)] != prefix: + return None + # f(['a, 'b', 'c', 'd'], ['a', 'b']) -> ['c', 'd'] + return lst[(len(prefix)):] + + # root behavior: + # --root=subdir , lstrips subdir from the header guard + maybe_path = StripListPrefix(PathSplitToList(file_path_from_root), + PathSplitToList(_root)) + + if _root_debug: + sys.stderr.write(("_root lstrip (maybe_path=%s, file_path_from_root=%s," + + " _root=%s)\n") % (maybe_path, file_path_from_root, _root)) + + if maybe_path: + return os.path.join(*maybe_path) + + # --root=.. , will prepend the outer directory to the header guard + full_path = fileinfo.FullName() + # adapt slashes for windows + root_abspath = os.path.abspath(_root).replace('\\', '/') + + maybe_path = StripListPrefix(PathSplitToList(full_path), + PathSplitToList(root_abspath)) + + if _root_debug: + sys.stderr.write(("_root prepend (maybe_path=%s, full_path=%s, " + + "root_abspath=%s)\n") % (maybe_path, full_path, root_abspath)) + + if maybe_path: + return os.path.join(*maybe_path) + + if _root_debug: + sys.stderr.write("_root ignore, returning %s\n" % (file_path_from_root)) + + # --root=FAKE_DIR is ignored + return file_path_from_root + + file_path_from_root = FixupPathFromRoot() + return re.sub(r'[^a-zA-Z0-9]', '_', file_path_from_root).upper() + '_' + + +def CheckForHeaderGuard(filename, clean_lines, error): + """Checks that the file contains a header guard. + + Logs an error if no #ifndef header guard is present. For other + headers, checks that the full pathname is used. + + Args: + filename: The name of the C++ header file. + clean_lines: A CleansedLines instance containing the file. + error: The function to call with any errors found. + """ + + # Don't check for header guards if there are error suppression + # comments somewhere in this file. + # + # Because this is silencing a warning for a nonexistent line, we + # only support the very specific NOLINT(build/header_guard) syntax, + # and not the general NOLINT or NOLINT(*) syntax. + raw_lines = clean_lines.lines_without_raw_strings + for i in raw_lines: + if Search(r'//\s*NOLINT\(build/header_guard\)', i): + return + + # Allow pragma once instead of header guards + for i in raw_lines: + if Search(r'^\s*#pragma\s+once', i): + return + + cppvar = GetHeaderGuardCPPVariable(filename) + + ifndef = '' + ifndef_linenum = 0 + define = '' + endif = '' + endif_linenum = 0 + for linenum, line in enumerate(raw_lines): + linesplit = line.split() + if len(linesplit) >= 2: + # find the first occurrence of #ifndef and #define, save arg + if not ifndef and linesplit[0] == '#ifndef': + # set ifndef to the header guard presented on the #ifndef line. + ifndef = linesplit[1] + ifndef_linenum = linenum + if not define and linesplit[0] == '#define': + define = linesplit[1] + # find the last occurrence of #endif, save entire line + if line.startswith('#endif'): + endif = line + endif_linenum = linenum + + if not ifndef or not define or ifndef != define: + error(filename, 0, 'build/header_guard', 5, + 'No #ifndef header guard found, suggested CPP variable is: %s' % + cppvar) + return + + # The guard should be PATH_FILE_H_, but we also allow PATH_FILE_H__ + # for backward compatibility. + if ifndef != cppvar: + error_level = 0 + if ifndef != cppvar + '_': + error_level = 5 + + ParseNolintSuppressions(filename, raw_lines[ifndef_linenum], ifndef_linenum, + error) + error(filename, ifndef_linenum, 'build/header_guard', error_level, + '#ifndef header guard has wrong style, please use: %s' % cppvar) + + # Check for "//" comments on endif line. + ParseNolintSuppressions(filename, raw_lines[endif_linenum], endif_linenum, + error) + match = Match(r'#endif\s*//\s*' + cppvar + r'(_)?\b', endif) + if match: + if match.group(1) == '_': + # Issue low severity warning for deprecated double trailing underscore + error(filename, endif_linenum, 'build/header_guard', 0, + '#endif line should be "#endif // %s"' % cppvar) + return + + # Didn't find the corresponding "//" comment. If this file does not + # contain any "//" comments at all, it could be that the compiler + # only wants "/**/" comments, look for those instead. + no_single_line_comments = True + for i in xrange(1, len(raw_lines) - 1): + line = raw_lines[i] + if Match(r'^(?:(?:\'(?:\.|[^\'])*\')|(?:"(?:\.|[^"])*")|[^\'"])*//', line): + no_single_line_comments = False + break + + if no_single_line_comments: + match = Match(r'#endif\s*/\*\s*' + cppvar + r'(_)?\s*\*/', endif) + if match: + if match.group(1) == '_': + # Low severity warning for double trailing underscore + error(filename, endif_linenum, 'build/header_guard', 0, + '#endif line should be "#endif /* %s */"' % cppvar) + return + + # Didn't find anything + error(filename, endif_linenum, 'build/header_guard', 5, + '#endif line should be "#endif // %s"' % cppvar) + + +def CheckHeaderFileIncluded(filename, include_state, error): + """Logs an error if a source file does not include its header.""" + + # Do not check test files + fileinfo = FileInfo(filename) + if Search(_TEST_FILE_SUFFIX, fileinfo.BaseName()): + return + + for ext in GetHeaderExtensions(): + basefilename = filename[0:len(filename) - len(fileinfo.Extension())] + headerfile = basefilename + '.' + ext + if not os.path.exists(headerfile): + continue + headername = FileInfo(headerfile).RepositoryName() + first_include = None + include_uses_unix_dir_aliases = False + for section_list in include_state.include_list: + for f in section_list: + include_text = f[0] + if "./" in include_text: + include_uses_unix_dir_aliases = True + if headername in include_text or include_text in headername: + return + if not first_include: + first_include = f[1] + + message = '%s should include its header file %s' % (fileinfo.RepositoryName(), headername) + if include_uses_unix_dir_aliases: + message += ". Relative paths like . and .. are not allowed." + + error(filename, first_include, 'build/include', 5, message) + + +def CheckForBadCharacters(filename, lines, error): + """Logs an error for each line containing bad characters. + + Two kinds of bad characters: + + 1. Unicode replacement characters: These indicate that either the file + contained invalid UTF-8 (likely) or Unicode replacement characters (which + it shouldn't). Note that it's possible for this to throw off line + numbering if the invalid UTF-8 occurred adjacent to a newline. + + 2. NUL bytes. These are problematic for some tools. + + Args: + filename: The name of the current file. + lines: An array of strings, each representing a line of the file. + error: The function to call with any errors found. + """ + for linenum, line in enumerate(lines): + if unicode_escape_decode('\ufffd') in line: + error(filename, linenum, 'readability/utf8', 5, + 'Line contains invalid UTF-8 (or Unicode replacement character).') + if '\0' in line: + error(filename, linenum, 'readability/nul', 5, 'Line contains NUL byte.') + + +def CheckForNewlineAtEOF(filename, lines, error): + """Logs an error if there is no newline char at the end of the file. + + Args: + filename: The name of the current file. + lines: An array of strings, each representing a line of the file. + error: The function to call with any errors found. + """ + + # The array lines() was created by adding two newlines to the + # original file (go figure), then splitting on \n. + # To verify that the file ends in \n, we just have to make sure the + # last-but-two element of lines() exists and is empty. + if len(lines) < 3 or lines[-2]: + error(filename, len(lines) - 2, 'whitespace/ending_newline', 5, + 'Could not find a newline character at the end of the file.') + + +def CheckForMultilineCommentsAndStrings(filename, clean_lines, linenum, error): + """Logs an error if we see /* ... */ or "..." that extend past one line. + + /* ... */ comments are legit inside macros, for one line. + Otherwise, we prefer // comments, so it's ok to warn about the + other. Likewise, it's ok for strings to extend across multiple + lines, as long as a line continuation character (backslash) + terminates each line. Although not currently prohibited by the C++ + style guide, it's ugly and unnecessary. We don't do well with either + in this lint program, so we warn about both. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + line = clean_lines.elided[linenum] + + # Remove all \\ (escaped backslashes) from the line. They are OK, and the + # second (escaped) slash may trigger later \" detection erroneously. + line = line.replace('\\\\', '') + + if line.count('/*') > line.count('*/'): + error(filename, linenum, 'readability/multiline_comment', 5, + 'Complex multi-line /*...*/-style comment found. ' + 'Lint may give bogus warnings. ' + 'Consider replacing these with //-style comments, ' + 'with #if 0...#endif, ' + 'or with more clearly structured multi-line comments.') + + if (line.count('"') - line.count('\\"')) % 2: + error(filename, linenum, 'readability/multiline_string', 5, + 'Multi-line string ("...") found. This lint script doesn\'t ' + 'do well with such strings, and may give bogus warnings. ' + 'Use C++11 raw strings or concatenation instead.') + + +# (non-threadsafe name, thread-safe alternative, validation pattern) +# +# The validation pattern is used to eliminate false positives such as: +# _rand(); // false positive due to substring match. +# ->rand(); // some member function rand(). +# ACMRandom rand(seed); // some variable named rand. +# ISAACRandom rand(); // another variable named rand. +# +# Basically we require the return value of these functions to be used +# in some expression context on the same line by matching on some +# operator before the function name. This eliminates constructors and +# member function calls. +_UNSAFE_FUNC_PREFIX = r'(?:[-+*/=%^&|(<]\s*|>\s+)' +_THREADING_LIST = ( + ('asctime(', 'asctime_r(', _UNSAFE_FUNC_PREFIX + r'asctime\([^)]+\)'), + ('ctime(', 'ctime_r(', _UNSAFE_FUNC_PREFIX + r'ctime\([^)]+\)'), + ('getgrgid(', 'getgrgid_r(', _UNSAFE_FUNC_PREFIX + r'getgrgid\([^)]+\)'), + ('getgrnam(', 'getgrnam_r(', _UNSAFE_FUNC_PREFIX + r'getgrnam\([^)]+\)'), + ('getlogin(', 'getlogin_r(', _UNSAFE_FUNC_PREFIX + r'getlogin\(\)'), + ('getpwnam(', 'getpwnam_r(', _UNSAFE_FUNC_PREFIX + r'getpwnam\([^)]+\)'), + ('getpwuid(', 'getpwuid_r(', _UNSAFE_FUNC_PREFIX + r'getpwuid\([^)]+\)'), + ('gmtime(', 'gmtime_r(', _UNSAFE_FUNC_PREFIX + r'gmtime\([^)]+\)'), + ('localtime(', 'localtime_r(', _UNSAFE_FUNC_PREFIX + r'localtime\([^)]+\)'), + ('rand(', 'rand_r(', _UNSAFE_FUNC_PREFIX + r'rand\(\)'), + ('strtok(', 'strtok_r(', + _UNSAFE_FUNC_PREFIX + r'strtok\([^)]+\)'), + ('ttyname(', 'ttyname_r(', _UNSAFE_FUNC_PREFIX + r'ttyname\([^)]+\)'), + ) + + +def CheckPosixThreading(filename, clean_lines, linenum, error): + """Checks for calls to thread-unsafe functions. + + Much code has been originally written without consideration of + multi-threading. Also, engineers are relying on their old experience; + they have learned posix before threading extensions were added. These + tests guide the engineers to use thread-safe functions (when using + posix directly). + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + line = clean_lines.elided[linenum] + for single_thread_func, multithread_safe_func, pattern in _THREADING_LIST: + # Additional pattern matching check to confirm that this is the + # function we are looking for + if Search(pattern, line): + error(filename, linenum, 'runtime/threadsafe_fn', 2, + 'Consider using ' + multithread_safe_func + + '...) instead of ' + single_thread_func + + '...) for improved thread safety.') + + +def CheckVlogArguments(filename, clean_lines, linenum, error): + """Checks that VLOG() is only used for defining a logging level. + + For example, VLOG(2) is correct. VLOG(INFO), VLOG(WARNING), VLOG(ERROR), and + VLOG(FATAL) are not. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + line = clean_lines.elided[linenum] + if Search(r'\bVLOG\((INFO|ERROR|WARNING|DFATAL|FATAL)\)', line): + error(filename, linenum, 'runtime/vlog', 5, + 'VLOG() should be used with numeric verbosity level. ' + 'Use LOG() if you want symbolic severity levels.') + +# Matches invalid increment: *count++, which moves pointer instead of +# incrementing a value. +_RE_PATTERN_INVALID_INCREMENT = re.compile( + r'^\s*\*\w+(\+\+|--);') + + +def CheckInvalidIncrement(filename, clean_lines, linenum, error): + """Checks for invalid increment *count++. + + For example following function: + void increment_counter(int* count) { + *count++; + } + is invalid, because it effectively does count++, moving pointer, and should + be replaced with ++*count, (*count)++ or *count += 1. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + line = clean_lines.elided[linenum] + if _RE_PATTERN_INVALID_INCREMENT.match(line): + error(filename, linenum, 'runtime/invalid_increment', 5, + 'Changing pointer instead of value (or unused value of operator*).') + + +def IsMacroDefinition(clean_lines, linenum): + if Search(r'^#define', clean_lines[linenum]): + return True + + if linenum > 0 and Search(r'\\$', clean_lines[linenum - 1]): + return True + + return False + + +def IsForwardClassDeclaration(clean_lines, linenum): + return Match(r'^\s*(\btemplate\b)*.*class\s+\w+;\s*$', clean_lines[linenum]) + + +class _BlockInfo(object): + """Stores information about a generic block of code.""" + + def __init__(self, linenum, seen_open_brace): + self.starting_linenum = linenum + self.seen_open_brace = seen_open_brace + self.open_parentheses = 0 + self.inline_asm = _NO_ASM + self.check_namespace_indentation = False + + def CheckBegin(self, filename, clean_lines, linenum, error): + """Run checks that applies to text up to the opening brace. + + This is mostly for checking the text after the class identifier + and the "{", usually where the base class is specified. For other + blocks, there isn't much to check, so we always pass. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + pass + + def CheckEnd(self, filename, clean_lines, linenum, error): + """Run checks that applies to text after the closing brace. + + This is mostly used for checking end of namespace comments. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + pass + + def IsBlockInfo(self): + """Returns true if this block is a _BlockInfo. + + This is convenient for verifying that an object is an instance of + a _BlockInfo, but not an instance of any of the derived classes. + + Returns: + True for this class, False for derived classes. + """ + return self.__class__ == _BlockInfo + + +class _ExternCInfo(_BlockInfo): + """Stores information about an 'extern "C"' block.""" + + def __init__(self, linenum): + _BlockInfo.__init__(self, linenum, True) + + +class _ClassInfo(_BlockInfo): + """Stores information about a class.""" + + def __init__(self, name, class_or_struct, clean_lines, linenum): + _BlockInfo.__init__(self, linenum, False) + self.name = name + self.is_derived = False + self.check_namespace_indentation = True + if class_or_struct == 'struct': + self.access = 'public' + self.is_struct = True + else: + self.access = 'private' + self.is_struct = False + + # Remember initial indentation level for this class. Using raw_lines here + # instead of elided to account for leading comments. + self.class_indent = GetIndentLevel(clean_lines.raw_lines[linenum]) + + # Try to find the end of the class. This will be confused by things like: + # class A { + # } *x = { ... + # + # But it's still good enough for CheckSectionSpacing. + self.last_line = 0 + depth = 0 + for i in range(linenum, clean_lines.NumLines()): + line = clean_lines.elided[i] + depth += line.count('{') - line.count('}') + if not depth: + self.last_line = i + break + + def CheckBegin(self, filename, clean_lines, linenum, error): + # Look for a bare ':' + if Search('(^|[^:]):($|[^:])', clean_lines.elided[linenum]): + self.is_derived = True + + def CheckEnd(self, filename, clean_lines, linenum, error): + # If there is a DISALLOW macro, it should appear near the end of + # the class. + seen_last_thing_in_class = False + for i in xrange(linenum - 1, self.starting_linenum, -1): + match = Search( + r'\b(DISALLOW_COPY_AND_ASSIGN|DISALLOW_IMPLICIT_CONSTRUCTORS)\(' + + self.name + r'\)', + clean_lines.elided[i]) + if match: + if seen_last_thing_in_class: + error(filename, i, 'readability/constructors', 3, + match.group(1) + ' should be the last thing in the class') + break + + if not Match(r'^\s*$', clean_lines.elided[i]): + seen_last_thing_in_class = True + + # Check that closing brace is aligned with beginning of the class. + # Only do this if the closing brace is indented by only whitespaces. + # This means we will not check single-line class definitions. + indent = Match(r'^( *)\}', clean_lines.elided[linenum]) + if indent and len(indent.group(1)) != self.class_indent: + if self.is_struct: + parent = 'struct ' + self.name + else: + parent = 'class ' + self.name + error(filename, linenum, 'whitespace/indent', 3, + 'Closing brace should be aligned with beginning of %s' % parent) + + +class _NamespaceInfo(_BlockInfo): + """Stores information about a namespace.""" + + def __init__(self, name, linenum): + _BlockInfo.__init__(self, linenum, False) + self.name = name or '' + self.check_namespace_indentation = True + + def CheckEnd(self, filename, clean_lines, linenum, error): + """Check end of namespace comments.""" + line = clean_lines.raw_lines[linenum] + + # Check how many lines is enclosed in this namespace. Don't issue + # warning for missing namespace comments if there aren't enough + # lines. However, do apply checks if there is already an end of + # namespace comment and it's incorrect. + # + # TODO(unknown): We always want to check end of namespace comments + # if a namespace is large, but sometimes we also want to apply the + # check if a short namespace contained nontrivial things (something + # other than forward declarations). There is currently no logic on + # deciding what these nontrivial things are, so this check is + # triggered by namespace size only, which works most of the time. + if (linenum - self.starting_linenum < 10 + and not Match(r'^\s*};*\s*(//|/\*).*\bnamespace\b', line)): + return + + # Look for matching comment at end of namespace. + # + # Note that we accept C style "/* */" comments for terminating + # namespaces, so that code that terminate namespaces inside + # preprocessor macros can be cpplint clean. + # + # We also accept stuff like "// end of namespace ." with the + # period at the end. + # + # Besides these, we don't accept anything else, otherwise we might + # get false negatives when existing comment is a substring of the + # expected namespace. + if self.name: + # Named namespace + if not Match((r'^\s*};*\s*(//|/\*).*\bnamespace\s+' + + re.escape(self.name) + r'[\*/\.\\\s]*$'), + line): + error(filename, linenum, 'readability/namespace', 5, + 'Namespace should be terminated with "// namespace %s"' % + self.name) + else: + # Anonymous namespace + if not Match(r'^\s*};*\s*(//|/\*).*\bnamespace[\*/\.\\\s]*$', line): + # If "// namespace anonymous" or "// anonymous namespace (more text)", + # mention "// anonymous namespace" as an acceptable form + if Match(r'^\s*}.*\b(namespace anonymous|anonymous namespace)\b', line): + error(filename, linenum, 'readability/namespace', 5, + 'Anonymous namespace should be terminated with "// namespace"' + ' or "// anonymous namespace"') + else: + error(filename, linenum, 'readability/namespace', 5, + 'Anonymous namespace should be terminated with "// namespace"') + + +class _PreprocessorInfo(object): + """Stores checkpoints of nesting stacks when #if/#else is seen.""" + + def __init__(self, stack_before_if): + # The entire nesting stack before #if + self.stack_before_if = stack_before_if + + # The entire nesting stack up to #else + self.stack_before_else = [] + + # Whether we have already seen #else or #elif + self.seen_else = False + + +class NestingState(object): + """Holds states related to parsing braces.""" + + def __init__(self): + # Stack for tracking all braces. An object is pushed whenever we + # see a "{", and popped when we see a "}". Only 3 types of + # objects are possible: + # - _ClassInfo: a class or struct. + # - _NamespaceInfo: a namespace. + # - _BlockInfo: some other type of block. + self.stack = [] + + # Top of the previous stack before each Update(). + # + # Because the nesting_stack is updated at the end of each line, we + # had to do some convoluted checks to find out what is the current + # scope at the beginning of the line. This check is simplified by + # saving the previous top of nesting stack. + # + # We could save the full stack, but we only need the top. Copying + # the full nesting stack would slow down cpplint by ~10%. + self.previous_stack_top = [] + + # Stack of _PreprocessorInfo objects. + self.pp_stack = [] + + def SeenOpenBrace(self): + """Check if we have seen the opening brace for the innermost block. + + Returns: + True if we have seen the opening brace, False if the innermost + block is still expecting an opening brace. + """ + return (not self.stack) or self.stack[-1].seen_open_brace + + def InNamespaceBody(self): + """Check if we are currently one level inside a namespace body. + + Returns: + True if top of the stack is a namespace block, False otherwise. + """ + return self.stack and isinstance(self.stack[-1], _NamespaceInfo) + + def InExternC(self): + """Check if we are currently one level inside an 'extern "C"' block. + + Returns: + True if top of the stack is an extern block, False otherwise. + """ + return self.stack and isinstance(self.stack[-1], _ExternCInfo) + + def InClassDeclaration(self): + """Check if we are currently one level inside a class or struct declaration. + + Returns: + True if top of the stack is a class/struct, False otherwise. + """ + return self.stack and isinstance(self.stack[-1], _ClassInfo) + + def InAsmBlock(self): + """Check if we are currently one level inside an inline ASM block. + + Returns: + True if the top of the stack is a block containing inline ASM. + """ + return self.stack and self.stack[-1].inline_asm != _NO_ASM + + def InTemplateArgumentList(self, clean_lines, linenum, pos): + """Check if current position is inside template argument list. + + Args: + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + pos: position just after the suspected template argument. + Returns: + True if (linenum, pos) is inside template arguments. + """ + while linenum < clean_lines.NumLines(): + # Find the earliest character that might indicate a template argument + line = clean_lines.elided[linenum] + match = Match(r'^[^{};=\[\]\.<>]*(.)', line[pos:]) + if not match: + linenum += 1 + pos = 0 + continue + token = match.group(1) + pos += len(match.group(0)) + + # These things do not look like template argument list: + # class Suspect { + # class Suspect x; } + if token in ('{', '}', ';'): return False + + # These things look like template argument list: + # template + # template + # template + # template + if token in ('>', '=', '[', ']', '.'): return True + + # Check if token is an unmatched '<'. + # If not, move on to the next character. + if token != '<': + pos += 1 + if pos >= len(line): + linenum += 1 + pos = 0 + continue + + # We can't be sure if we just find a single '<', and need to + # find the matching '>'. + (_, end_line, end_pos) = CloseExpression(clean_lines, linenum, pos - 1) + if end_pos < 0: + # Not sure if template argument list or syntax error in file + return False + linenum = end_line + pos = end_pos + return False + + def UpdatePreprocessor(self, line): + """Update preprocessor stack. + + We need to handle preprocessors due to classes like this: + #ifdef SWIG + struct ResultDetailsPageElementExtensionPoint { + #else + struct ResultDetailsPageElementExtensionPoint : public Extension { + #endif + + We make the following assumptions (good enough for most files): + - Preprocessor condition evaluates to true from #if up to first + #else/#elif/#endif. + + - Preprocessor condition evaluates to false from #else/#elif up + to #endif. We still perform lint checks on these lines, but + these do not affect nesting stack. + + Args: + line: current line to check. + """ + if Match(r'^\s*#\s*(if|ifdef|ifndef)\b', line): + # Beginning of #if block, save the nesting stack here. The saved + # stack will allow us to restore the parsing state in the #else case. + self.pp_stack.append(_PreprocessorInfo(copy.deepcopy(self.stack))) + elif Match(r'^\s*#\s*(else|elif)\b', line): + # Beginning of #else block + if self.pp_stack: + if not self.pp_stack[-1].seen_else: + # This is the first #else or #elif block. Remember the + # whole nesting stack up to this point. This is what we + # keep after the #endif. + self.pp_stack[-1].seen_else = True + self.pp_stack[-1].stack_before_else = copy.deepcopy(self.stack) + + # Restore the stack to how it was before the #if + self.stack = copy.deepcopy(self.pp_stack[-1].stack_before_if) + else: + # TODO(unknown): unexpected #else, issue warning? + pass + elif Match(r'^\s*#\s*endif\b', line): + # End of #if or #else blocks. + if self.pp_stack: + # If we saw an #else, we will need to restore the nesting + # stack to its former state before the #else, otherwise we + # will just continue from where we left off. + if self.pp_stack[-1].seen_else: + # Here we can just use a shallow copy since we are the last + # reference to it. + self.stack = self.pp_stack[-1].stack_before_else + # Drop the corresponding #if + self.pp_stack.pop() + else: + # TODO(unknown): unexpected #endif, issue warning? + pass + + # TODO(unknown): Update() is too long, but we will refactor later. + def Update(self, filename, clean_lines, linenum, error): + """Update nesting state with current line. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + line = clean_lines.elided[linenum] + + # Remember top of the previous nesting stack. + # + # The stack is always pushed/popped and not modified in place, so + # we can just do a shallow copy instead of copy.deepcopy. Using + # deepcopy would slow down cpplint by ~28%. + if self.stack: + self.previous_stack_top = self.stack[-1] + else: + self.previous_stack_top = None + + # Update pp_stack + self.UpdatePreprocessor(line) + + # Count parentheses. This is to avoid adding struct arguments to + # the nesting stack. + if self.stack: + inner_block = self.stack[-1] + depth_change = line.count('(') - line.count(')') + inner_block.open_parentheses += depth_change + + # Also check if we are starting or ending an inline assembly block. + if inner_block.inline_asm in (_NO_ASM, _END_ASM): + if (depth_change != 0 and + inner_block.open_parentheses == 1 and + _MATCH_ASM.match(line)): + # Enter assembly block + inner_block.inline_asm = _INSIDE_ASM + else: + # Not entering assembly block. If previous line was _END_ASM, + # we will now shift to _NO_ASM state. + inner_block.inline_asm = _NO_ASM + elif (inner_block.inline_asm == _INSIDE_ASM and + inner_block.open_parentheses == 0): + # Exit assembly block + inner_block.inline_asm = _END_ASM + + # Consume namespace declaration at the beginning of the line. Do + # this in a loop so that we catch same line declarations like this: + # namespace proto2 { namespace bridge { class MessageSet; } } + while True: + # Match start of namespace. The "\b\s*" below catches namespace + # declarations even if it weren't followed by a whitespace, this + # is so that we don't confuse our namespace checker. The + # missing spaces will be flagged by CheckSpacing. + namespace_decl_match = Match(r'^\s*namespace\b\s*([:\w]+)?(.*)$', line) + if not namespace_decl_match: + break + + new_namespace = _NamespaceInfo(namespace_decl_match.group(1), linenum) + self.stack.append(new_namespace) + + line = namespace_decl_match.group(2) + if line.find('{') != -1: + new_namespace.seen_open_brace = True + line = line[line.find('{') + 1:] + + # Look for a class declaration in whatever is left of the line + # after parsing namespaces. The regexp accounts for decorated classes + # such as in: + # class LOCKABLE API Object { + # }; + class_decl_match = Match( + r'^(\s*(?:template\s*<[\w\s<>,:=]*>\s*)?' + r'(class|struct)\s+(?:[a-zA-Z0-9_]+\s+)*(\w+(?:::\w+)*))' + r'(.*)$', line) + if (class_decl_match and + (not self.stack or self.stack[-1].open_parentheses == 0)): + # We do not want to accept classes that are actually template arguments: + # template , + # template class Ignore3> + # void Function() {}; + # + # To avoid template argument cases, we scan forward and look for + # an unmatched '>'. If we see one, assume we are inside a + # template argument list. + end_declaration = len(class_decl_match.group(1)) + if not self.InTemplateArgumentList(clean_lines, linenum, end_declaration): + self.stack.append(_ClassInfo( + class_decl_match.group(3), class_decl_match.group(2), + clean_lines, linenum)) + line = class_decl_match.group(4) + + # If we have not yet seen the opening brace for the innermost block, + # run checks here. + if not self.SeenOpenBrace(): + self.stack[-1].CheckBegin(filename, clean_lines, linenum, error) + + # Update access control if we are inside a class/struct + if self.stack and isinstance(self.stack[-1], _ClassInfo): + classinfo = self.stack[-1] + access_match = Match( + r'^(.*)\b(public|private|protected|signals)(\s+(?:slots\s*)?)?' + r':(?:[^:]|$)', + line) + if access_match: + classinfo.access = access_match.group(2) + + # Check that access keywords are indented +1 space. Skip this + # check if the keywords are not preceded by whitespaces. + indent = access_match.group(1) + if (len(indent) != classinfo.class_indent + 1 and + Match(r'^\s*$', indent)): + if classinfo.is_struct: + parent = 'struct ' + classinfo.name + else: + parent = 'class ' + classinfo.name + slots = '' + if access_match.group(3): + slots = access_match.group(3) + error(filename, linenum, 'whitespace/indent', 3, + '%s%s: should be indented +1 space inside %s' % ( + access_match.group(2), slots, parent)) + + # Consume braces or semicolons from what's left of the line + while True: + # Match first brace, semicolon, or closed parenthesis. + matched = Match(r'^[^{;)}]*([{;)}])(.*)$', line) + if not matched: + break + + token = matched.group(1) + if token == '{': + # If namespace or class hasn't seen a opening brace yet, mark + # namespace/class head as complete. Push a new block onto the + # stack otherwise. + if not self.SeenOpenBrace(): + self.stack[-1].seen_open_brace = True + elif Match(r'^extern\s*"[^"]*"\s*\{', line): + self.stack.append(_ExternCInfo(linenum)) + else: + self.stack.append(_BlockInfo(linenum, True)) + if _MATCH_ASM.match(line): + self.stack[-1].inline_asm = _BLOCK_ASM + + elif token == ';' or token == ')': + # If we haven't seen an opening brace yet, but we already saw + # a semicolon, this is probably a forward declaration. Pop + # the stack for these. + # + # Similarly, if we haven't seen an opening brace yet, but we + # already saw a closing parenthesis, then these are probably + # function arguments with extra "class" or "struct" keywords. + # Also pop these stack for these. + if not self.SeenOpenBrace(): + self.stack.pop() + else: # token == '}' + # Perform end of block checks and pop the stack. + if self.stack: + self.stack[-1].CheckEnd(filename, clean_lines, linenum, error) + self.stack.pop() + line = matched.group(2) + + def InnermostClass(self): + """Get class info on the top of the stack. + + Returns: + A _ClassInfo object if we are inside a class, or None otherwise. + """ + for i in range(len(self.stack), 0, -1): + classinfo = self.stack[i - 1] + if isinstance(classinfo, _ClassInfo): + return classinfo + return None + + def CheckCompletedBlocks(self, filename, error): + """Checks that all classes and namespaces have been completely parsed. + + Call this when all lines in a file have been processed. + Args: + filename: The name of the current file. + error: The function to call with any errors found. + """ + # Note: This test can result in false positives if #ifdef constructs + # get in the way of brace matching. See the testBuildClass test in + # cpplint_unittest.py for an example of this. + for obj in self.stack: + if isinstance(obj, _ClassInfo): + error(filename, obj.starting_linenum, 'build/class', 5, + 'Failed to find complete declaration of class %s' % + obj.name) + elif isinstance(obj, _NamespaceInfo): + error(filename, obj.starting_linenum, 'build/namespaces', 5, + 'Failed to find complete declaration of namespace %s' % + obj.name) + + +def CheckForNonStandardConstructs(filename, clean_lines, linenum, + nesting_state, error): + r"""Logs an error if we see certain non-ANSI constructs ignored by gcc-2. + + Complain about several constructs which gcc-2 accepts, but which are + not standard C++. Warning about these in lint is one way to ease the + transition to new compilers. + - put storage class first (e.g. "static const" instead of "const static"). + - "%lld" instead of %qd" in printf-type functions. + - "%1$d" is non-standard in printf-type functions. + - "\%" is an undefined character escape sequence. + - text after #endif is not allowed. + - invalid inner-style forward declaration. + - >? and ?= and )\?=?\s*(\w+|[+-]?\d+)(\.\d*)?', + line): + error(filename, linenum, 'build/deprecated', 3, + '>? and ))?' + # r'\s*const\s*' + type_name + '\s*&\s*\w+\s*;' + error(filename, linenum, 'runtime/member_string_references', 2, + 'const string& members are dangerous. It is much better to use ' + 'alternatives, such as pointers or simple constants.') + + # Everything else in this function operates on class declarations. + # Return early if the top of the nesting stack is not a class, or if + # the class head is not completed yet. + classinfo = nesting_state.InnermostClass() + if not classinfo or not classinfo.seen_open_brace: + return + + # The class may have been declared with namespace or classname qualifiers. + # The constructor and destructor will not have those qualifiers. + base_classname = classinfo.name.split('::')[-1] + + # Look for single-argument constructors that aren't marked explicit. + # Technically a valid construct, but against style. + explicit_constructor_match = Match( + r'\s+(?:(?:inline|constexpr)\s+)*(explicit\s+)?' + r'(?:(?:inline|constexpr)\s+)*%s\s*' + r'\(((?:[^()]|\([^()]*\))*)\)' + % re.escape(base_classname), + line) + + if explicit_constructor_match: + is_marked_explicit = explicit_constructor_match.group(1) + + if not explicit_constructor_match.group(2): + constructor_args = [] + else: + constructor_args = explicit_constructor_match.group(2).split(',') + + # collapse arguments so that commas in template parameter lists and function + # argument parameter lists don't split arguments in two + i = 0 + while i < len(constructor_args): + constructor_arg = constructor_args[i] + while (constructor_arg.count('<') > constructor_arg.count('>') or + constructor_arg.count('(') > constructor_arg.count(')')): + constructor_arg += ',' + constructor_args[i + 1] + del constructor_args[i + 1] + constructor_args[i] = constructor_arg + i += 1 + + variadic_args = [arg for arg in constructor_args if '&&...' in arg] + defaulted_args = [arg for arg in constructor_args if '=' in arg] + noarg_constructor = (not constructor_args or # empty arg list + # 'void' arg specifier + (len(constructor_args) == 1 and + constructor_args[0].strip() == 'void')) + onearg_constructor = ((len(constructor_args) == 1 and # exactly one arg + not noarg_constructor) or + # all but at most one arg defaulted + (len(constructor_args) >= 1 and + not noarg_constructor and + len(defaulted_args) >= len(constructor_args) - 1) or + # variadic arguments with zero or one argument + (len(constructor_args) <= 2 and + len(variadic_args) >= 1)) + initializer_list_constructor = bool( + onearg_constructor and + Search(r'\bstd\s*::\s*initializer_list\b', constructor_args[0])) + copy_constructor = bool( + onearg_constructor and + Match(r'((const\s+(volatile\s+)?)?|(volatile\s+(const\s+)?))?' + r'%s(\s*<[^>]*>)?(\s+const)?\s*(?:<\w+>\s*)?&' + % re.escape(base_classname), constructor_args[0].strip())) + + if (not is_marked_explicit and + onearg_constructor and + not initializer_list_constructor and + not copy_constructor): + if defaulted_args or variadic_args: + error(filename, linenum, 'runtime/explicit', 5, + 'Constructors callable with one argument ' + 'should be marked explicit.') + else: + error(filename, linenum, 'runtime/explicit', 5, + 'Single-parameter constructors should be marked explicit.') + elif is_marked_explicit and not onearg_constructor: + if noarg_constructor: + error(filename, linenum, 'runtime/explicit', 5, + 'Zero-parameter constructors should not be marked explicit.') + + +def CheckSpacingForFunctionCall(filename, clean_lines, linenum, error): + """Checks for the correctness of various spacing around function calls. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + line = clean_lines.elided[linenum] + + # Since function calls often occur inside if/for/while/switch + # expressions - which have their own, more liberal conventions - we + # first see if we should be looking inside such an expression for a + # function call, to which we can apply more strict standards. + fncall = line # if there's no control flow construct, look at whole line + for pattern in (r'\bif\s*\((.*)\)\s*{', + r'\bfor\s*\((.*)\)\s*{', + r'\bwhile\s*\((.*)\)\s*[{;]', + r'\bswitch\s*\((.*)\)\s*{'): + match = Search(pattern, line) + if match: + fncall = match.group(1) # look inside the parens for function calls + break + + # Except in if/for/while/switch, there should never be space + # immediately inside parens (eg "f( 3, 4 )"). We make an exception + # for nested parens ( (a+b) + c ). Likewise, there should never be + # a space before a ( when it's a function argument. I assume it's a + # function argument when the char before the whitespace is legal in + # a function name (alnum + _) and we're not starting a macro. Also ignore + # pointers and references to arrays and functions coz they're too tricky: + # we use a very simple way to recognize these: + # " (something)(maybe-something)" or + # " (something)(maybe-something," or + # " (something)[something]" + # Note that we assume the contents of [] to be short enough that + # they'll never need to wrap. + if ( # Ignore control structures. + not Search(r'\b(if|for|while|switch|return|new|delete|catch|sizeof)\b', + fncall) and + # Ignore pointers/references to functions. + not Search(r' \([^)]+\)\([^)]*(\)|,$)', fncall) and + # Ignore pointers/references to arrays. + not Search(r' \([^)]+\)\[[^\]]+\]', fncall)): + if Search(r'\w\s*\(\s(?!\s*\\$)', fncall): # a ( used for a fn call + error(filename, linenum, 'whitespace/parens', 4, + 'Extra space after ( in function call') + elif Search(r'\(\s+(?!(\s*\\)|\()', fncall): + error(filename, linenum, 'whitespace/parens', 2, + 'Extra space after (') + if (Search(r'\w\s+\(', fncall) and + not Search(r'_{0,2}asm_{0,2}\s+_{0,2}volatile_{0,2}\s+\(', fncall) and + not Search(r'#\s*define|typedef|using\s+\w+\s*=', fncall) and + not Search(r'\w\s+\((\w+::)*\*\w+\)\(', fncall) and + not Search(r'\bcase\s+\(', fncall)): + # TODO(unknown): Space after an operator function seem to be a common + # error, silence those for now by restricting them to highest verbosity. + if Search(r'\boperator_*\b', line): + error(filename, linenum, 'whitespace/parens', 0, + 'Extra space before ( in function call') + else: + error(filename, linenum, 'whitespace/parens', 4, + 'Extra space before ( in function call') + # If the ) is followed only by a newline or a { + newline, assume it's + # part of a control statement (if/while/etc), and don't complain + if Search(r'[^)]\s+\)\s*[^{\s]', fncall): + # If the closing parenthesis is preceded by only whitespaces, + # try to give a more descriptive error message. + if Search(r'^\s+\)', fncall): + error(filename, linenum, 'whitespace/parens', 2, + 'Closing ) should be moved to the previous line') + else: + error(filename, linenum, 'whitespace/parens', 2, + 'Extra space before )') + + +def IsBlankLine(line): + """Returns true if the given line is blank. + + We consider a line to be blank if the line is empty or consists of + only white spaces. + + Args: + line: A line of a string. + + Returns: + True, if the given line is blank. + """ + return not line or line.isspace() + + +def CheckForNamespaceIndentation(filename, nesting_state, clean_lines, line, + error): + is_namespace_indent_item = ( + len(nesting_state.stack) > 1 and + nesting_state.stack[-1].check_namespace_indentation and + isinstance(nesting_state.previous_stack_top, _NamespaceInfo) and + nesting_state.previous_stack_top == nesting_state.stack[-2]) + + if ShouldCheckNamespaceIndentation(nesting_state, is_namespace_indent_item, + clean_lines.elided, line): + CheckItemIndentationInNamespace(filename, clean_lines.elided, + line, error) + + +def CheckForFunctionLengths(filename, clean_lines, linenum, + function_state, error): + """Reports for long function bodies. + + For an overview why this is done, see: + https://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Write_Short_Functions + + Uses a simplistic algorithm assuming other style guidelines + (especially spacing) are followed. + Only checks unindented functions, so class members are unchecked. + Trivial bodies are unchecked, so constructors with huge initializer lists + may be missed. + Blank/comment lines are not counted so as to avoid encouraging the removal + of vertical space and comments just to get through a lint check. + NOLINT *on the last line of a function* disables this check. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + function_state: Current function name and lines in body so far. + error: The function to call with any errors found. + """ + lines = clean_lines.lines + line = lines[linenum] + joined_line = '' + + starting_func = False + regexp = r'(\w(\w|::|\*|\&|\s)*)\(' # decls * & space::name( ... + match_result = Match(regexp, line) + if match_result: + # If the name is all caps and underscores, figure it's a macro and + # ignore it, unless it's TEST or TEST_F. + function_name = match_result.group(1).split()[-1] + if function_name == 'TEST' or function_name == 'TEST_F' or ( + not Match(r'[A-Z_]+$', function_name)): + starting_func = True + + if starting_func: + body_found = False + for start_linenum in xrange(linenum, clean_lines.NumLines()): + start_line = lines[start_linenum] + joined_line += ' ' + start_line.lstrip() + if Search(r'(;|})', start_line): # Declarations and trivial functions + body_found = True + break # ... ignore + if Search(r'{', start_line): + body_found = True + function = Search(r'((\w|:)*)\(', line).group(1) + if Match(r'TEST', function): # Handle TEST... macros + parameter_regexp = Search(r'(\(.*\))', joined_line) + if parameter_regexp: # Ignore bad syntax + function += parameter_regexp.group(1) + else: + function += '()' + function_state.Begin(function) + break + if not body_found: + # No body for the function (or evidence of a non-function) was found. + error(filename, linenum, 'readability/fn_size', 5, + 'Lint failed to find start of function body.') + elif Match(r'^\}\s*$', line): # function end + function_state.Check(error, filename, linenum) + function_state.End() + elif not Match(r'^\s*$', line): + function_state.Count() # Count non-blank/non-comment lines. + + +_RE_PATTERN_TODO = re.compile(r'^//(\s*)TODO(\(.+?\))?:?(\s|$)?') + + +def CheckComment(line, filename, linenum, next_line_start, error): + """Checks for common mistakes in comments. + + Args: + line: The line in question. + filename: The name of the current file. + linenum: The number of the line to check. + next_line_start: The first non-whitespace column of the next line. + error: The function to call with any errors found. + """ + commentpos = line.find('//') + if commentpos != -1: + # Check if the // may be in quotes. If so, ignore it + if re.sub(r'\\.', '', line[0:commentpos]).count('"') % 2 == 0: + # Allow one space for new scopes, two spaces otherwise: + if (not (Match(r'^.*{ *//', line) and next_line_start == commentpos) and + ((commentpos >= 1 and + line[commentpos-1] not in string.whitespace) or + (commentpos >= 2 and + line[commentpos-2] not in string.whitespace))): + error(filename, linenum, 'whitespace/comments', 2, + 'At least two spaces is best between code and comments') + + # Checks for common mistakes in TODO comments. + comment = line[commentpos:] + match = _RE_PATTERN_TODO.match(comment) + if match: + # One whitespace is correct; zero whitespace is handled elsewhere. + leading_whitespace = match.group(1) + if len(leading_whitespace) > 1: + error(filename, linenum, 'whitespace/todo', 2, + 'Too many spaces before TODO') + + username = match.group(2) + if not username: + error(filename, linenum, 'readability/todo', 2, + 'Missing username in TODO; it should look like ' + '"// TODO(my_username): Stuff."') + + middle_whitespace = match.group(3) + # Comparisons made explicit for correctness -- pylint: disable=g-explicit-bool-comparison + if middle_whitespace != ' ' and middle_whitespace != '': + error(filename, linenum, 'whitespace/todo', 2, + 'TODO(my_username) should be followed by a space') + + # If the comment contains an alphanumeric character, there + # should be a space somewhere between it and the // unless + # it's a /// or //! Doxygen comment. + if (Match(r'//[^ ]*\w', comment) and + not Match(r'(///|//\!)(\s+|$)', comment)): + error(filename, linenum, 'whitespace/comments', 4, + 'Should have a space between // and comment') + + +def CheckSpacing(filename, clean_lines, linenum, nesting_state, error): + """Checks for the correctness of various spacing issues in the code. + + Things we check for: spaces around operators, spaces after + if/for/while/switch, no spaces around parens in function calls, two + spaces between code and comment, don't start a block with a blank + line, don't end a function with a blank line, don't add a blank line + after public/protected/private, don't have too many blank lines in a row. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + nesting_state: A NestingState instance which maintains information about + the current stack of nested blocks being parsed. + error: The function to call with any errors found. + """ + + # Don't use "elided" lines here, otherwise we can't check commented lines. + # Don't want to use "raw" either, because we don't want to check inside C++11 + # raw strings, + raw = clean_lines.lines_without_raw_strings + line = raw[linenum] + + # Before nixing comments, check if the line is blank for no good + # reason. This includes the first line after a block is opened, and + # blank lines at the end of a function (ie, right before a line like '}' + # + # Skip all the blank line checks if we are immediately inside a + # namespace body. In other words, don't issue blank line warnings + # for this block: + # namespace { + # + # } + # + # A warning about missing end of namespace comments will be issued instead. + # + # Also skip blank line checks for 'extern "C"' blocks, which are formatted + # like namespaces. + if (IsBlankLine(line) and + not nesting_state.InNamespaceBody() and + not nesting_state.InExternC()): + elided = clean_lines.elided + prev_line = elided[linenum - 1] + prevbrace = prev_line.rfind('{') + # TODO(unknown): Don't complain if line before blank line, and line after, + # both start with alnums and are indented the same amount. + # This ignores whitespace at the start of a namespace block + # because those are not usually indented. + if prevbrace != -1 and prev_line[prevbrace:].find('}') == -1: + # OK, we have a blank line at the start of a code block. Before we + # complain, we check if it is an exception to the rule: The previous + # non-empty line has the parameters of a function header that are indented + # 4 spaces (because they did not fit in a 80 column line when placed on + # the same line as the function name). We also check for the case where + # the previous line is indented 6 spaces, which may happen when the + # initializers of a constructor do not fit into a 80 column line. + exception = False + if Match(r' {6}\w', prev_line): # Initializer list? + # We are looking for the opening column of initializer list, which + # should be indented 4 spaces to cause 6 space indentation afterwards. + search_position = linenum-2 + while (search_position >= 0 + and Match(r' {6}\w', elided[search_position])): + search_position -= 1 + exception = (search_position >= 0 + and elided[search_position][:5] == ' :') + else: + # Search for the function arguments or an initializer list. We use a + # simple heuristic here: If the line is indented 4 spaces; and we have a + # closing paren, without the opening paren, followed by an opening brace + # or colon (for initializer lists) we assume that it is the last line of + # a function header. If we have a colon indented 4 spaces, it is an + # initializer list. + exception = (Match(r' {4}\w[^\(]*\)\s*(const\s*)?(\{\s*$|:)', + prev_line) + or Match(r' {4}:', prev_line)) + + if not exception: + error(filename, linenum, 'whitespace/blank_line', 2, + 'Redundant blank line at the start of a code block ' + 'should be deleted.') + # Ignore blank lines at the end of a block in a long if-else + # chain, like this: + # if (condition1) { + # // Something followed by a blank line + # + # } else if (condition2) { + # // Something else + # } + if linenum + 1 < clean_lines.NumLines(): + next_line = raw[linenum + 1] + if (next_line + and Match(r'\s*}', next_line) + and next_line.find('} else ') == -1): + error(filename, linenum, 'whitespace/blank_line', 3, + 'Redundant blank line at the end of a code block ' + 'should be deleted.') + + matched = Match(r'\s*(public|protected|private):', prev_line) + if matched: + error(filename, linenum, 'whitespace/blank_line', 3, + 'Do not leave a blank line after "%s:"' % matched.group(1)) + + # Next, check comments + next_line_start = 0 + if linenum + 1 < clean_lines.NumLines(): + next_line = raw[linenum + 1] + next_line_start = len(next_line) - len(next_line.lstrip()) + CheckComment(line, filename, linenum, next_line_start, error) + + # get rid of comments and strings + line = clean_lines.elided[linenum] + + # You shouldn't have spaces before your brackets, except for C++11 attributes + # or maybe after 'delete []', 'return []() {};', or 'auto [abc, ...] = ...;'. + if (Search(r'\w\s+\[(?!\[)', line) and + not Search(r'(?:auto&?|delete|return)\s+\[', line)): + error(filename, linenum, 'whitespace/braces', 5, + 'Extra space before [') + + # In range-based for, we wanted spaces before and after the colon, but + # not around "::" tokens that might appear. + if (Search(r'for *\(.*[^:]:[^: ]', line) or + Search(r'for *\(.*[^: ]:[^:]', line)): + error(filename, linenum, 'whitespace/forcolon', 2, + 'Missing space around colon in range-based for loop') + + +def CheckOperatorSpacing(filename, clean_lines, linenum, error): + """Checks for horizontal spacing around operators. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + line = clean_lines.elided[linenum] + + # Don't try to do spacing checks for operator methods. Do this by + # replacing the troublesome characters with something else, + # preserving column position for all other characters. + # + # The replacement is done repeatedly to avoid false positives from + # operators that call operators. + while True: + match = Match(r'^(.*\boperator\b)(\S+)(\s*\(.*)$', line) + if match: + line = match.group(1) + ('_' * len(match.group(2))) + match.group(3) + else: + break + + # We allow no-spaces around = within an if: "if ( (a=Foo()) == 0 )". + # Otherwise not. Note we only check for non-spaces on *both* sides; + # sometimes people put non-spaces on one side when aligning ='s among + # many lines (not that this is behavior that I approve of...) + if ((Search(r'[\w.]=', line) or + Search(r'=[\w.]', line)) + and not Search(r'\b(if|while|for) ', line) + # Operators taken from [lex.operators] in C++11 standard. + and not Search(r'(>=|<=|==|!=|&=|\^=|\|=|\+=|\*=|\/=|\%=)', line) + and not Search(r'operator=', line)): + error(filename, linenum, 'whitespace/operators', 4, + 'Missing spaces around =') + + # It's ok not to have spaces around binary operators like + - * /, but if + # there's too little whitespace, we get concerned. It's hard to tell, + # though, so we punt on this one for now. TODO. + + # You should always have whitespace around binary operators. + # + # Check <= and >= first to avoid false positives with < and >, then + # check non-include lines for spacing around < and >. + # + # If the operator is followed by a comma, assume it's be used in a + # macro context and don't do any checks. This avoids false + # positives. + # + # Note that && is not included here. This is because there are too + # many false positives due to RValue references. + match = Search(r'[^<>=!\s](==|!=|<=|>=|\|\|)[^<>=!\s,;\)]', line) + if match: + error(filename, linenum, 'whitespace/operators', 3, + 'Missing spaces around %s' % match.group(1)) + elif not Match(r'#.*include', line): + # Look for < that is not surrounded by spaces. This is only + # triggered if both sides are missing spaces, even though + # technically should should flag if at least one side is missing a + # space. This is done to avoid some false positives with shifts. + match = Match(r'^(.*[^\s<])<[^\s=<,]', line) + if match: + (_, _, end_pos) = CloseExpression( + clean_lines, linenum, len(match.group(1))) + if end_pos <= -1: + error(filename, linenum, 'whitespace/operators', 3, + 'Missing spaces around <') + + # Look for > that is not surrounded by spaces. Similar to the + # above, we only trigger if both sides are missing spaces to avoid + # false positives with shifts. + match = Match(r'^(.*[^-\s>])>[^\s=>,]', line) + if match: + (_, _, start_pos) = ReverseCloseExpression( + clean_lines, linenum, len(match.group(1))) + if start_pos <= -1: + error(filename, linenum, 'whitespace/operators', 3, + 'Missing spaces around >') + + # We allow no-spaces around << when used like this: 10<<20, but + # not otherwise (particularly, not when used as streams) + # + # We also allow operators following an opening parenthesis, since + # those tend to be macros that deal with operators. + match = Search(r'(operator|[^\s(<])(?:L|UL|LL|ULL|l|ul|ll|ull)?<<([^\s,=<])', line) + if (match and not (match.group(1).isdigit() and match.group(2).isdigit()) and + not (match.group(1) == 'operator' and match.group(2) == ';')): + error(filename, linenum, 'whitespace/operators', 3, + 'Missing spaces around <<') + + # We allow no-spaces around >> for almost anything. This is because + # C++11 allows ">>" to close nested templates, which accounts for + # most cases when ">>" is not followed by a space. + # + # We still warn on ">>" followed by alpha character, because that is + # likely due to ">>" being used for right shifts, e.g.: + # value >> alpha + # + # When ">>" is used to close templates, the alphanumeric letter that + # follows would be part of an identifier, and there should still be + # a space separating the template type and the identifier. + # type> alpha + match = Search(r'>>[a-zA-Z_]', line) + if match: + error(filename, linenum, 'whitespace/operators', 3, + 'Missing spaces around >>') + + # There shouldn't be space around unary operators + match = Search(r'(!\s|~\s|[\s]--[\s;]|[\s]\+\+[\s;])', line) + if match: + error(filename, linenum, 'whitespace/operators', 4, + 'Extra space for operator %s' % match.group(1)) + + +def CheckParenthesisSpacing(filename, clean_lines, linenum, error): + """Checks for horizontal spacing around parentheses. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + line = clean_lines.elided[linenum] + + # No spaces after an if, while, switch, or for + match = Search(r' (if\(|for\(|while\(|switch\()', line) + if match: + error(filename, linenum, 'whitespace/parens', 5, + 'Missing space before ( in %s' % match.group(1)) + + # For if/for/while/switch, the left and right parens should be + # consistent about how many spaces are inside the parens, and + # there should either be zero or one spaces inside the parens. + # We don't want: "if ( foo)" or "if ( foo )". + # Exception: "for ( ; foo; bar)" and "for (foo; bar; )" are allowed. + match = Search(r'\b(if|for|while|switch)\s*' + r'\(([ ]*)(.).*[^ ]+([ ]*)\)\s*{\s*$', + line) + if match: + if len(match.group(2)) != len(match.group(4)): + if not (match.group(3) == ';' and + len(match.group(2)) == 1 + len(match.group(4)) or + not match.group(2) and Search(r'\bfor\s*\(.*; \)', line)): + error(filename, linenum, 'whitespace/parens', 5, + 'Mismatching spaces inside () in %s' % match.group(1)) + if len(match.group(2)) not in [0, 1]: + error(filename, linenum, 'whitespace/parens', 5, + 'Should have zero or one spaces inside ( and ) in %s' % + match.group(1)) + + +def CheckCommaSpacing(filename, clean_lines, linenum, error): + """Checks for horizontal spacing near commas and semicolons. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + raw = clean_lines.lines_without_raw_strings + line = clean_lines.elided[linenum] + + # You should always have a space after a comma (either as fn arg or operator) + # + # This does not apply when the non-space character following the + # comma is another comma, since the only time when that happens is + # for empty macro arguments. + # + # We run this check in two passes: first pass on elided lines to + # verify that lines contain missing whitespaces, second pass on raw + # lines to confirm that those missing whitespaces are not due to + # elided comments. + if (Search(r',[^,\s]', ReplaceAll(r'\boperator\s*,\s*\(', 'F(', line)) and + Search(r',[^,\s]', raw[linenum])): + error(filename, linenum, 'whitespace/comma', 3, + 'Missing space after ,') + + # You should always have a space after a semicolon + # except for few corner cases + # TODO(unknown): clarify if 'if (1) { return 1;}' is requires one more + # space after ; + if Search(r';[^\s};\\)/]', line): + error(filename, linenum, 'whitespace/semicolon', 3, + 'Missing space after ;') + + +def _IsType(clean_lines, nesting_state, expr): + """Check if expression looks like a type name, returns true if so. + + Args: + clean_lines: A CleansedLines instance containing the file. + nesting_state: A NestingState instance which maintains information about + the current stack of nested blocks being parsed. + expr: The expression to check. + Returns: + True, if token looks like a type. + """ + # Keep only the last token in the expression + last_word = Match(r'^.*(\b\S+)$', expr) + if last_word: + token = last_word.group(1) + else: + token = expr + + # Match native types and stdint types + if _TYPES.match(token): + return True + + # Try a bit harder to match templated types. Walk up the nesting + # stack until we find something that resembles a typename + # declaration for what we are looking for. + typename_pattern = (r'\b(?:typename|class|struct)\s+' + re.escape(token) + + r'\b') + block_index = len(nesting_state.stack) - 1 + while block_index >= 0: + if isinstance(nesting_state.stack[block_index], _NamespaceInfo): + return False + + # Found where the opening brace is. We want to scan from this + # line up to the beginning of the function, minus a few lines. + # template + # class C + # : public ... { // start scanning here + last_line = nesting_state.stack[block_index].starting_linenum + + next_block_start = 0 + if block_index > 0: + next_block_start = nesting_state.stack[block_index - 1].starting_linenum + first_line = last_line + while first_line >= next_block_start: + if clean_lines.elided[first_line].find('template') >= 0: + break + first_line -= 1 + if first_line < next_block_start: + # Didn't find any "template" keyword before reaching the next block, + # there are probably no template things to check for this block + block_index -= 1 + continue + + # Look for typename in the specified range + for i in xrange(first_line, last_line + 1, 1): + if Search(typename_pattern, clean_lines.elided[i]): + return True + block_index -= 1 + + return False + + +def CheckBracesSpacing(filename, clean_lines, linenum, nesting_state, error): + """Checks for horizontal spacing near commas. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + nesting_state: A NestingState instance which maintains information about + the current stack of nested blocks being parsed. + error: The function to call with any errors found. + """ + line = clean_lines.elided[linenum] + + # Except after an opening paren, or after another opening brace (in case of + # an initializer list, for instance), you should have spaces before your + # braces when they are delimiting blocks, classes, namespaces etc. + # And since you should never have braces at the beginning of a line, + # this is an easy test. Except that braces used for initialization don't + # follow the same rule; we often don't want spaces before those. + match = Match(r'^(.*[^ ({>]){', line) + + if match: + # Try a bit harder to check for brace initialization. This + # happens in one of the following forms: + # Constructor() : initializer_list_{} { ... } + # Constructor{}.MemberFunction() + # Type variable{}; + # FunctionCall(type{}, ...); + # LastArgument(..., type{}); + # LOG(INFO) << type{} << " ..."; + # map_of_type[{...}] = ...; + # ternary = expr ? new type{} : nullptr; + # OuterTemplate{}> + # + # We check for the character following the closing brace, and + # silence the warning if it's one of those listed above, i.e. + # "{.;,)<>]:". + # + # To account for nested initializer list, we allow any number of + # closing braces up to "{;,)<". We can't simply silence the + # warning on first sight of closing brace, because that would + # cause false negatives for things that are not initializer lists. + # Silence this: But not this: + # Outer{ if (...) { + # Inner{...} if (...){ // Missing space before { + # }; } + # + # There is a false negative with this approach if people inserted + # spurious semicolons, e.g. "if (cond){};", but we will catch the + # spurious semicolon with a separate check. + leading_text = match.group(1) + (endline, endlinenum, endpos) = CloseExpression( + clean_lines, linenum, len(match.group(1))) + trailing_text = '' + if endpos > -1: + trailing_text = endline[endpos:] + for offset in xrange(endlinenum + 1, + min(endlinenum + 3, clean_lines.NumLines() - 1)): + trailing_text += clean_lines.elided[offset] + # We also suppress warnings for `uint64_t{expression}` etc., as the style + # guide recommends brace initialization for integral types to avoid + # overflow/truncation. + if (not Match(r'^[\s}]*[{.;,)<>\]:]', trailing_text) + and not _IsType(clean_lines, nesting_state, leading_text)): + error(filename, linenum, 'whitespace/braces', 5, + 'Missing space before {') + + # Make sure '} else {' has spaces. + if Search(r'}else', line): + error(filename, linenum, 'whitespace/braces', 5, + 'Missing space before else') + + # You shouldn't have a space before a semicolon at the end of the line. + # There's a special case for "for" since the style guide allows space before + # the semicolon there. + if Search(r':\s*;\s*$', line): + error(filename, linenum, 'whitespace/semicolon', 5, + 'Semicolon defining empty statement. Use {} instead.') + elif Search(r'^\s*;\s*$', line): + error(filename, linenum, 'whitespace/semicolon', 5, + 'Line contains only semicolon. If this should be an empty statement, ' + 'use {} instead.') + elif (Search(r'\s+;\s*$', line) and + not Search(r'\bfor\b', line)): + error(filename, linenum, 'whitespace/semicolon', 5, + 'Extra space before last semicolon. If this should be an empty ' + 'statement, use {} instead.') + + +def IsDecltype(clean_lines, linenum, column): + """Check if the token ending on (linenum, column) is decltype(). + + Args: + clean_lines: A CleansedLines instance containing the file. + linenum: the number of the line to check. + column: end column of the token to check. + Returns: + True if this token is decltype() expression, False otherwise. + """ + (text, _, start_col) = ReverseCloseExpression(clean_lines, linenum, column) + if start_col < 0: + return False + if Search(r'\bdecltype\s*$', text[0:start_col]): + return True + return False + +def CheckSectionSpacing(filename, clean_lines, class_info, linenum, error): + """Checks for additional blank line issues related to sections. + + Currently the only thing checked here is blank line before protected/private. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + class_info: A _ClassInfo objects. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + # Skip checks if the class is small, where small means 25 lines or less. + # 25 lines seems like a good cutoff since that's the usual height of + # terminals, and any class that can't fit in one screen can't really + # be considered "small". + # + # Also skip checks if we are on the first line. This accounts for + # classes that look like + # class Foo { public: ... }; + # + # If we didn't find the end of the class, last_line would be zero, + # and the check will be skipped by the first condition. + if (class_info.last_line - class_info.starting_linenum <= 24 or + linenum <= class_info.starting_linenum): + return + + matched = Match(r'\s*(public|protected|private):', clean_lines.lines[linenum]) + if matched: + # Issue warning if the line before public/protected/private was + # not a blank line, but don't do this if the previous line contains + # "class" or "struct". This can happen two ways: + # - We are at the beginning of the class. + # - We are forward-declaring an inner class that is semantically + # private, but needed to be public for implementation reasons. + # Also ignores cases where the previous line ends with a backslash as can be + # common when defining classes in C macros. + prev_line = clean_lines.lines[linenum - 1] + if (not IsBlankLine(prev_line) and + not Search(r'\b(class|struct)\b', prev_line) and + not Search(r'\\$', prev_line)): + # Try a bit harder to find the beginning of the class. This is to + # account for multi-line base-specifier lists, e.g.: + # class Derived + # : public Base { + end_class_head = class_info.starting_linenum + for i in range(class_info.starting_linenum, linenum): + if Search(r'\{\s*$', clean_lines.lines[i]): + end_class_head = i + break + if end_class_head < linenum - 1: + error(filename, linenum, 'whitespace/blank_line', 3, + '"%s:" should be preceded by a blank line' % matched.group(1)) + + +def GetPreviousNonBlankLine(clean_lines, linenum): + """Return the most recent non-blank line and its line number. + + Args: + clean_lines: A CleansedLines instance containing the file contents. + linenum: The number of the line to check. + + Returns: + A tuple with two elements. The first element is the contents of the last + non-blank line before the current line, or the empty string if this is the + first non-blank line. The second is the line number of that line, or -1 + if this is the first non-blank line. + """ + + prevlinenum = linenum - 1 + while prevlinenum >= 0: + prevline = clean_lines.elided[prevlinenum] + if not IsBlankLine(prevline): # if not a blank line... + return (prevline, prevlinenum) + prevlinenum -= 1 + return ('', -1) + + +def CheckBraces(filename, clean_lines, linenum, error): + """Looks for misplaced braces (e.g. at the end of line). + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + + line = clean_lines.elided[linenum] # get rid of comments and strings + + if Match(r'\s*{\s*$', line): + # We allow an open brace to start a line in the case where someone is using + # braces in a block to explicitly create a new scope, which is commonly used + # to control the lifetime of stack-allocated variables. Braces are also + # used for brace initializers inside function calls. We don't detect this + # perfectly: we just don't complain if the last non-whitespace character on + # the previous non-blank line is ',', ';', ':', '(', '{', or '}', or if the + # previous line starts a preprocessor block. We also allow a brace on the + # following line if it is part of an array initialization and would not fit + # within the 80 character limit of the preceding line. + prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0] + if (not Search(r'[,;:}{(]\s*$', prevline) and + not Match(r'\s*#', prevline) and + not (GetLineWidth(prevline) > _line_length - 2 and '[]' in prevline)): + error(filename, linenum, 'whitespace/braces', 4, + '{ should almost always be at the end of the previous line') + + # An else clause should be on the same line as the preceding closing brace. + if Match(r'\s*else\b\s*(?:if\b|\{|$)', line): + prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0] + if Match(r'\s*}\s*$', prevline): + error(filename, linenum, 'whitespace/newline', 4, + 'An else should appear on the same line as the preceding }') + + # If braces come on one side of an else, they should be on both. + # However, we have to worry about "else if" that spans multiple lines! + if Search(r'else if\s*\(', line): # could be multi-line if + brace_on_left = bool(Search(r'}\s*else if\s*\(', line)) + # find the ( after the if + pos = line.find('else if') + pos = line.find('(', pos) + if pos > 0: + (endline, _, endpos) = CloseExpression(clean_lines, linenum, pos) + brace_on_right = endline[endpos:].find('{') != -1 + if brace_on_left != brace_on_right: # must be brace after if + error(filename, linenum, 'readability/braces', 5, + 'If an else has a brace on one side, it should have it on both') + elif Search(r'}\s*else[^{]*$', line) or Match(r'[^}]*else\s*{', line): + error(filename, linenum, 'readability/braces', 5, + 'If an else has a brace on one side, it should have it on both') + + # Likewise, an else should never have the else clause on the same line + if Search(r'\belse [^\s{]', line) and not Search(r'\belse if\b', line): + error(filename, linenum, 'whitespace/newline', 4, + 'Else clause should never be on same line as else (use 2 lines)') + + # In the same way, a do/while should never be on one line + if Match(r'\s*do [^\s{]', line): + error(filename, linenum, 'whitespace/newline', 4, + 'do/while clauses should not be on a single line') + + # Check single-line if/else bodies. The style guide says 'curly braces are not + # required for single-line statements'. We additionally allow multi-line, + # single statements, but we reject anything with more than one semicolon in + # it. This means that the first semicolon after the if should be at the end of + # its line, and the line after that should have an indent level equal to or + # lower than the if. We also check for ambiguous if/else nesting without + # braces. + if_else_match = Search(r'\b(if\s*(|constexpr)\s*\(|else\b)', line) + if if_else_match and not Match(r'\s*#', line): + if_indent = GetIndentLevel(line) + endline, endlinenum, endpos = line, linenum, if_else_match.end() + if_match = Search(r'\bif\s*(|constexpr)\s*\(', line) + if if_match: + # This could be a multiline if condition, so find the end first. + pos = if_match.end() - 1 + (endline, endlinenum, endpos) = CloseExpression(clean_lines, linenum, pos) + # Check for an opening brace, either directly after the if or on the next + # line. If found, this isn't a single-statement conditional. + if (not Match(r'\s*{', endline[endpos:]) + and not (Match(r'\s*$', endline[endpos:]) + and endlinenum < (len(clean_lines.elided) - 1) + and Match(r'\s*{', clean_lines.elided[endlinenum + 1]))): + while (endlinenum < len(clean_lines.elided) + and ';' not in clean_lines.elided[endlinenum][endpos:]): + endlinenum += 1 + endpos = 0 + if endlinenum < len(clean_lines.elided): + endline = clean_lines.elided[endlinenum] + # We allow a mix of whitespace and closing braces (e.g. for one-liner + # methods) and a single \ after the semicolon (for macros) + endpos = endline.find(';') + if not Match(r';[\s}]*(\\?)$', endline[endpos:]): + # Semicolon isn't the last character, there's something trailing. + # Output a warning if the semicolon is not contained inside + # a lambda expression. + if not Match(r'^[^{};]*\[[^\[\]]*\][^{}]*\{[^{}]*\}\s*\)*[;,]\s*$', + endline): + error(filename, linenum, 'readability/braces', 4, + 'If/else bodies with multiple statements require braces') + elif endlinenum < len(clean_lines.elided) - 1: + # Make sure the next line is dedented + next_line = clean_lines.elided[endlinenum + 1] + next_indent = GetIndentLevel(next_line) + # With ambiguous nested if statements, this will error out on the + # if that *doesn't* match the else, regardless of whether it's the + # inner one or outer one. + if (if_match and Match(r'\s*else\b', next_line) + and next_indent != if_indent): + error(filename, linenum, 'readability/braces', 4, + 'Else clause should be indented at the same level as if. ' + 'Ambiguous nested if/else chains require braces.') + elif next_indent > if_indent: + error(filename, linenum, 'readability/braces', 4, + 'If/else bodies with multiple statements require braces') + + +def CheckTrailingSemicolon(filename, clean_lines, linenum, error): + """Looks for redundant trailing semicolon. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + + line = clean_lines.elided[linenum] + + # Block bodies should not be followed by a semicolon. Due to C++11 + # brace initialization, there are more places where semicolons are + # required than not, so we explicitly list the allowed rules rather + # than listing the disallowed ones. These are the places where "};" + # should be replaced by just "}": + # 1. Some flavor of block following closing parenthesis: + # for (;;) {}; + # while (...) {}; + # switch (...) {}; + # Function(...) {}; + # if (...) {}; + # if (...) else if (...) {}; + # + # 2. else block: + # if (...) else {}; + # + # 3. const member function: + # Function(...) const {}; + # + # 4. Block following some statement: + # x = 42; + # {}; + # + # 5. Block at the beginning of a function: + # Function(...) { + # {}; + # } + # + # Note that naively checking for the preceding "{" will also match + # braces inside multi-dimensional arrays, but this is fine since + # that expression will not contain semicolons. + # + # 6. Block following another block: + # while (true) {} + # {}; + # + # 7. End of namespaces: + # namespace {}; + # + # These semicolons seems far more common than other kinds of + # redundant semicolons, possibly due to people converting classes + # to namespaces. For now we do not warn for this case. + # + # Try matching case 1 first. + match = Match(r'^(.*\)\s*)\{', line) + if match: + # Matched closing parenthesis (case 1). Check the token before the + # matching opening parenthesis, and don't warn if it looks like a + # macro. This avoids these false positives: + # - macro that defines a base class + # - multi-line macro that defines a base class + # - macro that defines the whole class-head + # + # But we still issue warnings for macros that we know are safe to + # warn, specifically: + # - TEST, TEST_F, TEST_P, MATCHER, MATCHER_P + # - TYPED_TEST + # - INTERFACE_DEF + # - EXCLUSIVE_LOCKS_REQUIRED, SHARED_LOCKS_REQUIRED, LOCKS_EXCLUDED: + # + # We implement a list of safe macros instead of a list of + # unsafe macros, even though the latter appears less frequently in + # google code and would have been easier to implement. This is because + # the downside for getting the allowed checks wrong means some extra + # semicolons, while the downside for getting disallowed checks wrong + # would result in compile errors. + # + # In addition to macros, we also don't want to warn on + # - Compound literals + # - Lambdas + # - alignas specifier with anonymous structs + # - decltype + closing_brace_pos = match.group(1).rfind(')') + opening_parenthesis = ReverseCloseExpression( + clean_lines, linenum, closing_brace_pos) + if opening_parenthesis[2] > -1: + line_prefix = opening_parenthesis[0][0:opening_parenthesis[2]] + macro = Search(r'\b([A-Z_][A-Z0-9_]*)\s*$', line_prefix) + func = Match(r'^(.*\])\s*$', line_prefix) + if ((macro and + macro.group(1) not in ( + 'TEST', 'TEST_F', 'MATCHER', 'MATCHER_P', 'TYPED_TEST', + 'EXCLUSIVE_LOCKS_REQUIRED', 'SHARED_LOCKS_REQUIRED', + 'LOCKS_EXCLUDED', 'INTERFACE_DEF')) or + (func and not Search(r'\boperator\s*\[\s*\]', func.group(1))) or + Search(r'\b(?:struct|union)\s+alignas\s*$', line_prefix) or + Search(r'\bdecltype$', line_prefix) or + Search(r'\s+=\s*$', line_prefix)): + match = None + if (match and + opening_parenthesis[1] > 1 and + Search(r'\]\s*$', clean_lines.elided[opening_parenthesis[1] - 1])): + # Multi-line lambda-expression + match = None + + else: + # Try matching cases 2-3. + match = Match(r'^(.*(?:else|\)\s*const)\s*)\{', line) + if not match: + # Try matching cases 4-6. These are always matched on separate lines. + # + # Note that we can't simply concatenate the previous line to the + # current line and do a single match, otherwise we may output + # duplicate warnings for the blank line case: + # if (cond) { + # // blank line + # } + prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0] + if prevline and Search(r'[;{}]\s*$', prevline): + match = Match(r'^(\s*)\{', line) + + # Check matching closing brace + if match: + (endline, endlinenum, endpos) = CloseExpression( + clean_lines, linenum, len(match.group(1))) + if endpos > -1 and Match(r'^\s*;', endline[endpos:]): + # Current {} pair is eligible for semicolon check, and we have found + # the redundant semicolon, output warning here. + # + # Note: because we are scanning forward for opening braces, and + # outputting warnings for the matching closing brace, if there are + # nested blocks with trailing semicolons, we will get the error + # messages in reversed order. + + # We need to check the line forward for NOLINT + raw_lines = clean_lines.raw_lines + ParseNolintSuppressions(filename, raw_lines[endlinenum-1], endlinenum-1, + error) + ParseNolintSuppressions(filename, raw_lines[endlinenum], endlinenum, + error) + + error(filename, endlinenum, 'readability/braces', 4, + "You don't need a ; after a }") + + +def CheckEmptyBlockBody(filename, clean_lines, linenum, error): + """Look for empty loop/conditional body with only a single semicolon. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + + # Search for loop keywords at the beginning of the line. Because only + # whitespaces are allowed before the keywords, this will also ignore most + # do-while-loops, since those lines should start with closing brace. + # + # We also check "if" blocks here, since an empty conditional block + # is likely an error. + line = clean_lines.elided[linenum] + matched = Match(r'\s*(for|while|if)\s*\(', line) + if matched: + # Find the end of the conditional expression. + (end_line, end_linenum, end_pos) = CloseExpression( + clean_lines, linenum, line.find('(')) + + # Output warning if what follows the condition expression is a semicolon. + # No warning for all other cases, including whitespace or newline, since we + # have a separate check for semicolons preceded by whitespace. + if end_pos >= 0 and Match(r';', end_line[end_pos:]): + if matched.group(1) == 'if': + error(filename, end_linenum, 'whitespace/empty_conditional_body', 5, + 'Empty conditional bodies should use {}') + else: + error(filename, end_linenum, 'whitespace/empty_loop_body', 5, + 'Empty loop bodies should use {} or continue') + + # Check for if statements that have completely empty bodies (no comments) + # and no else clauses. + if end_pos >= 0 and matched.group(1) == 'if': + # Find the position of the opening { for the if statement. + # Return without logging an error if it has no brackets. + opening_linenum = end_linenum + opening_line_fragment = end_line[end_pos:] + # Loop until EOF or find anything that's not whitespace or opening {. + while not Search(r'^\s*\{', opening_line_fragment): + if Search(r'^(?!\s*$)', opening_line_fragment): + # Conditional has no brackets. + return + opening_linenum += 1 + if opening_linenum == len(clean_lines.elided): + # Couldn't find conditional's opening { or any code before EOF. + return + opening_line_fragment = clean_lines.elided[opening_linenum] + # Set opening_line (opening_line_fragment may not be entire opening line). + opening_line = clean_lines.elided[opening_linenum] + + # Find the position of the closing }. + opening_pos = opening_line_fragment.find('{') + if opening_linenum == end_linenum: + # We need to make opening_pos relative to the start of the entire line. + opening_pos += end_pos + (closing_line, closing_linenum, closing_pos) = CloseExpression( + clean_lines, opening_linenum, opening_pos) + if closing_pos < 0: + return + + # Now construct the body of the conditional. This consists of the portion + # of the opening line after the {, all lines until the closing line, + # and the portion of the closing line before the }. + if (clean_lines.raw_lines[opening_linenum] != + CleanseComments(clean_lines.raw_lines[opening_linenum])): + # Opening line ends with a comment, so conditional isn't empty. + return + if closing_linenum > opening_linenum: + # Opening line after the {. Ignore comments here since we checked above. + bodylist = list(opening_line[opening_pos+1:]) + # All lines until closing line, excluding closing line, with comments. + bodylist.extend(clean_lines.raw_lines[opening_linenum+1:closing_linenum]) + # Closing line before the }. Won't (and can't) have comments. + bodylist.append(clean_lines.elided[closing_linenum][:closing_pos-1]) + body = '\n'.join(bodylist) + else: + # If statement has brackets and fits on a single line. + body = opening_line[opening_pos+1:closing_pos-1] + + # Check if the body is empty + if not _EMPTY_CONDITIONAL_BODY_PATTERN.search(body): + return + # The body is empty. Now make sure there's not an else clause. + current_linenum = closing_linenum + current_line_fragment = closing_line[closing_pos:] + # Loop until EOF or find anything that's not whitespace or else clause. + while Search(r'^\s*$|^(?=\s*else)', current_line_fragment): + if Search(r'^(?=\s*else)', current_line_fragment): + # Found an else clause, so don't log an error. + return + current_linenum += 1 + if current_linenum == len(clean_lines.elided): + break + current_line_fragment = clean_lines.elided[current_linenum] + + # The body is empty and there's no else clause until EOF or other code. + error(filename, end_linenum, 'whitespace/empty_if_body', 4, + ('If statement had no body and no else clause')) + + +def FindCheckMacro(line): + """Find a replaceable CHECK-like macro. + + Args: + line: line to search on. + Returns: + (macro name, start position), or (None, -1) if no replaceable + macro is found. + """ + for macro in _CHECK_MACROS: + i = line.find(macro) + if i >= 0: + # Find opening parenthesis. Do a regular expression match here + # to make sure that we are matching the expected CHECK macro, as + # opposed to some other macro that happens to contain the CHECK + # substring. + matched = Match(r'^(.*\b' + macro + r'\s*)\(', line) + if not matched: + continue + return (macro, len(matched.group(1))) + return (None, -1) + + +def CheckCheck(filename, clean_lines, linenum, error): + """Checks the use of CHECK and EXPECT macros. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + + # Decide the set of replacement macros that should be suggested + lines = clean_lines.elided + (check_macro, start_pos) = FindCheckMacro(lines[linenum]) + if not check_macro: + return + + # Find end of the boolean expression by matching parentheses + (last_line, end_line, end_pos) = CloseExpression( + clean_lines, linenum, start_pos) + if end_pos < 0: + return + + # If the check macro is followed by something other than a + # semicolon, assume users will log their own custom error messages + # and don't suggest any replacements. + if not Match(r'\s*;', last_line[end_pos:]): + return + + if linenum == end_line: + expression = lines[linenum][start_pos + 1:end_pos - 1] + else: + expression = lines[linenum][start_pos + 1:] + for i in xrange(linenum + 1, end_line): + expression += lines[i] + expression += last_line[0:end_pos - 1] + + # Parse expression so that we can take parentheses into account. + # This avoids false positives for inputs like "CHECK((a < 4) == b)", + # which is not replaceable by CHECK_LE. + lhs = '' + rhs = '' + operator = None + while expression: + matched = Match(r'^\s*(<<|<<=|>>|>>=|->\*|->|&&|\|\||' + r'==|!=|>=|>|<=|<|\()(.*)$', expression) + if matched: + token = matched.group(1) + if token == '(': + # Parenthesized operand + expression = matched.group(2) + (end, _) = FindEndOfExpressionInLine(expression, 0, ['(']) + if end < 0: + return # Unmatched parenthesis + lhs += '(' + expression[0:end] + expression = expression[end:] + elif token in ('&&', '||'): + # Logical and/or operators. This means the expression + # contains more than one term, for example: + # CHECK(42 < a && a < b); + # + # These are not replaceable with CHECK_LE, so bail out early. + return + elif token in ('<<', '<<=', '>>', '>>=', '->*', '->'): + # Non-relational operator + lhs += token + expression = matched.group(2) + else: + # Relational operator + operator = token + rhs = matched.group(2) + break + else: + # Unparenthesized operand. Instead of appending to lhs one character + # at a time, we do another regular expression match to consume several + # characters at once if possible. Trivial benchmark shows that this + # is more efficient when the operands are longer than a single + # character, which is generally the case. + matched = Match(r'^([^-=!<>()&|]+)(.*)$', expression) + if not matched: + matched = Match(r'^(\s*\S)(.*)$', expression) + if not matched: + break + lhs += matched.group(1) + expression = matched.group(2) + + # Only apply checks if we got all parts of the boolean expression + if not (lhs and operator and rhs): + return + + # Check that rhs do not contain logical operators. We already know + # that lhs is fine since the loop above parses out && and ||. + if rhs.find('&&') > -1 or rhs.find('||') > -1: + return + + # At least one of the operands must be a constant literal. This is + # to avoid suggesting replacements for unprintable things like + # CHECK(variable != iterator) + # + # The following pattern matches decimal, hex integers, strings, and + # characters (in that order). + lhs = lhs.strip() + rhs = rhs.strip() + match_constant = r'^([-+]?(\d+|0[xX][0-9a-fA-F]+)[lLuU]{0,3}|".*"|\'.*\')$' + if Match(match_constant, lhs) or Match(match_constant, rhs): + # Note: since we know both lhs and rhs, we can provide a more + # descriptive error message like: + # Consider using CHECK_EQ(x, 42) instead of CHECK(x == 42) + # Instead of: + # Consider using CHECK_EQ instead of CHECK(a == b) + # + # We are still keeping the less descriptive message because if lhs + # or rhs gets long, the error message might become unreadable. + error(filename, linenum, 'readability/check', 2, + 'Consider using %s instead of %s(a %s b)' % ( + _CHECK_REPLACEMENT[check_macro][operator], + check_macro, operator)) + + +def CheckAltTokens(filename, clean_lines, linenum, error): + """Check alternative keywords being used in boolean expressions. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + line = clean_lines.elided[linenum] + + # Avoid preprocessor lines + if Match(r'^\s*#', line): + return + + # Last ditch effort to avoid multi-line comments. This will not help + # if the comment started before the current line or ended after the + # current line, but it catches most of the false positives. At least, + # it provides a way to workaround this warning for people who use + # multi-line comments in preprocessor macros. + # + # TODO(unknown): remove this once cpplint has better support for + # multi-line comments. + if line.find('/*') >= 0 or line.find('*/') >= 0: + return + + for match in _ALT_TOKEN_REPLACEMENT_PATTERN.finditer(line): + error(filename, linenum, 'readability/alt_tokens', 2, + 'Use operator %s instead of %s' % ( + _ALT_TOKEN_REPLACEMENT[match.group(1)], match.group(1))) + + +def GetLineWidth(line): + """Determines the width of the line in column positions. + + Args: + line: A string, which may be a Unicode string. + + Returns: + The width of the line in column positions, accounting for Unicode + combining characters and wide characters. + """ + if isinstance(line, unicode): + width = 0 + for uc in unicodedata.normalize('NFC', line): + if unicodedata.east_asian_width(uc) in ('W', 'F'): + width += 2 + elif not unicodedata.combining(uc): + # Issue 337 + # https://mail.python.org/pipermail/python-list/2012-August/628809.html + if (sys.version_info.major, sys.version_info.minor) <= (3, 2): + # https://github.com/python/cpython/blob/2.7/Include/unicodeobject.h#L81 + is_wide_build = sysconfig.get_config_var("Py_UNICODE_SIZE") >= 4 + # https://github.com/python/cpython/blob/2.7/Objects/unicodeobject.c#L564 + is_low_surrogate = 0xDC00 <= ord(uc) <= 0xDFFF + if not is_wide_build and is_low_surrogate: + width -= 1 + + width += 1 + return width + else: + return len(line) + + +def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state, + error): + """Checks rules from the 'C++ style rules' section of cppguide.html. + + Most of these rules are hard to test (naming, comment style), but we + do what we can. In particular we check for 2-space indents, line lengths, + tab usage, spaces inside code, etc. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + file_extension: The extension (without the dot) of the filename. + nesting_state: A NestingState instance which maintains information about + the current stack of nested blocks being parsed. + error: The function to call with any errors found. + """ + + # Don't use "elided" lines here, otherwise we can't check commented lines. + # Don't want to use "raw" either, because we don't want to check inside C++11 + # raw strings, + raw_lines = clean_lines.lines_without_raw_strings + line = raw_lines[linenum] + prev = raw_lines[linenum - 1] if linenum > 0 else '' + + if line.find('\t') != -1: + error(filename, linenum, 'whitespace/tab', 1, + 'Tab found; better to use spaces') + + # One or three blank spaces at the beginning of the line is weird; it's + # hard to reconcile that with 2-space indents. + # NOTE: here are the conditions rob pike used for his tests. Mine aren't + # as sophisticated, but it may be worth becoming so: RLENGTH==initial_spaces + # if(RLENGTH > 20) complain = 0; + # if(match($0, " +(error|private|public|protected):")) complain = 0; + # if(match(prev, "&& *$")) complain = 0; + # if(match(prev, "\\|\\| *$")) complain = 0; + # if(match(prev, "[\",=><] *$")) complain = 0; + # if(match($0, " <<")) complain = 0; + # if(match(prev, " +for \\(")) complain = 0; + # if(prevodd && match(prevprev, " +for \\(")) complain = 0; + scope_or_label_pattern = r'\s*(?:public|private|protected|signals)(?:\s+(?:slots\s*)?)?:\s*\\?$' + classinfo = nesting_state.InnermostClass() + initial_spaces = 0 + cleansed_line = clean_lines.elided[linenum] + while initial_spaces < len(line) and line[initial_spaces] == ' ': + initial_spaces += 1 + # There are certain situations we allow one space, notably for + # section labels, and also lines containing multi-line raw strings. + # We also don't check for lines that look like continuation lines + # (of lines ending in double quotes, commas, equals, or angle brackets) + # because the rules for how to indent those are non-trivial. + if (not Search(r'[",=><] *$', prev) and + (initial_spaces == 1 or initial_spaces == 3) and + not Match(scope_or_label_pattern, cleansed_line) and + not (clean_lines.raw_lines[linenum] != line and + Match(r'^\s*""', line))): + error(filename, linenum, 'whitespace/indent', 3, + 'Weird number of spaces at line-start. ' + 'Are you using a 2-space indent?') + + if line and line[-1].isspace(): + error(filename, linenum, 'whitespace/end_of_line', 4, + 'Line ends in whitespace. Consider deleting these extra spaces.') + + # Check if the line is a header guard. + is_header_guard = False + if IsHeaderExtension(file_extension): + cppvar = GetHeaderGuardCPPVariable(filename) + if (line.startswith('#ifndef %s' % cppvar) or + line.startswith('#define %s' % cppvar) or + line.startswith('#endif // %s' % cppvar)): + is_header_guard = True + # #include lines and header guards can be long, since there's no clean way to + # split them. + # + # URLs can be long too. It's possible to split these, but it makes them + # harder to cut&paste. + # + # The "$Id:...$" comment may also get very long without it being the + # developers fault. + # + # Doxygen documentation copying can get pretty long when using an overloaded + # function declaration + if (not line.startswith('#include') and not is_header_guard and + not Match(r'^\s*//.*http(s?)://\S*$', line) and + not Match(r'^\s*//\s*[^\s]*$', line) and + not Match(r'^// \$Id:.*#[0-9]+ \$$', line) and + not Match(r'^\s*/// [@\\](copydoc|copydetails|copybrief) .*$', line)): + line_width = GetLineWidth(line) + if line_width > _line_length: + error(filename, linenum, 'whitespace/line_length', 2, + 'Lines should be <= %i characters long' % _line_length) + + if (cleansed_line.count(';') > 1 and + # allow simple single line lambdas + not Match(r'^[^{};]*\[[^\[\]]*\][^{}]*\{[^{}\n\r]*\}', + line) and + # for loops are allowed two ;'s (and may run over two lines). + cleansed_line.find('for') == -1 and + (GetPreviousNonBlankLine(clean_lines, linenum)[0].find('for') == -1 or + GetPreviousNonBlankLine(clean_lines, linenum)[0].find(';') != -1) and + # It's ok to have many commands in a switch case that fits in 1 line + not ((cleansed_line.find('case ') != -1 or + cleansed_line.find('default:') != -1) and + cleansed_line.find('break;') != -1)): + error(filename, linenum, 'whitespace/newline', 0, + 'More than one command on the same line') + + # Some more style checks + CheckBraces(filename, clean_lines, linenum, error) + CheckTrailingSemicolon(filename, clean_lines, linenum, error) + CheckEmptyBlockBody(filename, clean_lines, linenum, error) + CheckSpacing(filename, clean_lines, linenum, nesting_state, error) + CheckOperatorSpacing(filename, clean_lines, linenum, error) + CheckParenthesisSpacing(filename, clean_lines, linenum, error) + CheckCommaSpacing(filename, clean_lines, linenum, error) + CheckBracesSpacing(filename, clean_lines, linenum, nesting_state, error) + CheckSpacingForFunctionCall(filename, clean_lines, linenum, error) + CheckCheck(filename, clean_lines, linenum, error) + CheckAltTokens(filename, clean_lines, linenum, error) + classinfo = nesting_state.InnermostClass() + if classinfo: + CheckSectionSpacing(filename, clean_lines, classinfo, linenum, error) + + +_RE_PATTERN_INCLUDE = re.compile(r'^\s*#\s*include\s*([<"])([^>"]*)[>"].*$') +# Matches the first component of a filename delimited by -s and _s. That is: +# _RE_FIRST_COMPONENT.match('foo').group(0) == 'foo' +# _RE_FIRST_COMPONENT.match('foo.cc').group(0) == 'foo' +# _RE_FIRST_COMPONENT.match('foo-bar_baz.cc').group(0) == 'foo' +# _RE_FIRST_COMPONENT.match('foo_bar-baz.cc').group(0) == 'foo' +_RE_FIRST_COMPONENT = re.compile(r'^[^-_.]+') + + +def _DropCommonSuffixes(filename): + """Drops common suffixes like _test.cc or -inl.h from filename. + + For example: + >>> _DropCommonSuffixes('foo/foo-inl.h') + 'foo/foo' + >>> _DropCommonSuffixes('foo/bar/foo.cc') + 'foo/bar/foo' + >>> _DropCommonSuffixes('foo/foo_internal.h') + 'foo/foo' + >>> _DropCommonSuffixes('foo/foo_unusualinternal.h') + 'foo/foo_unusualinternal' + + Args: + filename: The input filename. + + Returns: + The filename with the common suffix removed. + """ + for suffix in itertools.chain( + ('%s.%s' % (test_suffix.lstrip('_'), ext) + for test_suffix, ext in itertools.product(_test_suffixes, GetNonHeaderExtensions())), + ('%s.%s' % (suffix, ext) + for suffix, ext in itertools.product(['inl', 'imp', 'internal'], GetHeaderExtensions()))): + if (filename.endswith(suffix) and len(filename) > len(suffix) and + filename[-len(suffix) - 1] in ('-', '_')): + return filename[:-len(suffix) - 1] + return os.path.splitext(filename)[0] + + +def _ClassifyInclude(fileinfo, include, used_angle_brackets, include_order="default"): + """Figures out what kind of header 'include' is. + + Args: + fileinfo: The current file cpplint is running over. A FileInfo instance. + include: The path to a #included file. + used_angle_brackets: True if the #include used <> rather than "". + include_order: "default" or other value allowed in program arguments + + Returns: + One of the _XXX_HEADER constants. + + For example: + >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'stdio.h', True) + _C_SYS_HEADER + >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'string', True) + _CPP_SYS_HEADER + >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/foo.h', True, "standardcfirst") + _OTHER_SYS_HEADER + >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/foo.h', False) + _LIKELY_MY_HEADER + >>> _ClassifyInclude(FileInfo('foo/foo_unknown_extension.cc'), + ... 'bar/foo_other_ext.h', False) + _POSSIBLE_MY_HEADER + >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/bar.h', False) + _OTHER_HEADER + """ + # This is a list of all standard c++ header files, except + # those already checked for above. + is_cpp_header = include in _CPP_HEADERS + + # Mark include as C header if in list or in a known folder for standard-ish C headers. + is_std_c_header = (include_order == "default") or (include in _C_HEADERS + # additional linux glibc header folders + or Search(r'(?:%s)\/.*\.h' % "|".join(C_STANDARD_HEADER_FOLDERS), include)) + + # Headers with C++ extensions shouldn't be considered C system headers + is_system = used_angle_brackets and not os.path.splitext(include)[1] in ['.hpp', '.hxx', '.h++'] + + if is_system: + if is_cpp_header: + return _CPP_SYS_HEADER + if is_std_c_header: + return _C_SYS_HEADER + else: + return _OTHER_SYS_HEADER + + # If the target file and the include we're checking share a + # basename when we drop common extensions, and the include + # lives in . , then it's likely to be owned by the target file. + target_dir, target_base = ( + os.path.split(_DropCommonSuffixes(fileinfo.RepositoryName()))) + include_dir, include_base = os.path.split(_DropCommonSuffixes(include)) + target_dir_pub = os.path.normpath(target_dir + '/../public') + target_dir_pub = target_dir_pub.replace('\\', '/') + if target_base == include_base and ( + include_dir == target_dir or + include_dir == target_dir_pub): + return _LIKELY_MY_HEADER + + # If the target and include share some initial basename + # component, it's possible the target is implementing the + # include, so it's allowed to be first, but we'll never + # complain if it's not there. + target_first_component = _RE_FIRST_COMPONENT.match(target_base) + include_first_component = _RE_FIRST_COMPONENT.match(include_base) + if (target_first_component and include_first_component and + target_first_component.group(0) == + include_first_component.group(0)): + return _POSSIBLE_MY_HEADER + + return _OTHER_HEADER + + + +def CheckIncludeLine(filename, clean_lines, linenum, include_state, error): + """Check rules that are applicable to #include lines. + + Strings on #include lines are NOT removed from elided line, to make + certain tasks easier. However, to prevent false positives, checks + applicable to #include lines in CheckLanguage must be put here. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + include_state: An _IncludeState instance in which the headers are inserted. + error: The function to call with any errors found. + """ + fileinfo = FileInfo(filename) + line = clean_lines.lines[linenum] + + # "include" should use the new style "foo/bar.h" instead of just "bar.h" + # Only do this check if the included header follows google naming + # conventions. If not, assume that it's a 3rd party API that + # requires special include conventions. + # + # We also make an exception for Lua headers, which follow google + # naming convention but not the include convention. + match = Match(r'#include\s*"([^/]+\.h)"', line) + if match and not _THIRD_PARTY_HEADERS_PATTERN.match(match.group(1)): + error(filename, linenum, 'build/include_subdir', 4, + 'Include the directory when naming .h files') + + # we shouldn't include a file more than once. actually, there are a + # handful of instances where doing so is okay, but in general it's + # not. + match = _RE_PATTERN_INCLUDE.search(line) + if match: + include = match.group(2) + used_angle_brackets = (match.group(1) == '<') + duplicate_line = include_state.FindHeader(include) + if duplicate_line >= 0: + error(filename, linenum, 'build/include', 4, + '"%s" already included at %s:%s' % + (include, filename, duplicate_line)) + return + + for extension in GetNonHeaderExtensions(): + if (include.endswith('.' + extension) and + os.path.dirname(fileinfo.RepositoryName()) != os.path.dirname(include)): + error(filename, linenum, 'build/include', 4, + 'Do not include .' + extension + ' files from other packages') + return + + # We DO want to include a 3rd party looking header if it matches the + # filename. Otherwise we get an erroneous error "...should include its + # header" error later. + third_src_header = False + for ext in GetHeaderExtensions(): + basefilename = filename[0:len(filename) - len(fileinfo.Extension())] + headerfile = basefilename + '.' + ext + headername = FileInfo(headerfile).RepositoryName() + if headername in include or include in headername: + third_src_header = True + break + + if third_src_header or not _THIRD_PARTY_HEADERS_PATTERN.match(include): + include_state.include_list[-1].append((include, linenum)) + + # We want to ensure that headers appear in the right order: + # 1) for foo.cc, foo.h (preferred location) + # 2) c system files + # 3) cpp system files + # 4) for foo.cc, foo.h (deprecated location) + # 5) other google headers + # + # We classify each include statement as one of those 5 types + # using a number of techniques. The include_state object keeps + # track of the highest type seen, and complains if we see a + # lower type after that. + error_message = include_state.CheckNextIncludeOrder( + _ClassifyInclude(fileinfo, include, used_angle_brackets, _include_order)) + if error_message: + error(filename, linenum, 'build/include_order', 4, + '%s. Should be: %s.h, c system, c++ system, other.' % + (error_message, fileinfo.BaseName())) + canonical_include = include_state.CanonicalizeAlphabeticalOrder(include) + if not include_state.IsInAlphabeticalOrder( + clean_lines, linenum, canonical_include): + error(filename, linenum, 'build/include_alpha', 4, + 'Include "%s" not in alphabetical order' % include) + include_state.SetLastHeader(canonical_include) + + + +def _GetTextInside(text, start_pattern): + r"""Retrieves all the text between matching open and close parentheses. + + Given a string of lines and a regular expression string, retrieve all the text + following the expression and between opening punctuation symbols like + (, [, or {, and the matching close-punctuation symbol. This properly nested + occurrences of the punctuations, so for the text like + printf(a(), b(c())); + a call to _GetTextInside(text, r'printf\(') will return 'a(), b(c())'. + start_pattern must match string having an open punctuation symbol at the end. + + Args: + text: The lines to extract text. Its comments and strings must be elided. + It can be single line and can span multiple lines. + start_pattern: The regexp string indicating where to start extracting + the text. + Returns: + The extracted text. + None if either the opening string or ending punctuation could not be found. + """ + # TODO(unknown): Audit cpplint.py to see what places could be profitably + # rewritten to use _GetTextInside (and use inferior regexp matching today). + + # Give opening punctuations to get the matching close-punctuations. + matching_punctuation = {'(': ')', '{': '}', '[': ']'} + closing_punctuation = set(itervalues(matching_punctuation)) + + # Find the position to start extracting text. + match = re.search(start_pattern, text, re.M) + if not match: # start_pattern not found in text. + return None + start_position = match.end(0) + + assert start_position > 0, ( + 'start_pattern must ends with an opening punctuation.') + assert text[start_position - 1] in matching_punctuation, ( + 'start_pattern must ends with an opening punctuation.') + # Stack of closing punctuations we expect to have in text after position. + punctuation_stack = [matching_punctuation[text[start_position - 1]]] + position = start_position + while punctuation_stack and position < len(text): + if text[position] == punctuation_stack[-1]: + punctuation_stack.pop() + elif text[position] in closing_punctuation: + # A closing punctuation without matching opening punctuations. + return None + elif text[position] in matching_punctuation: + punctuation_stack.append(matching_punctuation[text[position]]) + position += 1 + if punctuation_stack: + # Opening punctuations left without matching close-punctuations. + return None + # punctuations match. + return text[start_position:position - 1] + + +# Patterns for matching call-by-reference parameters. +# +# Supports nested templates up to 2 levels deep using this messy pattern: +# < (?: < (?: < [^<>]* +# > +# | [^<>] )* +# > +# | [^<>] )* +# > +_RE_PATTERN_IDENT = r'[_a-zA-Z]\w*' # =~ [[:alpha:]][[:alnum:]]* +_RE_PATTERN_TYPE = ( + r'(?:const\s+)?(?:typename\s+|class\s+|struct\s+|union\s+|enum\s+)?' + r'(?:\w|' + r'\s*<(?:<(?:<[^<>]*>|[^<>])*>|[^<>])*>|' + r'::)+') +# A call-by-reference parameter ends with '& identifier'. +_RE_PATTERN_REF_PARAM = re.compile( + r'(' + _RE_PATTERN_TYPE + r'(?:\s*(?:\bconst\b|[*]))*\s*' + r'&\s*' + _RE_PATTERN_IDENT + r')\s*(?:=[^,()]+)?[,)]') +# A call-by-const-reference parameter either ends with 'const& identifier' +# or looks like 'const type& identifier' when 'type' is atomic. +_RE_PATTERN_CONST_REF_PARAM = ( + r'(?:.*\s*\bconst\s*&\s*' + _RE_PATTERN_IDENT + + r'|const\s+' + _RE_PATTERN_TYPE + r'\s*&\s*' + _RE_PATTERN_IDENT + r')') +# Stream types. +_RE_PATTERN_REF_STREAM_PARAM = ( + r'(?:.*stream\s*&\s*' + _RE_PATTERN_IDENT + r')') + + +def CheckLanguage(filename, clean_lines, linenum, file_extension, + include_state, nesting_state, error): + """Checks rules from the 'C++ language rules' section of cppguide.html. + + Some of these rules are hard to test (function overloading, using + uint32 inappropriately), but we do the best we can. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + file_extension: The extension (without the dot) of the filename. + include_state: An _IncludeState instance in which the headers are inserted. + nesting_state: A NestingState instance which maintains information about + the current stack of nested blocks being parsed. + error: The function to call with any errors found. + """ + # If the line is empty or consists of entirely a comment, no need to + # check it. + line = clean_lines.elided[linenum] + if not line: + return + + match = _RE_PATTERN_INCLUDE.search(line) + if match: + CheckIncludeLine(filename, clean_lines, linenum, include_state, error) + return + + # Reset include state across preprocessor directives. This is meant + # to silence warnings for conditional includes. + match = Match(r'^\s*#\s*(if|ifdef|ifndef|elif|else|endif)\b', line) + if match: + include_state.ResetSection(match.group(1)) + + + # Perform other checks now that we are sure that this is not an include line + CheckCasts(filename, clean_lines, linenum, error) + CheckGlobalStatic(filename, clean_lines, linenum, error) + CheckPrintf(filename, clean_lines, linenum, error) + + if IsHeaderExtension(file_extension): + # TODO(unknown): check that 1-arg constructors are explicit. + # How to tell it's a constructor? + # (handled in CheckForNonStandardConstructs for now) + # TODO(unknown): check that classes declare or disable copy/assign + # (level 1 error) + pass + + # Check if people are using the verboten C basic types. The only exception + # we regularly allow is "unsigned short port" for port. + if Search(r'\bshort port\b', line): + if not Search(r'\bunsigned short port\b', line): + error(filename, linenum, 'runtime/int', 4, + 'Use "unsigned short" for ports, not "short"') + else: + match = Search(r'\b(short|long(?! +double)|long long)\b', line) + if match: + error(filename, linenum, 'runtime/int', 4, + 'Use int16/int64/etc, rather than the C type %s' % match.group(1)) + + # Check if some verboten operator overloading is going on + # TODO(unknown): catch out-of-line unary operator&: + # class X {}; + # int operator&(const X& x) { return 42; } // unary operator& + # The trick is it's hard to tell apart from binary operator&: + # class Y { int operator&(const Y& x) { return 23; } }; // binary operator& + if Search(r'\boperator\s*&\s*\(\s*\)', line): + error(filename, linenum, 'runtime/operator', 4, + 'Unary operator& is dangerous. Do not use it.') + + # Check for suspicious usage of "if" like + # } if (a == b) { + if Search(r'\}\s*if\s*\(', line): + error(filename, linenum, 'readability/braces', 4, + 'Did you mean "else if"? If not, start a new line for "if".') + + # Check for potential format string bugs like printf(foo). + # We constrain the pattern not to pick things like DocidForPrintf(foo). + # Not perfect but it can catch printf(foo.c_str()) and printf(foo->c_str()) + # TODO(unknown): Catch the following case. Need to change the calling + # convention of the whole function to process multiple line to handle it. + # printf( + # boy_this_is_a_really_long_variable_that_cannot_fit_on_the_prev_line); + printf_args = _GetTextInside(line, r'(?i)\b(string)?printf\s*\(') + if printf_args: + match = Match(r'([\w.\->()]+)$', printf_args) + if match and match.group(1) != '__VA_ARGS__': + function_name = re.search(r'\b((?:string)?printf)\s*\(', + line, re.I).group(1) + error(filename, linenum, 'runtime/printf', 4, + 'Potential format string bug. Do %s("%%s", %s) instead.' + % (function_name, match.group(1))) + + # Check for potential memset bugs like memset(buf, sizeof(buf), 0). + match = Search(r'memset\s*\(([^,]*),\s*([^,]*),\s*0\s*\)', line) + if match and not Match(r"^''|-?[0-9]+|0x[0-9A-Fa-f]$", match.group(2)): + error(filename, linenum, 'runtime/memset', 4, + 'Did you mean "memset(%s, 0, %s)"?' + % (match.group(1), match.group(2))) + + if Search(r'\busing namespace\b', line): + if Search(r'\bliterals\b', line): + error(filename, linenum, 'build/namespaces_literals', 5, + 'Do not use namespace using-directives. ' + 'Use using-declarations instead.') + else: + error(filename, linenum, 'build/namespaces', 5, + 'Do not use namespace using-directives. ' + 'Use using-declarations instead.') + + # Detect variable-length arrays. + match = Match(r'\s*(.+::)?(\w+) [a-z]\w*\[(.+)];', line) + if (match and match.group(2) != 'return' and match.group(2) != 'delete' and + match.group(3).find(']') == -1): + # Split the size using space and arithmetic operators as delimiters. + # If any of the resulting tokens are not compile time constants then + # report the error. + tokens = re.split(r'\s|\+|\-|\*|\/|<<|>>]', match.group(3)) + is_const = True + skip_next = False + for tok in tokens: + if skip_next: + skip_next = False + continue + + if Search(r'sizeof\(.+\)', tok): continue + if Search(r'arraysize\(\w+\)', tok): continue + + tok = tok.lstrip('(') + tok = tok.rstrip(')') + if not tok: continue + if Match(r'\d+', tok): continue + if Match(r'0[xX][0-9a-fA-F]+', tok): continue + if Match(r'k[A-Z0-9]\w*', tok): continue + if Match(r'(.+::)?k[A-Z0-9]\w*', tok): continue + if Match(r'(.+::)?[A-Z][A-Z0-9_]*', tok): continue + # A catch all for tricky sizeof cases, including 'sizeof expression', + # 'sizeof(*type)', 'sizeof(const type)', 'sizeof(struct StructName)' + # requires skipping the next token because we split on ' ' and '*'. + if tok.startswith('sizeof'): + skip_next = True + continue + is_const = False + break + if not is_const: + error(filename, linenum, 'runtime/arrays', 1, + 'Do not use variable-length arrays. Use an appropriately named ' + "('k' followed by CamelCase) compile-time constant for the size.") + + # Check for use of unnamed namespaces in header files. Registration + # macros are typically OK, so we allow use of "namespace {" on lines + # that end with backslashes. + if (IsHeaderExtension(file_extension) + and Search(r'\bnamespace\s*{', line) + and line[-1] != '\\'): + error(filename, linenum, 'build/namespaces_headers', 4, + 'Do not use unnamed namespaces in header files. See ' + 'https://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Namespaces' + ' for more information.') + + +def CheckGlobalStatic(filename, clean_lines, linenum, error): + """Check for unsafe global or static objects. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + line = clean_lines.elided[linenum] + + # Match two lines at a time to support multiline declarations + if linenum + 1 < clean_lines.NumLines() and not Search(r'[;({]', line): + line += clean_lines.elided[linenum + 1].strip() + + # Check for people declaring static/global STL strings at the top level. + # This is dangerous because the C++ language does not guarantee that + # globals with constructors are initialized before the first access, and + # also because globals can be destroyed when some threads are still running. + # TODO(unknown): Generalize this to also find static unique_ptr instances. + # TODO(unknown): File bugs for clang-tidy to find these. + match = Match( + r'((?:|static +)(?:|const +))(?::*std::)?string( +const)? +' + r'([a-zA-Z0-9_:]+)\b(.*)', + line) + + # Remove false positives: + # - String pointers (as opposed to values). + # string *pointer + # const string *pointer + # string const *pointer + # string *const pointer + # + # - Functions and template specializations. + # string Function(... + # string Class::Method(... + # + # - Operators. These are matched separately because operator names + # cross non-word boundaries, and trying to match both operators + # and functions at the same time would decrease accuracy of + # matching identifiers. + # string Class::operator*() + if (match and + not Search(r'\bstring\b(\s+const)?\s*[\*\&]\s*(const\s+)?\w', line) and + not Search(r'\boperator\W', line) and + not Match(r'\s*(<.*>)?(::[a-zA-Z0-9_]+)*\s*\(([^"]|$)', match.group(4))): + if Search(r'\bconst\b', line): + error(filename, linenum, 'runtime/string', 4, + 'For a static/global string constant, use a C style string ' + 'instead: "%schar%s %s[]".' % + (match.group(1), match.group(2) or '', match.group(3))) + else: + error(filename, linenum, 'runtime/string', 4, + 'Static/global string variables are not permitted.') + + if (Search(r'\b([A-Za-z0-9_]*_)\(\1\)', line) or + Search(r'\b([A-Za-z0-9_]*_)\(CHECK_NOTNULL\(\1\)\)', line)): + error(filename, linenum, 'runtime/init', 4, + 'You seem to be initializing a member variable with itself.') + + +def CheckPrintf(filename, clean_lines, linenum, error): + """Check for printf related issues. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + line = clean_lines.elided[linenum] + + # When snprintf is used, the second argument shouldn't be a literal. + match = Search(r'snprintf\s*\(([^,]*),\s*([0-9]*)\s*,', line) + if match and match.group(2) != '0': + # If 2nd arg is zero, snprintf is used to calculate size. + error(filename, linenum, 'runtime/printf', 3, + 'If you can, use sizeof(%s) instead of %s as the 2nd arg ' + 'to snprintf.' % (match.group(1), match.group(2))) + + # Check if some verboten C functions are being used. + if Search(r'\bsprintf\s*\(', line): + error(filename, linenum, 'runtime/printf', 5, + 'Never use sprintf. Use snprintf instead.') + match = Search(r'\b(strcpy|strcat)\s*\(', line) + if match: + error(filename, linenum, 'runtime/printf', 4, + 'Almost always, snprintf is better than %s' % match.group(1)) + + +def IsDerivedFunction(clean_lines, linenum): + """Check if current line contains an inherited function. + + Args: + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + Returns: + True if current line contains a function with "override" + virt-specifier. + """ + # Scan back a few lines for start of current function + for i in xrange(linenum, max(-1, linenum - 10), -1): + match = Match(r'^([^()]*\w+)\(', clean_lines.elided[i]) + if match: + # Look for "override" after the matching closing parenthesis + line, _, closing_paren = CloseExpression( + clean_lines, i, len(match.group(1))) + return (closing_paren >= 0 and + Search(r'\boverride\b', line[closing_paren:])) + return False + + +def IsOutOfLineMethodDefinition(clean_lines, linenum): + """Check if current line contains an out-of-line method definition. + + Args: + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + Returns: + True if current line contains an out-of-line method definition. + """ + # Scan back a few lines for start of current function + for i in xrange(linenum, max(-1, linenum - 10), -1): + if Match(r'^([^()]*\w+)\(', clean_lines.elided[i]): + return Match(r'^[^()]*\w+::\w+\(', clean_lines.elided[i]) is not None + return False + + +def IsInitializerList(clean_lines, linenum): + """Check if current line is inside constructor initializer list. + + Args: + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + Returns: + True if current line appears to be inside constructor initializer + list, False otherwise. + """ + for i in xrange(linenum, 1, -1): + line = clean_lines.elided[i] + if i == linenum: + remove_function_body = Match(r'^(.*)\{\s*$', line) + if remove_function_body: + line = remove_function_body.group(1) + + if Search(r'\s:\s*\w+[({]', line): + # A lone colon tend to indicate the start of a constructor + # initializer list. It could also be a ternary operator, which + # also tend to appear in constructor initializer lists as + # opposed to parameter lists. + return True + if Search(r'\}\s*,\s*$', line): + # A closing brace followed by a comma is probably the end of a + # brace-initialized member in constructor initializer list. + return True + if Search(r'[{};]\s*$', line): + # Found one of the following: + # - A closing brace or semicolon, probably the end of the previous + # function. + # - An opening brace, probably the start of current class or namespace. + # + # Current line is probably not inside an initializer list since + # we saw one of those things without seeing the starting colon. + return False + + # Got to the beginning of the file without seeing the start of + # constructor initializer list. + return False + + +def CheckForNonConstReference(filename, clean_lines, linenum, + nesting_state, error): + """Check for non-const references. + + Separate from CheckLanguage since it scans backwards from current + line, instead of scanning forward. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + nesting_state: A NestingState instance which maintains information about + the current stack of nested blocks being parsed. + error: The function to call with any errors found. + """ + # Do nothing if there is no '&' on current line. + line = clean_lines.elided[linenum] + if '&' not in line: + return + + # If a function is inherited, current function doesn't have much of + # a choice, so any non-const references should not be blamed on + # derived function. + if IsDerivedFunction(clean_lines, linenum): + return + + # Don't warn on out-of-line method definitions, as we would warn on the + # in-line declaration, if it isn't marked with 'override'. + if IsOutOfLineMethodDefinition(clean_lines, linenum): + return + + # Long type names may be broken across multiple lines, usually in one + # of these forms: + # LongType + # ::LongTypeContinued &identifier + # LongType:: + # LongTypeContinued &identifier + # LongType< + # ...>::LongTypeContinued &identifier + # + # If we detected a type split across two lines, join the previous + # line to current line so that we can match const references + # accordingly. + # + # Note that this only scans back one line, since scanning back + # arbitrary number of lines would be expensive. If you have a type + # that spans more than 2 lines, please use a typedef. + if linenum > 1: + previous = None + if Match(r'\s*::(?:[\w<>]|::)+\s*&\s*\S', line): + # previous_line\n + ::current_line + previous = Search(r'\b((?:const\s*)?(?:[\w<>]|::)+[\w<>])\s*$', + clean_lines.elided[linenum - 1]) + elif Match(r'\s*[a-zA-Z_]([\w<>]|::)+\s*&\s*\S', line): + # previous_line::\n + current_line + previous = Search(r'\b((?:const\s*)?(?:[\w<>]|::)+::)\s*$', + clean_lines.elided[linenum - 1]) + if previous: + line = previous.group(1) + line.lstrip() + else: + # Check for templated parameter that is split across multiple lines + endpos = line.rfind('>') + if endpos > -1: + (_, startline, startpos) = ReverseCloseExpression( + clean_lines, linenum, endpos) + if startpos > -1 and startline < linenum: + # Found the matching < on an earlier line, collect all + # pieces up to current line. + line = '' + for i in xrange(startline, linenum + 1): + line += clean_lines.elided[i].strip() + + # Check for non-const references in function parameters. A single '&' may + # found in the following places: + # inside expression: binary & for bitwise AND + # inside expression: unary & for taking the address of something + # inside declarators: reference parameter + # We will exclude the first two cases by checking that we are not inside a + # function body, including one that was just introduced by a trailing '{'. + # TODO(unknown): Doesn't account for 'catch(Exception& e)' [rare]. + if (nesting_state.previous_stack_top and + not (isinstance(nesting_state.previous_stack_top, _ClassInfo) or + isinstance(nesting_state.previous_stack_top, _NamespaceInfo))): + # Not at toplevel, not within a class, and not within a namespace + return + + # Avoid initializer lists. We only need to scan back from the + # current line for something that starts with ':'. + # + # We don't need to check the current line, since the '&' would + # appear inside the second set of parentheses on the current line as + # opposed to the first set. + if linenum > 0: + for i in xrange(linenum - 1, max(0, linenum - 10), -1): + previous_line = clean_lines.elided[i] + if not Search(r'[),]\s*$', previous_line): + break + if Match(r'^\s*:\s+\S', previous_line): + return + + # Avoid preprocessors + if Search(r'\\\s*$', line): + return + + # Avoid constructor initializer lists + if IsInitializerList(clean_lines, linenum): + return + + # We allow non-const references in a few standard places, like functions + # called "swap()" or iostream operators like "<<" or ">>". Do not check + # those function parameters. + # + # We also accept & in static_assert, which looks like a function but + # it's actually a declaration expression. + allowed_functions = (r'(?:[sS]wap(?:<\w:+>)?|' + r'operator\s*[<>][<>]|' + r'static_assert|COMPILE_ASSERT' + r')\s*\(') + if Search(allowed_functions, line): + return + elif not Search(r'\S+\([^)]*$', line): + # Don't see an allowed function on this line. Actually we + # didn't see any function name on this line, so this is likely a + # multi-line parameter list. Try a bit harder to catch this case. + for i in xrange(2): + if (linenum > i and + Search(allowed_functions, clean_lines.elided[linenum - i - 1])): + return + + decls = ReplaceAll(r'{[^}]*}', ' ', line) # exclude function body + for parameter in re.findall(_RE_PATTERN_REF_PARAM, decls): + if (not Match(_RE_PATTERN_CONST_REF_PARAM, parameter) and + not Match(_RE_PATTERN_REF_STREAM_PARAM, parameter)): + error(filename, linenum, 'runtime/references', 2, + 'Is this a non-const reference? ' + 'If so, make const or use a pointer: ' + + ReplaceAll(' *<', '<', parameter)) + + +def CheckCasts(filename, clean_lines, linenum, error): + """Various cast related checks. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + line = clean_lines.elided[linenum] + + # Check to see if they're using an conversion function cast. + # I just try to capture the most common basic types, though there are more. + # Parameterless conversion functions, such as bool(), are allowed as they are + # probably a member operator declaration or default constructor. + match = Search( + r'(\bnew\s+(?:const\s+)?|\S<\s*(?:const\s+)?)?\b' + r'(int|float|double|bool|char|int32|uint32|int64|uint64)' + r'(\([^)].*)', line) + expecting_function = ExpectingFunctionArgs(clean_lines, linenum) + if match and not expecting_function: + matched_type = match.group(2) + + # matched_new_or_template is used to silence two false positives: + # - New operators + # - Template arguments with function types + # + # For template arguments, we match on types immediately following + # an opening bracket without any spaces. This is a fast way to + # silence the common case where the function type is the first + # template argument. False negative with less-than comparison is + # avoided because those operators are usually followed by a space. + # + # function // bracket + no space = false positive + # value < double(42) // bracket + space = true positive + matched_new_or_template = match.group(1) + + # Avoid arrays by looking for brackets that come after the closing + # parenthesis. + if Match(r'\([^()]+\)\s*\[', match.group(3)): + return + + # Other things to ignore: + # - Function pointers + # - Casts to pointer types + # - Placement new + # - Alias declarations + matched_funcptr = match.group(3) + if (matched_new_or_template is None and + not (matched_funcptr and + (Match(r'\((?:[^() ]+::\s*\*\s*)?[^() ]+\)\s*\(', + matched_funcptr) or + matched_funcptr.startswith('(*)'))) and + not Match(r'\s*using\s+\S+\s*=\s*' + matched_type, line) and + not Search(r'new\(\S+\)\s*' + matched_type, line)): + error(filename, linenum, 'readability/casting', 4, + 'Using deprecated casting style. ' + 'Use static_cast<%s>(...) instead' % + matched_type) + + if not expecting_function: + CheckCStyleCast(filename, clean_lines, linenum, 'static_cast', + r'\((int|float|double|bool|char|u?int(16|32|64))\)', error) + + # This doesn't catch all cases. Consider (const char * const)"hello". + # + # (char *) "foo" should always be a const_cast (reinterpret_cast won't + # compile). + if CheckCStyleCast(filename, clean_lines, linenum, 'const_cast', + r'\((char\s?\*+\s?)\)\s*"', error): + pass + else: + # Check pointer casts for other than string constants + CheckCStyleCast(filename, clean_lines, linenum, 'reinterpret_cast', + r'\((\w+\s?\*+\s?)\)', error) + + # In addition, we look for people taking the address of a cast. This + # is dangerous -- casts can assign to temporaries, so the pointer doesn't + # point where you think. + # + # Some non-identifier character is required before the '&' for the + # expression to be recognized as a cast. These are casts: + # expression = &static_cast(temporary()); + # function(&(int*)(temporary())); + # + # This is not a cast: + # reference_type&(int* function_param); + match = Search( + r'(?:[^\w]&\(([^)*][^)]*)\)[\w(])|' + r'(?:[^\w]&(static|dynamic|down|reinterpret)_cast\b)', line) + if match: + # Try a better error message when the & is bound to something + # dereferenced by the casted pointer, as opposed to the casted + # pointer itself. + parenthesis_error = False + match = Match(r'^(.*&(?:static|dynamic|down|reinterpret)_cast\b)<', line) + if match: + _, y1, x1 = CloseExpression(clean_lines, linenum, len(match.group(1))) + if x1 >= 0 and clean_lines.elided[y1][x1] == '(': + _, y2, x2 = CloseExpression(clean_lines, y1, x1) + if x2 >= 0: + extended_line = clean_lines.elided[y2][x2:] + if y2 < clean_lines.NumLines() - 1: + extended_line += clean_lines.elided[y2 + 1] + if Match(r'\s*(?:->|\[)', extended_line): + parenthesis_error = True + + if parenthesis_error: + error(filename, linenum, 'readability/casting', 4, + ('Are you taking an address of something dereferenced ' + 'from a cast? Wrapping the dereferenced expression in ' + 'parentheses will make the binding more obvious')) + else: + error(filename, linenum, 'runtime/casting', 4, + ('Are you taking an address of a cast? ' + 'This is dangerous: could be a temp var. ' + 'Take the address before doing the cast, rather than after')) + + +def CheckCStyleCast(filename, clean_lines, linenum, cast_type, pattern, error): + """Checks for a C-style cast by looking for the pattern. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + cast_type: The string for the C++ cast to recommend. This is either + reinterpret_cast, static_cast, or const_cast, depending. + pattern: The regular expression used to find C-style casts. + error: The function to call with any errors found. + + Returns: + True if an error was emitted. + False otherwise. + """ + line = clean_lines.elided[linenum] + match = Search(pattern, line) + if not match: + return False + + # Exclude lines with keywords that tend to look like casts + context = line[0:match.start(1) - 1] + if Match(r'.*\b(?:sizeof|alignof|alignas|[_A-Z][_A-Z0-9]*)\s*$', context): + return False + + # Try expanding current context to see if we one level of + # parentheses inside a macro. + if linenum > 0: + for i in xrange(linenum - 1, max(0, linenum - 5), -1): + context = clean_lines.elided[i] + context + if Match(r'.*\b[_A-Z][_A-Z0-9]*\s*\((?:\([^()]*\)|[^()])*$', context): + return False + + # operator++(int) and operator--(int) + if context.endswith(' operator++') or context.endswith(' operator--'): + return False + + # A single unnamed argument for a function tends to look like old style cast. + # If we see those, don't issue warnings for deprecated casts. + remainder = line[match.end(0):] + if Match(r'^\s*(?:;|const\b|throw\b|final\b|override\b|[=>{),]|->)', + remainder): + return False + + # At this point, all that should be left is actual casts. + error(filename, linenum, 'readability/casting', 4, + 'Using C-style cast. Use %s<%s>(...) instead' % + (cast_type, match.group(1))) + + return True + + +def ExpectingFunctionArgs(clean_lines, linenum): + """Checks whether where function type arguments are expected. + + Args: + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + + Returns: + True if the line at 'linenum' is inside something that expects arguments + of function types. + """ + line = clean_lines.elided[linenum] + return (Match(r'^\s*MOCK_(CONST_)?METHOD\d+(_T)?\(', line) or + (linenum >= 2 and + (Match(r'^\s*MOCK_(?:CONST_)?METHOD\d+(?:_T)?\((?:\S+,)?\s*$', + clean_lines.elided[linenum - 1]) or + Match(r'^\s*MOCK_(?:CONST_)?METHOD\d+(?:_T)?\(\s*$', + clean_lines.elided[linenum - 2]) or + Search(r'\bstd::m?function\s*\<\s*$', + clean_lines.elided[linenum - 1])))) + + +_HEADERS_CONTAINING_TEMPLATES = ( + ('', ('deque',)), + ('', ('unary_function', 'binary_function', + 'plus', 'minus', 'multiplies', 'divides', 'modulus', + 'negate', + 'equal_to', 'not_equal_to', 'greater', 'less', + 'greater_equal', 'less_equal', + 'logical_and', 'logical_or', 'logical_not', + 'unary_negate', 'not1', 'binary_negate', 'not2', + 'bind1st', 'bind2nd', + 'pointer_to_unary_function', + 'pointer_to_binary_function', + 'ptr_fun', + 'mem_fun_t', 'mem_fun', 'mem_fun1_t', 'mem_fun1_ref_t', + 'mem_fun_ref_t', + 'const_mem_fun_t', 'const_mem_fun1_t', + 'const_mem_fun_ref_t', 'const_mem_fun1_ref_t', + 'mem_fun_ref', + )), + ('', ('numeric_limits',)), + ('', ('list',)), + ('', ('multimap',)), + ('', ('allocator', 'make_shared', 'make_unique', 'shared_ptr', + 'unique_ptr', 'weak_ptr')), + ('', ('queue', 'priority_queue',)), + ('', ('multiset',)), + ('', ('stack',)), + ('', ('char_traits', 'basic_string',)), + ('', ('tuple',)), + ('', ('unordered_map', 'unordered_multimap')), + ('', ('unordered_set', 'unordered_multiset')), + ('', ('pair',)), + ('', ('vector',)), + + # gcc extensions. + # Note: std::hash is their hash, ::hash is our hash + ('', ('hash_map', 'hash_multimap',)), + ('', ('hash_set', 'hash_multiset',)), + ('', ('slist',)), + ) + +_HEADERS_MAYBE_TEMPLATES = ( + ('', ('copy', 'max', 'min', 'min_element', 'sort', + 'transform', + )), + ('', ('forward', 'make_pair', 'move', 'swap')), + ) + +_RE_PATTERN_STRING = re.compile(r'\bstring\b') + +_re_pattern_headers_maybe_templates = [] +for _header, _templates in _HEADERS_MAYBE_TEMPLATES: + for _template in _templates: + # Match max(..., ...), max(..., ...), but not foo->max, foo.max or + # 'type::max()'. + _re_pattern_headers_maybe_templates.append( + (re.compile(r'[^>.]\b' + _template + r'(<.*?>)?\([^\)]'), + _template, + _header)) +# Match set, but not foo->set, foo.set +_re_pattern_headers_maybe_templates.append( + (re.compile(r'[^>.]\bset\s*\<'), + 'set<>', + '')) +# Match 'map var' and 'std::map(...)', but not 'map(...)'' +_re_pattern_headers_maybe_templates.append( + (re.compile(r'(std\b::\bmap\s*\<)|(^(std\b::\b)map\b\(\s*\<)'), + 'map<>', + '')) + +# Other scripts may reach in and modify this pattern. +_re_pattern_templates = [] +for _header, _templates in _HEADERS_CONTAINING_TEMPLATES: + for _template in _templates: + _re_pattern_templates.append( + (re.compile(r'(\<|\b)' + _template + r'\s*\<'), + _template + '<>', + _header)) + + +def FilesBelongToSameModule(filename_cc, filename_h): + """Check if these two filenames belong to the same module. + + The concept of a 'module' here is a as follows: + foo.h, foo-inl.h, foo.cc, foo_test.cc and foo_unittest.cc belong to the + same 'module' if they are in the same directory. + some/path/public/xyzzy and some/path/internal/xyzzy are also considered + to belong to the same module here. + + If the filename_cc contains a longer path than the filename_h, for example, + '/absolute/path/to/base/sysinfo.cc', and this file would include + 'base/sysinfo.h', this function also produces the prefix needed to open the + header. This is used by the caller of this function to more robustly open the + header file. We don't have access to the real include paths in this context, + so we need this guesswork here. + + Known bugs: tools/base/bar.cc and base/bar.h belong to the same module + according to this implementation. Because of this, this function gives + some false positives. This should be sufficiently rare in practice. + + Args: + filename_cc: is the path for the source (e.g. .cc) file + filename_h: is the path for the header path + + Returns: + Tuple with a bool and a string: + bool: True if filename_cc and filename_h belong to the same module. + string: the additional prefix needed to open the header file. + """ + fileinfo_cc = FileInfo(filename_cc) + if not fileinfo_cc.Extension().lstrip('.') in GetNonHeaderExtensions(): + return (False, '') + + fileinfo_h = FileInfo(filename_h) + if not IsHeaderExtension(fileinfo_h.Extension().lstrip('.')): + return (False, '') + + filename_cc = filename_cc[:-(len(fileinfo_cc.Extension()))] + matched_test_suffix = Search(_TEST_FILE_SUFFIX, fileinfo_cc.BaseName()) + if matched_test_suffix: + filename_cc = filename_cc[:-len(matched_test_suffix.group(1))] + + filename_cc = filename_cc.replace('/public/', '/') + filename_cc = filename_cc.replace('/internal/', '/') + + filename_h = filename_h[:-(len(fileinfo_h.Extension()))] + if filename_h.endswith('-inl'): + filename_h = filename_h[:-len('-inl')] + filename_h = filename_h.replace('/public/', '/') + filename_h = filename_h.replace('/internal/', '/') + + files_belong_to_same_module = filename_cc.endswith(filename_h) + common_path = '' + if files_belong_to_same_module: + common_path = filename_cc[:-len(filename_h)] + return files_belong_to_same_module, common_path + + +def UpdateIncludeState(filename, include_dict, io=codecs): + """Fill up the include_dict with new includes found from the file. + + Args: + filename: the name of the header to read. + include_dict: a dictionary in which the headers are inserted. + io: The io factory to use to read the file. Provided for testability. + + Returns: + True if a header was successfully added. False otherwise. + """ + headerfile = None + try: + with io.open(filename, 'r', 'utf8', 'replace') as headerfile: + linenum = 0 + for line in headerfile: + linenum += 1 + clean_line = CleanseComments(line) + match = _RE_PATTERN_INCLUDE.search(clean_line) + if match: + include = match.group(2) + include_dict.setdefault(include, linenum) + return True + except IOError: + return False + + + +def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error, + io=codecs): + """Reports for missing stl includes. + + This function will output warnings to make sure you are including the headers + necessary for the stl containers and functions that you use. We only give one + reason to include a header. For example, if you use both equal_to<> and + less<> in a .h file, only one (the latter in the file) of these will be + reported as a reason to include the . + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + include_state: An _IncludeState instance. + error: The function to call with any errors found. + io: The IO factory to use to read the header file. Provided for unittest + injection. + """ + required = {} # A map of header name to linenumber and the template entity. + # Example of required: { '': (1219, 'less<>') } + + for linenum in xrange(clean_lines.NumLines()): + line = clean_lines.elided[linenum] + if not line or line[0] == '#': + continue + + # String is special -- it is a non-templatized type in STL. + matched = _RE_PATTERN_STRING.search(line) + if matched: + # Don't warn about strings in non-STL namespaces: + # (We check only the first match per line; good enough.) + prefix = line[:matched.start()] + if prefix.endswith('std::') or not prefix.endswith('::'): + required[''] = (linenum, 'string') + + for pattern, template, header in _re_pattern_headers_maybe_templates: + if pattern.search(line): + required[header] = (linenum, template) + + # The following function is just a speed up, no semantics are changed. + if not '<' in line: # Reduces the cpu time usage by skipping lines. + continue + + for pattern, template, header in _re_pattern_templates: + matched = pattern.search(line) + if matched: + # Don't warn about IWYU in non-STL namespaces: + # (We check only the first match per line; good enough.) + prefix = line[:matched.start()] + if prefix.endswith('std::') or not prefix.endswith('::'): + required[header] = (linenum, template) + + # The policy is that if you #include something in foo.h you don't need to + # include it again in foo.cc. Here, we will look at possible includes. + # Let's flatten the include_state include_list and copy it into a dictionary. + include_dict = dict([item for sublist in include_state.include_list + for item in sublist]) + + # Did we find the header for this file (if any) and successfully load it? + header_found = False + + # Use the absolute path so that matching works properly. + abs_filename = FileInfo(filename).FullName() + + # For Emacs's flymake. + # If cpplint is invoked from Emacs's flymake, a temporary file is generated + # by flymake and that file name might end with '_flymake.cc'. In that case, + # restore original file name here so that the corresponding header file can be + # found. + # e.g. If the file name is 'foo_flymake.cc', we should search for 'foo.h' + # instead of 'foo_flymake.h' + abs_filename = re.sub(r'_flymake\.cc$', '.cc', abs_filename) + + # include_dict is modified during iteration, so we iterate over a copy of + # the keys. + header_keys = list(include_dict.keys()) + for header in header_keys: + (same_module, common_path) = FilesBelongToSameModule(abs_filename, header) + fullpath = common_path + header + if same_module and UpdateIncludeState(fullpath, include_dict, io): + header_found = True + + # If we can't find the header file for a .cc, assume it's because we don't + # know where to look. In that case we'll give up as we're not sure they + # didn't include it in the .h file. + # TODO(unknown): Do a better job of finding .h files so we are confident that + # not having the .h file means there isn't one. + if not header_found: + for extension in GetNonHeaderExtensions(): + if filename.endswith('.' + extension): + return + + # All the lines have been processed, report the errors found. + for required_header_unstripped in sorted(required, key=required.__getitem__): + template = required[required_header_unstripped][1] + if required_header_unstripped.strip('<>"') not in include_dict: + error(filename, required[required_header_unstripped][0], + 'build/include_what_you_use', 4, + 'Add #include ' + required_header_unstripped + ' for ' + template) + + +_RE_PATTERN_EXPLICIT_MAKEPAIR = re.compile(r'\bmake_pair\s*<') + + +def CheckMakePairUsesDeduction(filename, clean_lines, linenum, error): + """Check that make_pair's template arguments are deduced. + + G++ 4.6 in C++11 mode fails badly if make_pair's template arguments are + specified explicitly, and such use isn't intended in any case. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + line = clean_lines.elided[linenum] + match = _RE_PATTERN_EXPLICIT_MAKEPAIR.search(line) + if match: + error(filename, linenum, 'build/explicit_make_pair', + 4, # 4 = high confidence + 'For C++11-compatibility, omit template arguments from make_pair' + ' OR use pair directly OR if appropriate, construct a pair directly') + + +def CheckRedundantVirtual(filename, clean_lines, linenum, error): + """Check if line contains a redundant "virtual" function-specifier. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + # Look for "virtual" on current line. + line = clean_lines.elided[linenum] + virtual = Match(r'^(.*)(\bvirtual\b)(.*)$', line) + if not virtual: return + + # Ignore "virtual" keywords that are near access-specifiers. These + # are only used in class base-specifier and do not apply to member + # functions. + if (Search(r'\b(public|protected|private)\s+$', virtual.group(1)) or + Match(r'^\s+(public|protected|private)\b', virtual.group(3))): + return + + # Ignore the "virtual" keyword from virtual base classes. Usually + # there is a column on the same line in these cases (virtual base + # classes are rare in google3 because multiple inheritance is rare). + if Match(r'^.*[^:]:[^:].*$', line): return + + # Look for the next opening parenthesis. This is the start of the + # parameter list (possibly on the next line shortly after virtual). + # TODO(unknown): doesn't work if there are virtual functions with + # decltype() or other things that use parentheses, but csearch suggests + # that this is rare. + end_col = -1 + end_line = -1 + start_col = len(virtual.group(2)) + for start_line in xrange(linenum, min(linenum + 3, clean_lines.NumLines())): + line = clean_lines.elided[start_line][start_col:] + parameter_list = Match(r'^([^(]*)\(', line) + if parameter_list: + # Match parentheses to find the end of the parameter list + (_, end_line, end_col) = CloseExpression( + clean_lines, start_line, start_col + len(parameter_list.group(1))) + break + start_col = 0 + + if end_col < 0: + return # Couldn't find end of parameter list, give up + + # Look for "override" or "final" after the parameter list + # (possibly on the next few lines). + for i in xrange(end_line, min(end_line + 3, clean_lines.NumLines())): + line = clean_lines.elided[i][end_col:] + match = Search(r'\b(override|final)\b', line) + if match: + error(filename, linenum, 'readability/inheritance', 4, + ('"virtual" is redundant since function is ' + 'already declared as "%s"' % match.group(1))) + + # Set end_col to check whole lines after we are done with the + # first line. + end_col = 0 + if Search(r'[^\w]\s*$', line): + break + + +def CheckRedundantOverrideOrFinal(filename, clean_lines, linenum, error): + """Check if line contains a redundant "override" or "final" virt-specifier. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + # Look for closing parenthesis nearby. We need one to confirm where + # the declarator ends and where the virt-specifier starts to avoid + # false positives. + line = clean_lines.elided[linenum] + declarator_end = line.rfind(')') + if declarator_end >= 0: + fragment = line[declarator_end:] + else: + if linenum > 1 and clean_lines.elided[linenum - 1].rfind(')') >= 0: + fragment = line + else: + return + + # Check that at most one of "override" or "final" is present, not both + if Search(r'\boverride\b', fragment) and Search(r'\bfinal\b', fragment): + error(filename, linenum, 'readability/inheritance', 4, + ('"override" is redundant since function is ' + 'already declared as "final"')) + + + + +# Returns true if we are at a new block, and it is directly +# inside of a namespace. +def IsBlockInNameSpace(nesting_state, is_forward_declaration): + """Checks that the new block is directly in a namespace. + + Args: + nesting_state: The _NestingState object that contains info about our state. + is_forward_declaration: If the class is a forward declared class. + Returns: + Whether or not the new block is directly in a namespace. + """ + if is_forward_declaration: + return len(nesting_state.stack) >= 1 and ( + isinstance(nesting_state.stack[-1], _NamespaceInfo)) + + + return (len(nesting_state.stack) > 1 and + nesting_state.stack[-1].check_namespace_indentation and + isinstance(nesting_state.stack[-2], _NamespaceInfo)) + + +def ShouldCheckNamespaceIndentation(nesting_state, is_namespace_indent_item, + raw_lines_no_comments, linenum): + """This method determines if we should apply our namespace indentation check. + + Args: + nesting_state: The current nesting state. + is_namespace_indent_item: If we just put a new class on the stack, True. + If the top of the stack is not a class, or we did not recently + add the class, False. + raw_lines_no_comments: The lines without the comments. + linenum: The current line number we are processing. + + Returns: + True if we should apply our namespace indentation check. Currently, it + only works for classes and namespaces inside of a namespace. + """ + + is_forward_declaration = IsForwardClassDeclaration(raw_lines_no_comments, + linenum) + + if not (is_namespace_indent_item or is_forward_declaration): + return False + + # If we are in a macro, we do not want to check the namespace indentation. + if IsMacroDefinition(raw_lines_no_comments, linenum): + return False + + return IsBlockInNameSpace(nesting_state, is_forward_declaration) + + +# Call this method if the line is directly inside of a namespace. +# If the line above is blank (excluding comments) or the start of +# an inner namespace, it cannot be indented. +def CheckItemIndentationInNamespace(filename, raw_lines_no_comments, linenum, + error): + line = raw_lines_no_comments[linenum] + if Match(r'^\s+', line): + error(filename, linenum, 'runtime/indentation_namespace', 4, + 'Do not indent within a namespace') + + +def ProcessLine(filename, file_extension, clean_lines, line, + include_state, function_state, nesting_state, error, + extra_check_functions=None): + """Processes a single line in the file. + + Args: + filename: Filename of the file that is being processed. + file_extension: The extension (dot not included) of the file. + clean_lines: An array of strings, each representing a line of the file, + with comments stripped. + line: Number of line being processed. + include_state: An _IncludeState instance in which the headers are inserted. + function_state: A _FunctionState instance which counts function lines, etc. + nesting_state: A NestingState instance which maintains information about + the current stack of nested blocks being parsed. + error: A callable to which errors are reported, which takes 4 arguments: + filename, line number, error level, and message + extra_check_functions: An array of additional check functions that will be + run on each source line. Each function takes 4 + arguments: filename, clean_lines, line, error + """ + raw_lines = clean_lines.raw_lines + ParseNolintSuppressions(filename, raw_lines[line], line, error) + nesting_state.Update(filename, clean_lines, line, error) + CheckForNamespaceIndentation(filename, nesting_state, clean_lines, line, + error) + if nesting_state.InAsmBlock(): return + CheckForFunctionLengths(filename, clean_lines, line, function_state, error) + CheckForMultilineCommentsAndStrings(filename, clean_lines, line, error) + CheckStyle(filename, clean_lines, line, file_extension, nesting_state, error) + CheckLanguage(filename, clean_lines, line, file_extension, include_state, + nesting_state, error) + CheckForNonConstReference(filename, clean_lines, line, nesting_state, error) + CheckForNonStandardConstructs(filename, clean_lines, line, + nesting_state, error) + CheckVlogArguments(filename, clean_lines, line, error) + CheckPosixThreading(filename, clean_lines, line, error) + CheckInvalidIncrement(filename, clean_lines, line, error) + CheckMakePairUsesDeduction(filename, clean_lines, line, error) + CheckRedundantVirtual(filename, clean_lines, line, error) + CheckRedundantOverrideOrFinal(filename, clean_lines, line, error) + if extra_check_functions: + for check_fn in extra_check_functions: + check_fn(filename, clean_lines, line, error) + +def FlagCxx11Features(filename, clean_lines, linenum, error): + """Flag those c++11 features that we only allow in certain places. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + line = clean_lines.elided[linenum] + + include = Match(r'\s*#\s*include\s+[<"]([^<"]+)[">]', line) + + # Flag unapproved C++ TR1 headers. + if include and include.group(1).startswith('tr1/'): + error(filename, linenum, 'build/c++tr1', 5, + ('C++ TR1 headers such as <%s> are unapproved.') % include.group(1)) + + # Flag unapproved C++11 headers. + if include and include.group(1) in ('cfenv', + 'condition_variable', + 'fenv.h', + 'future', + 'mutex', + 'thread', + 'chrono', + 'ratio', + 'regex', + 'system_error', + ): + error(filename, linenum, 'build/c++11', 5, + ('<%s> is an unapproved C++11 header.') % include.group(1)) + + # The only place where we need to worry about C++11 keywords and library + # features in preprocessor directives is in macro definitions. + if Match(r'\s*#', line) and not Match(r'\s*#\s*define\b', line): return + + # These are classes and free functions. The classes are always + # mentioned as std::*, but we only catch the free functions if + # they're not found by ADL. They're alphabetical by header. + for top_name in ( + # type_traits + 'alignment_of', + 'aligned_union', + ): + if Search(r'\bstd::%s\b' % top_name, line): + error(filename, linenum, 'build/c++11', 5, + ('std::%s is an unapproved C++11 class or function. Send c-style ' + 'an example of where it would make your code more readable, and ' + 'they may let you use it.') % top_name) + + +def FlagCxx14Features(filename, clean_lines, linenum, error): + """Flag those C++14 features that we restrict. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + line = clean_lines.elided[linenum] + + include = Match(r'\s*#\s*include\s+[<"]([^<"]+)[">]', line) + + # Flag unapproved C++14 headers. + if include and include.group(1) in ('scoped_allocator', 'shared_mutex'): + error(filename, linenum, 'build/c++14', 5, + ('<%s> is an unapproved C++14 header.') % include.group(1)) + + +def ProcessFileData(filename, file_extension, lines, error, + extra_check_functions=None): + """Performs lint checks and reports any errors to the given error function. + + Args: + filename: Filename of the file that is being processed. + file_extension: The extension (dot not included) of the file. + lines: An array of strings, each representing a line of the file, with the + last element being empty if the file is terminated with a newline. + error: A callable to which errors are reported, which takes 4 arguments: + filename, line number, error level, and message + extra_check_functions: An array of additional check functions that will be + run on each source line. Each function takes 4 + arguments: filename, clean_lines, line, error + """ + lines = (['// marker so line numbers and indices both start at 1'] + lines + + ['// marker so line numbers end in a known way']) + + include_state = _IncludeState() + function_state = _FunctionState() + nesting_state = NestingState() + + ResetNolintSuppressions() + + CheckForCopyright(filename, lines, error) + ProcessGlobalSuppresions(lines) + RemoveMultiLineComments(filename, lines, error) + clean_lines = CleansedLines(lines) + + if IsHeaderExtension(file_extension): + CheckForHeaderGuard(filename, clean_lines, error) + + for line in xrange(clean_lines.NumLines()): + ProcessLine(filename, file_extension, clean_lines, line, + include_state, function_state, nesting_state, error, + extra_check_functions) + FlagCxx11Features(filename, clean_lines, line, error) + nesting_state.CheckCompletedBlocks(filename, error) + + CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error) + + # Check that the .cc file has included its header if it exists. + if _IsSourceExtension(file_extension): + CheckHeaderFileIncluded(filename, include_state, error) + + # We check here rather than inside ProcessLine so that we see raw + # lines rather than "cleaned" lines. + CheckForBadCharacters(filename, lines, error) + + CheckForNewlineAtEOF(filename, lines, error) + +def ProcessConfigOverrides(filename): + """ Loads the configuration files and processes the config overrides. + + Args: + filename: The name of the file being processed by the linter. + + Returns: + False if the current |filename| should not be processed further. + """ + + abs_filename = os.path.abspath(filename) + cfg_filters = [] + keep_looking = True + while keep_looking: + abs_path, base_name = os.path.split(abs_filename) + if not base_name: + break # Reached the root directory. + + cfg_file = os.path.join(abs_path, "CPPLINT.cfg") + abs_filename = abs_path + if not os.path.isfile(cfg_file): + continue + + try: + with open(cfg_file) as file_handle: + for line in file_handle: + line, _, _ = line.partition('#') # Remove comments. + if not line.strip(): + continue + + name, _, val = line.partition('=') + name = name.strip() + val = val.strip() + if name == 'set noparent': + keep_looking = False + elif name == 'filter': + cfg_filters.append(val) + elif name == 'exclude_files': + # When matching exclude_files pattern, use the base_name of + # the current file name or the directory name we are processing. + # For example, if we are checking for lint errors in /foo/bar/baz.cc + # and we found the .cfg file at /foo/CPPLINT.cfg, then the config + # file's "exclude_files" filter is meant to be checked against "bar" + # and not "baz" nor "bar/baz.cc". + if base_name: + pattern = re.compile(val) + if pattern.match(base_name): + if _cpplint_state.quiet: + # Suppress "Ignoring file" warning when using --quiet. + return False + _cpplint_state.PrintInfo('Ignoring "%s": file excluded by "%s". ' + 'File path component "%s" matches ' + 'pattern "%s"\n' % + (filename, cfg_file, base_name, val)) + return False + elif name == 'linelength': + global _line_length + try: + _line_length = int(val) + except ValueError: + _cpplint_state.PrintError('Line length must be numeric.') + elif name == 'extensions': + ProcessExtensionsOption(val) + elif name == 'root': + global _root + # root directories are specified relative to CPPLINT.cfg dir. + _root = os.path.join(os.path.dirname(cfg_file), val) + elif name == 'headers': + ProcessHppHeadersOption(val) + elif name == 'includeorder': + ProcessIncludeOrderOption(val) + else: + _cpplint_state.PrintError( + 'Invalid configuration option (%s) in file %s\n' % + (name, cfg_file)) + + except IOError: + _cpplint_state.PrintError( + "Skipping config file '%s': Can't open for reading\n" % cfg_file) + keep_looking = False + + # Apply all the accumulated filters in reverse order (top-level directory + # config options having the least priority). + for cfg_filter in reversed(cfg_filters): + _AddFilters(cfg_filter) + + return True + + +def ProcessFile(filename, vlevel, extra_check_functions=None): + """Does google-lint on a single file. + + Args: + filename: The name of the file to parse. + + vlevel: The level of errors to report. Every error of confidence + >= verbose_level will be reported. 0 is a good default. + + extra_check_functions: An array of additional check functions that will be + run on each source line. Each function takes 4 + arguments: filename, clean_lines, line, error + """ + + _SetVerboseLevel(vlevel) + _BackupFilters() + old_errors = _cpplint_state.error_count + + if not ProcessConfigOverrides(filename): + _RestoreFilters() + return + + lf_lines = [] + crlf_lines = [] + try: + # Support the UNIX convention of using "-" for stdin. Note that + # we are not opening the file with universal newline support + # (which codecs doesn't support anyway), so the resulting lines do + # contain trailing '\r' characters if we are reading a file that + # has CRLF endings. + # If after the split a trailing '\r' is present, it is removed + # below. + if filename == '-': + lines = codecs.StreamReaderWriter(sys.stdin, + codecs.getreader('utf8'), + codecs.getwriter('utf8'), + 'replace').read().split('\n') + else: + with codecs.open(filename, 'r', 'utf8', 'replace') as target_file: + lines = target_file.read().split('\n') + + # Remove trailing '\r'. + # The -1 accounts for the extra trailing blank line we get from split() + for linenum in range(len(lines) - 1): + if lines[linenum].endswith('\r'): + lines[linenum] = lines[linenum].rstrip('\r') + crlf_lines.append(linenum + 1) + else: + lf_lines.append(linenum + 1) + + except IOError: + _cpplint_state.PrintError( + "Skipping input '%s': Can't open for reading\n" % filename) + _RestoreFilters() + return + + # Note, if no dot is found, this will give the entire filename as the ext. + file_extension = filename[filename.rfind('.') + 1:] + + # When reading from stdin, the extension is unknown, so no cpplint tests + # should rely on the extension. + if filename != '-' and file_extension not in GetAllExtensions(): + _cpplint_state.PrintError('Ignoring %s; not a valid file name ' + '(%s)\n' % (filename, ', '.join(GetAllExtensions()))) + else: + ProcessFileData(filename, file_extension, lines, Error, + extra_check_functions) + + # If end-of-line sequences are a mix of LF and CR-LF, issue + # warnings on the lines with CR. + # + # Don't issue any warnings if all lines are uniformly LF or CR-LF, + # since critique can handle these just fine, and the style guide + # doesn't dictate a particular end of line sequence. + # + # We can't depend on os.linesep to determine what the desired + # end-of-line sequence should be, since that will return the + # server-side end-of-line sequence. + if lf_lines and crlf_lines: + # Warn on every line with CR. An alternative approach might be to + # check whether the file is mostly CRLF or just LF, and warn on the + # minority, we bias toward LF here since most tools prefer LF. + for linenum in crlf_lines: + Error(filename, linenum, 'whitespace/newline', 1, + 'Unexpected \\r (^M) found; better to use only \\n') + + # Suppress printing anything if --quiet was passed unless the error + # count has increased after processing this file. + if not _cpplint_state.quiet or old_errors != _cpplint_state.error_count: + _cpplint_state.PrintInfo('Done processing %s\n' % filename) + _RestoreFilters() + + +def PrintUsage(message): + """Prints a brief usage string and exits, optionally with an error message. + + Args: + message: The optional error message. + """ + sys.stderr.write(_USAGE % (list(GetAllExtensions()), + ','.join(list(GetAllExtensions())), + GetHeaderExtensions(), + ','.join(GetHeaderExtensions()))) + + if message: + sys.exit('\nFATAL ERROR: ' + message) + else: + sys.exit(0) + +def PrintVersion(): + sys.stdout.write('Cpplint fork (https://github.com/cpplint/cpplint)\n') + sys.stdout.write('cpplint ' + __VERSION__ + '\n') + sys.stdout.write('Python ' + sys.version + '\n') + sys.exit(0) + +def PrintCategories(): + """Prints a list of all the error-categories used by error messages. + + These are the categories used to filter messages via --filter. + """ + sys.stderr.write(''.join(' %s\n' % cat for cat in _ERROR_CATEGORIES)) + sys.exit(0) + + +def ParseArguments(args): + """Parses the command line arguments. + + This may set the output format and verbosity level as side-effects. + + Args: + args: The command line arguments: + + Returns: + The list of filenames to lint. + """ + try: + (opts, filenames) = getopt.getopt(args, '', ['help', 'output=', 'verbose=', + 'v=', + 'version', + 'counting=', + 'filter=', + 'root=', + 'repository=', + 'linelength=', + 'extensions=', + 'exclude=', + 'recursive', + 'headers=', + 'includeorder=', + 'quiet']) + except getopt.GetoptError: + PrintUsage('Invalid arguments.') + + verbosity = _VerboseLevel() + output_format = _OutputFormat() + filters = '' + quiet = _Quiet() + counting_style = '' + recursive = False + + for (opt, val) in opts: + if opt == '--help': + PrintUsage(None) + if opt == '--version': + PrintVersion() + elif opt == '--output': + if val not in ('emacs', 'vs7', 'eclipse', 'junit', 'sed', 'gsed'): + PrintUsage('The only allowed output formats are emacs, vs7, eclipse ' + 'sed, gsed and junit.') + output_format = val + elif opt == '--quiet': + quiet = True + elif opt == '--verbose' or opt == '--v': + verbosity = int(val) + elif opt == '--filter': + filters = val + if not filters: + PrintCategories() + elif opt == '--counting': + if val not in ('total', 'toplevel', 'detailed'): + PrintUsage('Valid counting options are total, toplevel, and detailed') + counting_style = val + elif opt == '--root': + global _root + _root = val + elif opt == '--repository': + global _repository + _repository = val + elif opt == '--linelength': + global _line_length + try: + _line_length = int(val) + except ValueError: + PrintUsage('Line length must be digits.') + elif opt == '--exclude': + global _excludes + if not _excludes: + _excludes = set() + _excludes.update(glob.glob(val)) + elif opt == '--extensions': + ProcessExtensionsOption(val) + elif opt == '--headers': + ProcessHppHeadersOption(val) + elif opt == '--recursive': + recursive = True + elif opt == '--includeorder': + ProcessIncludeOrderOption(val) + + if not filenames: + PrintUsage('No files were specified.') + + if recursive: + filenames = _ExpandDirectories(filenames) + + if _excludes: + filenames = _FilterExcludedFiles(filenames) + + _SetOutputFormat(output_format) + _SetQuiet(quiet) + _SetVerboseLevel(verbosity) + _SetFilters(filters) + _SetCountingStyle(counting_style) + + filenames.sort() + return filenames + +def _ExpandDirectories(filenames): + """Searches a list of filenames and replaces directories in the list with + all files descending from those directories. Files with extensions not in + the valid extensions list are excluded. + + Args: + filenames: A list of files or directories + + Returns: + A list of all files that are members of filenames or descended from a + directory in filenames + """ + expanded = set() + for filename in filenames: + if not os.path.isdir(filename): + expanded.add(filename) + continue + + for root, _, files in os.walk(filename): + for loopfile in files: + fullname = os.path.join(root, loopfile) + if fullname.startswith('.' + os.path.sep): + fullname = fullname[len('.' + os.path.sep):] + expanded.add(fullname) + + filtered = [] + for filename in expanded: + if os.path.splitext(filename)[1][1:] in GetAllExtensions(): + filtered.append(filename) + return filtered + +def _FilterExcludedFiles(fnames): + """Filters out files listed in the --exclude command line switch. File paths + in the switch are evaluated relative to the current working directory + """ + exclude_paths = [os.path.abspath(f) for f in _excludes] + # because globbing does not work recursively, exclude all subpath of all excluded entries + return [f for f in fnames + if not any(e for e in exclude_paths + if _IsParentOrSame(e, os.path.abspath(f)))] + +def _IsParentOrSame(parent, child): + """Return true if child is subdirectory of parent. + Assumes both paths are absolute and don't contain symlinks. + """ + parent = os.path.normpath(parent) + child = os.path.normpath(child) + if parent == child: + return True + + prefix = os.path.commonprefix([parent, child]) + if prefix != parent: + return False + # Note: os.path.commonprefix operates on character basis, so + # take extra care of situations like '/foo/ba' and '/foo/bar/baz' + child_suffix = child[len(prefix):] + child_suffix = child_suffix.lstrip(os.sep) + return child == os.path.join(prefix, child_suffix) + +def main(): + filenames = ParseArguments(sys.argv[1:]) + backup_err = sys.stderr + try: + # Change stderr to write with replacement characters so we don't die + # if we try to print something containing non-ASCII characters. + sys.stderr = codecs.StreamReader(sys.stderr, 'replace') + + _cpplint_state.ResetErrorCounts() + for filename in filenames: + ProcessFile(filename, _cpplint_state.verbose_level) + # If --quiet is passed, suppress printing error count unless there are errors. + if not _cpplint_state.quiet or _cpplint_state.error_count > 0: + _cpplint_state.PrintErrorCounts() + + if _cpplint_state.output_format == 'junit': + sys.stderr.write(_cpplint_state.FormatJUnitXML()) + + finally: + sys.stderr = backup_err + + sys.exit(_cpplint_state.error_count > 0) + + +if __name__ == '__main__': + main() diff --git a/demo_storage/predefine.h b/demo_storage/predefine.h new file mode 100644 index 0000000..9fa45fe --- /dev/null +++ b/demo_storage/predefine.h @@ -0,0 +1,923 @@ +/** Copyright 2020 Alibaba Group Holding Limited. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/** + * @file predefine.h + * @brief Pre-defined macros for storage features. + * The macros are divided into several sections such as topology, partition, + * and so on. + * In each section, the first part lists all available macros, and undefines + * all GRIN_ASSUME_ macros by default. + * After that is the MOST IMPORTANT part for storage implementors, i.e., the + * StorageSpecific area. Storage implementors should turn ON/OFF the macros in + * this area based the features of the storage. The final part is the rule part + * to handle dependencies between macros which should not be edited. + */ + +#ifndef GRIN_INCLUDE_PREDEFINE_H_ +#define GRIN_INCLUDE_PREDEFINE_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/// Enumerates the directions of edges with respect to a certain vertex +typedef enum { + IN = 0, ///< incoming + OUT = 1, ///< outgoing + BOTH = 2, ///< incoming & outgoing +} GRIN_DIRECTION; + +/// Enumerates the datatype supported in the storage +typedef enum { + Undefined = 0, ///< other unknown types + Int32 = 1, ///< int + UInt32 = 2, ///< unsigned int + Int64 = 3, ///< long int + UInt64 = 4, ///< unsigned long int + Float = 5, ///< float + Double = 6, ///< double + String = 7, ///< string + Date32 = 8, ///< date + Time32 = 9, ///< Time32 + Timestamp64 = 10, ///< Timestamp +} GRIN_DATATYPE; + +/// Enumerates the error codes of grin +typedef enum { + NO_ERROR = 0, ///< success + UNKNOWN_ERROR = 1, ///< unknown error + INVALID_VALUE = 2, ///< invalid value + UNKNOWN_DATATYPE = 3, ///< unknown datatype +} GRIN_ERROR_CODE; + +/* Section 1: Toplogy */ + +/** @name TopologyMacros + * @brief Macros for basic graph topology features + */ +///@{ +/** @ingroup TopologyMacros + * @brief The storage only support directed graphs. + */ +#define GRIN_ASSUME_HAS_DIRECTED_GRAPH + +/** @ingroup TopologyMacros + * @brief The storage only support undirected graphs. + */ +#define GRIN_ASSUME_HAS_UNDIRECTED_GRAPH + +/** @ingroup TopologyMacros + * @brief The storage only support graphs with single + * edge between a pair of vertices. + */ +#define GRIN_ASSUME_HAS_MULTI_EDGE_GRAPH + +/** @ingroup TopologyMacros + * @brief There is data on vertex. E.g., the PageRank value of a vertex. + */ +#define GRIN_WITH_VERTEX_DATA + +/** @ingroup TopologyMacros + * @brief There is data on edge. E.g., the weight of an edge. + */ +#define GRIN_WITH_EDGE_DATA + +/** @ingroup TopologyMacros + * @brief Enable the vertex list structure. + * The vertex list related APIs follow the design of GRIN List. + */ +#define GRIN_ENABLE_VERTEX_LIST + +/** @ingroup TopologyMacros + * @brief Enable the vertex list array-style retrieval. + * The vertex list related APIs follow the design of GRIN List. + */ +#define GRIN_ENABLE_VERTEX_LIST_ARRAY + +/** @ingroup TopologyMacros + * @brief Enable the vertex list iterator. + * The vertex list iterator related APIs follow the design of GRIN Iterator. + */ +#define GRIN_ENABLE_VERTEX_LIST_ITERATOR + +/** @ingroup TopologyMacros + * @brief Enable the edge list structure. + * The edge list related APIs follow the design of GRIN List. + */ +#define GRIN_ENABLE_EDGE_LIST + +/** @ingroup TopologyMacros + * @brief Enable the edge list array-style retrieval. + * The edge list related APIs follow the design of GRIN List. + */ +#define GRIN_ENABLE_EDGE_LIST_ARRAY + +/** @ingroup TopologyMacros + * @brief Enable the edge list iterator. + * The edge list iterator related APIs follow the design of GRIN Iterator. + */ +#define GRIN_ENABLE_EDGE_LIST_ITERATOR + +/** @ingroup TopologyMacros + * @brief Enable the adjacent list structure. + * The adjacent list related APIs follow the design of GRIN List. + */ +#define GRIN_ENABLE_ADJACENT_LIST + +/** @ingroup TopologyMacros + * @brief Enable the adjacent list array-style retrieval. + * The adjacent list related APIs follow the design of GRIN List. + */ +#define GRIN_ENABLE_ADJACENT_LIST_ARRAY + +/** @ingroup TopologyMacros + * @brief Enable the adjacent list iterator. + * The adjacent list iterator related APIs follow the design of GRIN Iterator. + */ +#define GRIN_ENABLE_ADJACENT_LIST_ITERATOR +///@} + +#ifndef GRIN_DOXYGEN_SKIP +// GRIN_DEFAULT_DISABLE +#undef GRIN_ASSUME_HAS_DIRECTED_GRAPH +#undef GRIN_ASSUME_HAS_UNDIRECTED_GRAPH +#undef GRIN_ASSUME_HAS_MULTI_EDGE_GRAPH +#undef GRIN_WITH_VERTEX_DATA +#undef GRIN_WITH_EDGE_DATA +#undef GRIN_ENABLE_VERTEX_LIST +#undef GRIN_ENABLE_VERTEX_LIST_ARRAY +#undef GRIN_ENABLE_VERTEX_LIST_ITERATOR +#undef GRIN_ENABLE_EDGE_LIST +#undef GRIN_ENABLE_EDGE_LIST_ARRAY +#undef GRIN_ENABLE_EDGE_LIST_ITERATOR +#undef GRIN_ENABLE_ADJACENT_LIST +#undef GRIN_ENABLE_ADJACENT_LIST_ARRAY +#undef GRIN_ENABLE_ADJACENT_LIST_ITERATOR +// GRIN_END + +// GRIN_STORAGE_ENABLE +#define GRIN_ASSUME_HAS_DIRECTED_GRAPH +#define GRIN_ASSUME_HAS_UNDIRECTED_GRAPH +#define GRIN_ASSUME_HAS_MULTI_EDGE_GRAPH +#define GRIN_WITH_VERTEX_DATA +#define GRIN_WITH_EDGE_DATA +#define GRIN_ENABLE_VERTEX_LIST +#define GRIN_ENABLE_VERTEX_LIST_ARRAY +#define GRIN_ENABLE_VERTEX_LIST_ITERATOR +#define GRIN_ENABLE_EDGE_LIST +#define GRIN_ENABLE_EDGE_LIST_ARRAY +#define GRIN_ENABLE_EDGE_LIST_ITERATOR +#define GRIN_ENABLE_ADJACENT_LIST +#define GRIN_ENABLE_ADJACENT_LIST_ARRAY +#define GRIN_ENABLE_ADJACENT_LIST_ITERATOR +// GRIN_END + +// GRIN_FEATURE_DEPENDENCY +// GRIN_END + +#endif // GRIN_DOXYGEN_SKIP +/* End of Section 1 */ + +/* Section 2. Partition */ + +/** @name PartitionMacros + * @brief Macros for partitioned graph features + */ +///@{ +/** @ingroup PartitionMacros + * @brief Enable partitioned graph. A partitioned graph usually contains + * several fragments (i.e., local graphs) that are distributedly stored + * in a cluster. In GRIN, GRIN_GRAPH represents to a single fragment that can + * be locally accessed. + */ +#define GRIN_ENABLE_GRAPH_PARTITION + +/** @ingroup PartitionMacros + * @brief The storage provides natural number IDs for partitions. + * It follows the design of natural number ID trait in GRIN. + */ +#define GRIN_TRAIT_NATURAL_ID_FOR_PARTITION + +/** @ingroup PartitionMacros + * @brief The storage provides reference of vertex that can be + * recognized in other partitions where the vertex also appears. + */ +#define GRIN_ENABLE_VERTEX_REF + +/** @ingroup PartitionMacros + * @brief The storage provides fast reference of vertex, which means + * the vertex ref can be serialized into a int64 using + * grin_serialize_vertex_ref_as_int64 + */ +#define GRIN_TRAIT_FAST_VERTEX_REF + +/** @ingroup PartitionMacros + * @brief The storage provides reference of edge that can be + * recognized in other partitions where the edge also appears. + */ +#define GRIN_ENABLE_EDGE_REF +///@} + +/** @name PartitionStrategyMacros + * @brief Macros to define partition strategy assumptions, a partition strategy + * can be seen as a combination of detail partition assumptions which are + * defined after the strategies. Please refer to the documents for strategy + * details. + */ +///@{ +/** @ingroup PartitionStrategyMacros + * @brief The storage ONLY uses all-replicate partition strategy. This means the + * storage's replicate the graph among all partitions. + */ +#define GRIN_ASSUME_ALL_REPLICATE_PARTITION + +/** @ingroup PartitionStrategyMacros + * @brief The storage ONLY uses edge-cut partition strategy. This means the + * storage's entire partition strategy complies with edge-cut strategy + * definition in GRIN. + */ +#define GRIN_ASSUME_EDGE_CUT_PARTITION + +/** @ingroup PartitionStrategyMacros + * @brief The storage ONLY uses edge-cut partition & edges only follow src + * strategy. This means the storage's entire partition strategy complies with + * edge-cut strategy definition in GRIN, and edges are partitioned to the + * partition of the source vertex. + */ +#define GRIN_ASSUME_EDGE_CUT_FOLLOW_SRC_PARTITION + +/** @ingroup PartitionStrategyMacros + * @brief The storage ONLY uses edge-cut partition & edges only follow dst + * strategy. This means the storage's entire partition strategy complies with + * edge-cut strategy definition in GRIN, and edges are partitioned to the + * partition of the destination vertex. + */ +#define GRIN_ASSUME_EDGE_CUT_FOLLOW_DST_PARTITION + +/** @ingroup PartitionStrategyMacros + * @brief The storage ONLY uses vertex-cut partition strategy. This means the + * storage's entire partition strategy complies with vertex-cut strategy + * definition in GRIN. + */ +#define GRIN_ASSUME_VERTEX_CUT_PARTITION +///@} + +/** @name PartitionAssumptionMacros + * @brief Macros to define detailed partition assumptions with respect to the + * concept of local complete. Please refer to the documents for the meaning of + * local complete. + */ +///@{ +/** @ingroup PartitionAssumptionMacros + * @brief Assume the vertex data are only stored together with master vertices. + */ +#define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_VERTEX_DATA + +/** @ingroup PartitionAssumptionMacros + * @brief Assume the vertex data are replicated on both master and mirror + * vertices. + */ +#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_VERTEX_DATA + +/** @ingroup PartitionAssumptionMacros + * @brief Assume the edge data are only stored together with master edges. + */ +#define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_EDGE_DATA + +/** @ingroup PartitionAssumptionMacros + * @brief Assume the edge data are replicated on both master and mirror edges. + */ +#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_EDGE_DATA +///@} + +/** @name TraitMirrorPartitionMacros + * @brief Macros for storage that provides the partition list where the mirror + * vertices are located. This trait is usually enabled by storages using + * vertex-cut partition strategy. + */ +///@{ +/** @ingroup TraitMirrorPartitionMacros + * @brief The storage provides the partition list where the mirror + * vertices are located of a local master vertex. + */ +#define GRIN_TRAIT_MASTER_VERTEX_MIRROR_PARTITION_LIST + +/** @ingroup TraitMirrorPartitionMacros + * @brief The storage provides the partition list where the mirror + * vertices are located of a local mirror vertex + */ +#define GRIN_TRAIT_MIRROR_VERTEX_MIRROR_PARTITION_LIST + +/** @ingroup TraitMirrorPartitionMacros + * @brief The storage provides the partition list where the mirror + * edges are located of a local master edge + */ +#define GRIN_TRAIT_MASTER_EDGE_MIRROR_PARTITION_LIST + +/** @ingroup TraitMirrorPartitionMacros + * @brief The storage provides the partition list where the mirror + * edges are located of a local mirror edge + */ +#define GRIN_TRAIT_MIRROR_EDGE_MIRROR_PARTITION_LIST +///@} + +/** @name TraitFilterMacros + * @brief Macros for storage that provides filtering ability of partitions for + * structures like vertex list or adjacent list. This trait is usually enabled + * for efficient graph traversal. + */ +///@{ +/** @ingroup TraitFilterMacros + * @brief The storage provides a filtering predicate of master vertices + * for vertex list iterator. That means, the caller can use the predicate + * to make a master-only vertex list iterator from the original iterator. + */ +#define GRIN_TRAIT_SELECT_MASTER_FOR_VERTEX_LIST + +/** @ingroup TraitFilterMacros + * @brief The storage provides a filtering predicate of single partition + * vertices for vertex list iterator. That means, the caller can use the + * predicate to make a single-partition vertex list iterator from the original + * iterator. + */ +#define GRIN_TRAIT_SELECT_PARTITION_FOR_VERTEX_LIST + +/** @ingroup TraitFilterMacros + * @brief The storage provides a filtering predicate of master edges + * for edge list iterator. That means, the caller can use the predicate + * to make a master-only edge list iterator from the original iterator. + */ +#define GRIN_TRAIT_SELECT_MASTER_FOR_EDGE_LIST + +/** @ingroup TraitFilterMacros + * @brief The storage provides a filtering predicate of single partition edges + * for edge list iterator. That means, the caller can use the predicate + * to make a single-partition edge list iterator from the original iterator. + */ +#define GRIN_TRAIT_SELECT_PARTITION_FOR_EDGE_LIST + +/** @ingroup TraitFilterMacros + * @brief The storage provides a filtering predicate of master neighbors + * for adjacent list iterator. That means, the caller can use the predicate + * to make a master-only adjacent list iterator from the original iterator. + */ +#define GRIN_TRAIT_SELECT_MASTER_NEIGHBOR_FOR_ADJACENT_LIST + +/** @ingroup TraitFilterMacros + * @brief The storage provides a filtering predicate of single-partition + * vertices for adjacent list iterator. That means, the caller can use the + * predicate to make a single-partition adjacent list iterator from the original + * iterator. + */ +#define GRIN_TRAIT_SELECT_NEIGHBOR_PARTITION_FOR_ADJACENT_LIST +///@} + +#ifndef GRIN_DOXYGEN_SKIP +// GRIN_DEFAULT_DISABLE +#undef GRIN_ENABLE_GRAPH_PARTITION +#undef GRIN_TRAIT_NATURAL_ID_FOR_PARTITION +#undef GRIN_ENABLE_VERTEX_REF +#undef GRIN_TRAIT_FAST_VERTEX_REF +#undef GRIN_ENABLE_EDGE_REF +#undef GRIN_ASSUME_ALL_REPLICATE_PARTITION +#undef GRIN_ASSUME_EDGE_CUT_PARTITION +#undef GRIN_ASSUME_EDGE_CUT_FOLLOW_SRC_PARTITION +#undef GRIN_ASSUME_EDGE_CUT_FOLLOW_DST_PARTITION +#undef GRIN_ASSUME_VERTEX_CUT_PARTITION +#undef GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_VERTEX_DATA +#undef GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_VERTEX_DATA +#undef GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_EDGE_DATA +#undef GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_EDGE_DATA +#undef GRIN_TRAIT_MASTER_VERTEX_MIRROR_PARTITION_LIST +#undef GRIN_TRAIT_MIRROR_VERTEX_MIRROR_PARTITION_LIST +#undef GRIN_TRAIT_MASTER_EDGE_MIRROR_PARTITION_LIST +#undef GRIN_TRAIT_MIRROR_EDGE_MIRROR_PARTITION_LIST +#undef GRIN_TRAIT_SELECT_MASTER_FOR_VERTEX_LIST +#undef GRIN_TRAIT_SELECT_PARTITION_FOR_VERTEX_LIST +#undef GRIN_TRAIT_SELECT_MASTER_FOR_EDGE_LIST +#undef GRIN_TRAIT_SELECT_PARTITION_FOR_EDGE_LIST +#undef GRIN_TRAIT_SELECT_MASTER_NEIGHBOR_FOR_ADJACENT_LIST +#undef GRIN_TRAIT_SELECT_NEIGHBOR_PARTITION_FOR_ADJACENT_LIST +// GRIN_END + +// GRIN_STORAGE_ENABLE +#define GRIN_ENABLE_GRAPH_PARTITION +#define GRIN_TRAIT_NATURAL_ID_FOR_PARTITION +#define GRIN_ENABLE_VERTEX_REF +#define GRIN_TRAIT_FAST_VERTEX_REF +#define GRIN_ENABLE_EDGE_REF +#define GRIN_ASSUME_ALL_REPLICATE_PARTITION +#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_VERTEX_DATA +#define GRIN_TRAIT_MASTER_VERTEX_MIRROR_PARTITION_LIST +#define GRIN_TRAIT_MIRROR_VERTEX_MIRROR_PARTITION_LIST +#define GRIN_TRAIT_MASTER_EDGE_MIRROR_PARTITION_LIST +#define GRIN_TRAIT_MIRROR_EDGE_MIRROR_PARTITION_LIST +#define GRIN_TRAIT_SELECT_MASTER_FOR_VERTEX_LIST +#define GRIN_TRAIT_SELECT_PARTITION_FOR_VERTEX_LIST +#define GRIN_TRAIT_SELECT_MASTER_FOR_EDGE_LIST +#define GRIN_TRAIT_SELECT_PARTITION_FOR_EDGE_LIST +#define GRIN_TRAIT_SELECT_MASTER_NEIGHBOR_FOR_ADJACENT_LIST +#define GRIN_TRAIT_SELECT_NEIGHBOR_PARTITION_FOR_ADJACENT_LIST +// GRIN_END + +// GRIN_FEATURE_DEPENDENCY +#ifdef GRIN_ASSUME_ALL_REPLICATE_PARTITION +#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_VERTEX_DATA +#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_EDGE_DATA +#endif + +#ifdef GRIN_ASSUME_EDGE_CUT_PARTITION +#define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_VERTEX_DATA +#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_EDGE_DATA +#endif + +#ifdef GRIN_ASSUME_EDGE_CUT_FOLLOW_SRC_PARTITION +#define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_VERTEX_DATA +#define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_EDGE_DATA +#endif + +#ifdef GRIN_ASSUME_EDGE_CUT_FOLLOW_DST_PARTITION +#define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_VERTEX_DATA +#define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_EDGE_DATA +#endif + +#ifdef GRIN_ASSUME_VERTEX_CUT_PARTITION +#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_VERTEX_DATA +#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_EDGE_DATA +#define GRIN_TRAIT_MASTER_VERTEX_MIRROR_PARTITION_LIST +#endif +// GRIN_END + +#endif // GRIN_DOXY_SKIP +/* End of Section 2 */ + +/* Section 3. Property */ + +/** @name PropertyMacros + * @brief Macros for basic property graph features + */ +///@{ +/** @ingroup PropertyMacros + * @brief Enable the pure data structure Row + */ +#define GRIN_ENABLE_ROW + +/** @ingroup PropertyMacros + * @brief This trait is used to indicate the storage can return a pointer to the + * value of a property. + */ +#define GRIN_TRAIT_CONST_VALUE_PTR + +/** @ingroup PropertyMacros + * @brief There are properties bound to vertices. When vertices are typed, + * vertex properties are bound to vertex types, according to the definition of + * vertex type. + */ +#define GRIN_WITH_VERTEX_PROPERTY + +/** @ingroup PropertyMacros + * @brief There are property names for vertex properties. The relationship + * between property name and properties is one-to-many, because properties bound + * to different vertex/edge types are distinguished even they may share the same + * property name. Please refer to the design of Property for details. + */ +#define GRIN_WITH_VERTEX_PROPERTY_NAME + +/** @ingroup PropertyMacros + * @brief There are unique names for each vertex type. + */ +#define GRIN_WITH_VERTEX_TYPE_NAME + +/** @ingroup PropertyMacros + * @brief The storage provides natural number IDs for vertex types. + * It follows the design of natural ID trait in GRIN. + */ +#define GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_TYPE + +/** @ingroup PropertyMacros + * @brief There are primary keys for vertices. Vertex primary keys is + * a set of vertex properties whose values can distinguish vertices. When + * vertices are typed, each vertex type has its own primary keys which + * distinguishes the vertices of that type. + * + * With primary keys, one can get the vertex from the graph or a certain type + * by providing the values of the primary keys. The macro is unset if + * GRIN_WITH_VERTEX_PROPERTY is NOT defined, in which case, one can use + * ORIGINAL_ID when vertices have no properties. + */ +#define GRIN_ENABLE_VERTEX_PRIMARY_KEYS + +/** @ingroup PropertyMacros + * @brief The storage provides natural number IDs for properties bound to + * a certain vertex type. + * It follows the design of natural ID trait in GRIN. + */ +#define GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_PROPERTY + +/** @ingroup PropertyMacros + * @brief There are properties bound to edges. When edges are typed, edge + * properties are bound to edge types, according to the definition of edge type. + */ +#define GRIN_WITH_EDGE_PROPERTY + +/** @ingroup PropertyMacros + * @brief There are property names for edge properties. The relationship between + * property name and properties is one-to-many, because properties bound to + * different vertex/edge types are distinguished even they may share the same + * property name. Please refer to the design of Property for details. + */ +#define GRIN_WITH_EDGE_PROPERTY_NAME + +/** @ingroup PropertyMacros + * @brief There are unique names for each edge type. + */ +#define GRIN_WITH_EDGE_TYPE_NAME + +/** @ingroup PropertyMacros + * @brief The storage provides natural number IDs for edge types. + * It follows the design of natural ID trait in GRIN. + */ +#define GRIN_TRAIT_NATURAL_ID_FOR_EDGE_TYPE + +/** @ingroup PropertyMacros + * @brief There are primary keys for edges. Edge primary keys is + * a set of edge properties whose values can distinguish edges. When edges are + * typed, each edge type has its own primary keys which distinguishes the edges + * of that type. + * + * With primary keys, one can get the edge from the graph or a certain type + * by providing the values of the primary keys. The macro is unset if + * GRIN_WITH_EDGE_PROPERTY is NOT defined. + */ +#define GRIN_ENABLE_EDGE_PRIMARY_KEYS + +/** @ingroup PropertyMacros + * @brief The storage provides natural number IDs for properties bound to + * a certain edge type. + * It follows the design of natural ID trait in GRIN. + */ +#define GRIN_TRAIT_NATURAL_ID_FOR_EDGE_PROPERTY +///@} + +/** @name TraitFilterTypeMacros + * @brief Macros of traits to filter vertex/edge type for + * structures like vertex list and adjacent list. + */ +///@{ +/** @ingroup TraitFilterTypeMacros + * @brief The storage provides specific relationship description for each + * vertex-edge-vertex type traid. This means further optimizations can be + * applied by the callers for vev traid under certain relationships, such as + * one-to-one, one-to-many, or many-to-one. + */ +#define GRIN_TRAIT_SPECIFIC_VEV_RELATION +///@} + +/** @name PropetyAssumptionMacros + * @brief Macros of assumptions for property local complete, and particularly + * define the by type local complete assumptions for hybrid partiton strategy. + */ +///@{ +/** @ingroup PropetyAssumptionMacros + * @brief Assume full property values of a vertex are ONLY stored with master + * vertices. + */ +#define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_VERTEX_PROPERTY + +/** @ingroup PropetyAssumptionMacros + * @brief Assume full property values of a vertex are replicated with master and + * mirror vertices. + */ +#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_VERTEX_PROPERTY + +/** @ingroup PropetyAssumptionMacros + * @brief Assume full property values of a vertex are split among master and + * mirror vertices. + */ +#define GRIN_ASSUME_SPLIT_MASTER_MIRROR_PARTITION_FOR_VERTEX_PROPERTY + +/** @ingroup PropetyAssumptionMacros + * @brief Assume full property values of an edge are ONLY stored with master + * edges. + */ +#define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_EDGE_PROPERTY + +/** @ingroup PropetyAssumptionMacros + * @brief Assume full property values of an edge are replicated with master and + * mirror edges. + */ +#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_EDGE_PROPERTY + +/** @ingroup PropetyAssumptionMacros + * @brief Assume full property values of an edge are split among master and + * mirror edges. + */ +#define GRIN_ASSUME_SPLIT_MASTER_MIRROR_PARTITION_FOR_EDGE_PROPERTY +///@} + +#ifndef GRIN_DOXYGEN_SKIP +// GRIN_DEFAULT_DISABLE +#undef GRIN_ENABLE_ROW +#undef GRIN_TRAIT_CONST_VALUE_PTR +#undef GRIN_WITH_VERTEX_PROPERTY +#undef GRIN_WITH_VERTEX_PROPERTY_NAME +#undef GRIN_WITH_VERTEX_TYPE_NAME +#undef GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_TYPE +#undef GRIN_ENABLE_VERTEX_PRIMARY_KEYS +#undef GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_PROPERTY +#undef GRIN_WITH_EDGE_PROPERTY +#undef GRIN_WITH_EDGE_PROPERTY_NAME +#undef GRIN_WITH_EDGE_TYPE_NAME +#undef GRIN_TRAIT_NATURAL_ID_FOR_EDGE_TYPE +#undef GRIN_ENABLE_EDGE_PRIMARY_KEYS +#undef GRIN_TRAIT_NATURAL_ID_FOR_EDGE_PROPERTY +#undef GRIN_TRAIT_SPECIFIC_VEV_RELATION +#undef GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_VERTEX_PROPERTY +#undef GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_VERTEX_PROPERTY +#undef GRIN_ASSUME_SPLIT_MASTER_MIRROR_PARTITION_FOR_VERTEX_PROPERTY +#undef GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_EDGE_PROPERTY +#undef GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_EDGE_PROPERTY +#undef GRIN_ASSUME_SPLIT_MASTER_MIRROR_PARTITION_FOR_EDGE_PROPERTY +// GRIN_END + +// GRIN_STORAGE_ENABLE +#define GRIN_ENABLE_ROW +#define GRIN_TRAIT_CONST_VALUE_PTR +#define GRIN_WITH_VERTEX_PROPERTY +#define GRIN_WITH_VERTEX_PROPERTY_NAME +#define GRIN_WITH_VERTEX_TYPE_NAME +#define GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_TYPE +#define GRIN_ENABLE_VERTEX_PRIMARY_KEYS +#define GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_PROPERTY +#define GRIN_WITH_EDGE_PROPERTY +#define GRIN_WITH_EDGE_PROPERTY_NAME +#define GRIN_WITH_EDGE_TYPE_NAME +#define GRIN_TRAIT_NATURAL_ID_FOR_EDGE_TYPE +#define GRIN_ENABLE_EDGE_PRIMARY_KEYS +#define GRIN_TRAIT_NATURAL_ID_FOR_EDGE_PROPERTY +// GRIN_END + +// GRIN_FEATURE_DEPENDENCY +#ifdef GRIN_ASSUME_ALL_REPLICATE_PARTITION +#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_VERTEX_PROPERTY +#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_EDGE_PROPERTY +#endif + +#ifdef GRIN_ASSUME_EDGE_CUT_PARTITION +#define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_VERTEX_PROPERTY +#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_EDGE_PROPERTY +#endif + +#ifdef GRIN_ASSUME_EDGE_CUT_FOLLOW_SRC_PARTITION +#define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_VERTEX_PROPERTY +#define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_EDGE_PROPERTY +#endif + +#ifdef GRIN_ASSUME_EDGE_CUT_FOLLOW_DST_PARTITION +#define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_VERTEX_PROPERTY +#define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_EDGE_PROPERTY +#endif + +#ifdef GRIN_ASSUME_VERTEX_CUT_PARTITION +#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_VERTEX_PROPERTY +#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_EDGE_PROPERTY +#endif + +#ifdef GRIN_ENABLE_VERTEX_PRIMARY_KEYS +#define GRIN_ENABLE_ROW +#endif + +#ifdef GRIN_ENABLE_EDGE_PRIMARY_KEYS +#define GRIN_ENABLE_ROW +#endif +// GRIN_END + +#endif // GRIN_DOXY_SKIP +/* End of Section 3 */ + +/* Section 4. Index */ +/** @name IndexLabelMacros + * @brief Macros for label features + */ +///@{ +/** @ingroup IndexLabelMacros + * @brief Enable vertex label on graph. + */ +#define GRIN_WITH_VERTEX_LABEL + +/** @ingroup IndexLabelMacros + * @brief Enable edge label on graph. + */ +#define GRIN_WITH_EDGE_LABEL +///@} + +/** @name IndexOrderMacros + * @brief Macros for ordering features. + * Please refer to the order section in the documents for details. + */ +///@{ +/** @ingroup IndexOrderMacros + * @brief assume all vertex list are sorted. + * We will expend the assumption to support master/mirror or + * by type in the future if needed. + */ +#define GRIN_ASSUME_ALL_VERTEX_LIST_SORTED +///@} + +/** @name IndexOIDMacros + * @brief Macros for label features + */ +///@{ +/** @ingroup IndexOIDMacros + * @brief There is original ID of type int64 for each vertex + * This facilitates queries starting from a specific vertex, + * since one can get the vertex handler directly using its original ID. + */ +#define GRIN_ENABLE_VERTEX_ORIGINAL_ID_OF_INT64 + +/** @ingroup IndexOIDMacros + * @brief There is original ID of type string for each vertex + * This facilitates queries starting from a specific vertex, + * since one can get the vertex handler directly using its original ID. + */ +#define GRIN_ENABLE_VERTEX_ORIGINAL_ID_OF_STRING +///@} + +#ifndef GRIN_DOXYGEN_SKIP +// GRIN_DEFAULT_DISABLE +#undef GRIN_WITH_VERTEX_LABEL +#undef GRIN_WITH_EDGE_LABEL +#undef GRIN_ASSUME_ALL_VERTEX_LIST_SORTED +#undef GRIN_ENABLE_VERTEX_ORIGINAL_ID_OF_INT64 +#undef GRIN_ENABLE_VERTEX_ORIGINAL_ID_OF_STRING +// GRIN_END + +// GRIN_STORAGE_ENABLE +#define GRIN_WITH_VERTEX_LABEL +#define GRIN_WITH_EDGE_LABEL +#define GRIN_ASSUME_ALL_VERTEX_LIST_SORTED +#define GRIN_ENABLE_VERTEX_ORIGINAL_ID_OF_INT64 +#define GRIN_ENABLE_VERTEX_ORIGINAL_ID_OF_STRING +// GRIN_END + +// GRIN_FEATURE_DEPENDENCY +// GRIN_END + +#endif // GRIN_DOXYGEN_SKIP +/* End of Section 4 */ + +/** @name NullValues + * Macros for Null(invalid) values + */ +///@{ +/** @brief Null graph (invalid return value) */ +#define GRIN_NULL_GRAPH NULL +/** @brief Non-existing vertex (invalid return value) */ +#define GRIN_NULL_VERTEX -1 +/** @brief Non-existing edge (invalid return value) */ +#define GRIN_NULL_EDGE -1 +/** @brief Null list of any kind (invalid return value) */ +#define GRIN_NULL_LIST NULL +/** @brief Null list iterator of any kind (invalid return value) */ +#define GRIN_NULL_LIST_ITERATOR NULL +/** @brief Non-existing partition (invalid return value) */ +#define GRIN_NULL_PARTITION (unsigned)~0 +/** @brief Null vertex reference (invalid return value) */ +#define GRIN_NULL_VERTEX_REF -1 +/** @brief Null edge reference (invalid return value) */ +#define GRIN_NULL_EDGE_REF -1 +/** @brief Non-existing vertex type (invalid return value) */ +#define GRIN_NULL_VERTEX_TYPE (unsigned)~0 +/** @brief Non-existing edge type (invalid return value) */ +#define GRIN_NULL_EDGE_TYPE (unsigned)~0 +/** @brief Non-existing vertex property (invalid return value) */ +#define GRIN_NULL_VERTEX_PROPERTY (unsigned)~0 +/** @brief Non-existing vertex property (invalid return value) */ +#define GRIN_NULL_EDGE_PROPERTY (unsigned)~0 +/** @brief Null row (invalid return value) */ +#define GRIN_NULL_ROW NULL +/** @brief Null natural id of any kind (invalid return value) */ +#define GRIN_NULL_NATURAL_ID (unsigned)~0 +/** @brief Null size (invalid return value) */ +#define GRIN_NULL_SIZE (unsigned)~0 +/** @breif Null name (invalid return value) */ +#define GRIN_NULL_NAME NULL +///@} + +/* Define the handlers using typedef */ +typedef void *GRIN_GRAPH; +typedef long long int GRIN_VERTEX; +typedef long long int GRIN_EDGE; + +#ifdef GRIN_WITH_VERTEX_DATA +typedef void *GRIN_VERTEX_DATA; +#endif + +#ifdef GRIN_ENABLE_VERTEX_LIST +typedef void *GRIN_VERTEX_LIST; +#endif + +#ifdef GRIN_ENABLE_VERTEX_LIST_ITERATOR +typedef void *GRIN_VERTEX_LIST_ITERATOR; +#endif + +#ifdef GRIN_ENABLE_ADJACENT_LIST +typedef void *GRIN_ADJACENT_LIST; +#endif + +#ifdef GRIN_ENABLE_ADJACENT_LIST_ITERATOR +typedef void *GRIN_ADJACENT_LIST_ITERATOR; +#endif + +#ifdef GRIN_WITH_EDGE_DATA +typedef void *GRIN_EDGE_DATA; +#endif + +#ifdef GRIN_ENABLE_EDGE_LIST +typedef void *GRIN_EDGE_LIST; +#endif + +#ifdef GRIN_ENABLE_EDGE_LIST_ITERATOR +typedef void *GRIN_EDGE_LIST_ITERATOR; +#endif + +#ifdef GRIN_ENABLE_GRAPH_PARTITION +typedef void *GRIN_PARTITIONED_GRAPH; +typedef unsigned GRIN_PARTITION; +typedef void *GRIN_PARTITION_LIST; +#endif + +#ifdef GRIN_TRAIT_NATURAL_ID_FOR_PARTITION +typedef unsigned GRIN_PARTITION_ID; +#endif + +#ifdef GRIN_ENABLE_VERTEX_REF +typedef long long int GRIN_VERTEX_REF; +#endif + +#ifdef GRIN_ENABLE_EDGE_REF +typedef long long int GRIN_EDGE_REF; +#endif + +#ifdef GRIN_WITH_VERTEX_PROPERTY +typedef unsigned GRIN_VERTEX_TYPE; +typedef void *GRIN_VERTEX_TYPE_LIST; +typedef unsigned GRIN_VERTEX_PROPERTY; +typedef void *GRIN_VERTEX_PROPERTY_LIST; +#endif + +#ifdef GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_TYPE +typedef unsigned GRIN_VERTEX_TYPE_ID; +#endif + +#ifdef GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_PROPERTY +typedef unsigned GRIN_VERTEX_PROPERTY_ID; +#endif + +#ifdef GRIN_WITH_EDGE_PROPERTY +typedef unsigned GRIN_EDGE_TYPE; +typedef void *GRIN_EDGE_TYPE_LIST; +typedef unsigned GRIN_VEV_TYPE; +typedef void *GRIN_VEV_TYPE_LIST; +typedef unsigned GRIN_EDGE_PROPERTY; +typedef void *GRIN_EDGE_PROPERTY_LIST; +#endif + +#ifdef GRIN_TRAIT_NATURAL_ID_FOR_EDGE_TYPE +typedef unsigned GRIN_EDGE_TYPE_ID; +#endif + +#ifdef GRIN_TRAIT_NATURAL_ID_FOR_EDGE_PROPERTY +typedef unsigned GRIN_EDGE_PROPERTY_ID; +#endif + +#ifdef GRIN_ENABLE_ROW +typedef void *GRIN_ROW; +#endif + +#if defined(GRIN_WITH_VERTEX_LABEL) || defined(GRIN_WITH_EDGE_LABEL) +typedef char *GRIN_LABEL; +typedef void *GRIN_LABEL_LIST; +#endif + +#ifdef __cplusplus +} +#endif + +#endif // GRIN_INCLUDE_PREDEFINE_H_ diff --git a/demo_storage/src/storage.cc b/demo_storage/src/storage.cc new file mode 100644 index 0000000..660bf0f --- /dev/null +++ b/demo_storage/src/storage.cc @@ -0,0 +1,176 @@ +/** Copyright 2020 Alibaba Group Holding Limited. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "src/storage.h" + +namespace DEMO_STORAGE_NAMESPACE { +DemoStorage demo_storage; + +int64_t get_id_from_gid(const int64_t gid) { return (gid & 0xFFFFF); } + +uint32_t get_type_id_from_gid(const int64_t gid) { + return static_cast(gid >> 20); +} + +int64_t generate_gid_from_type_id_and_id(uint32_t type_id, int64_t id) { + return (static_cast(type_id) << 20) | id; +} + +void Graph::AddVertex(Vertex& vertex) noexcept { // NOLINT + uint32_t type_id = vertex.GetTypeId(); + if (vertices_.size() <= type_id) { + vertices_.resize(type_id + 1); + } + if (vertex.GetId() == -1) { + vertex.SetId(vertices_[type_id].size()); + } + if (vertices_[type_id].size() <= vertex.GetId()) { + vertices_[type_id].resize(vertex.GetId() + 1); + } + vertices_[type_id][vertex.GetId()] = vertex; + int64_t gid = generate_gid_from_type_id_and_id(type_id, vertex.GetId()); + if (vertex.GetOidType() == GRIN_DATATYPE::Int64) { + int64_t oid = vertex.GetOid(); + oid_int64_2_gid_[oid] = gid; + } else if (vertex.GetOidType() == GRIN_DATATYPE::String) { + std::string oid = vertex.GetOid(); + oid_string_2_gid_[oid] = gid; + } +} + +void Graph::AddEdge(Edge& edge) noexcept { // NOLINT + uint32_t type_id = edge.GetTypeId(); + if (edges_.size() <= type_id) { + edges_.resize(type_id + 1); + } + if (edge.GetId() == -1) { + edge.SetId(edges_[type_id].size()); + } + if (edges_[type_id].size() <= edge.GetId()) { + edges_[type_id].resize(edge.GetId() + 1); + } + edges_[type_id][edge.GetId()] = edge; + + int64_t source = edge.GetSource(), dest = edge.GetDest(); + uint32_t source_type_id = get_type_id_from_gid(source), + dest_type_id = get_type_id_from_gid(dest); + int64_t source_id = get_id_from_gid(source), dest_id = get_id_from_gid(dest); + uint32_t source_partition_id = GetMasterPartitionIdFromVertexGid(source), + dest_partition_id = GetMasterPartitionIdFromVertexGid(dest); + + both_adj_list_[std::make_tuple(source_type_id, source_id, type_id, + dest_partition_id)] + .push_back(edge.GetId()); + both_adj_list_[std::make_tuple(dest_type_id, dest_id, type_id, + source_partition_id)] + .push_back(edge.GetId()); + + if (is_directed_) { + in_adj_list_[std::make_tuple(dest_type_id, dest_id, type_id, + source_partition_id)] + .push_back(edge.GetId()); + out_adj_list_[std::make_tuple(source_type_id, source_id, type_id, + dest_partition_id)] + .push_back(edge.GetId()); + } +} + +Graph* DemoStorage::load_modern_graph(const std::string& name, + uint32_t partition_num, + uint32_t partition_id) { + Graph* graph = new Graph(name, partition_num, partition_id, true); + + // add vertex type + graph->AddVertexType("person"); + graph->AddVertexType("software"); + // add edge type + graph->AddEdgeType("knows"); + graph->AddEdgeType("created"); + // add VEV type + graph->AddVEVType("person", "knows", "person"); + graph->AddVEVType("person", "created", "software"); + + // add vertex property + Property vp_0_0("id", GRIN_DATATYPE::Int64, true); + Property vp_0_1("name", GRIN_DATATYPE::String, false); + Property vp_0_2("age", GRIN_DATATYPE::Int64, false); + graph->AddVertexProperty("person", vp_0_0); + graph->AddVertexProperty("person", vp_0_1); + graph->AddVertexProperty("person", vp_0_2); + Property vp_1_0("id", GRIN_DATATYPE::Int64, true); + Property vp_1_1("name", GRIN_DATATYPE::String, false); + Property vp_1_2("lang", GRIN_DATATYPE::String, false); + graph->AddVertexProperty("software", vp_1_0); + graph->AddVertexProperty("software", vp_1_1); + graph->AddVertexProperty("software", vp_1_2); + + // add edge property + Property ep_x_0("weight", GRIN_DATATYPE::Double, false); + graph->AddEdgeProperty("knows", ep_x_0); + graph->AddEdgeProperty("created", ep_x_0); + + // add vertex + std::vector v_0_id = {2, 6, 4, 1}; + std::vector v_0_name = {"vadas", "peter", "josh", "marko"}; + std::vector v_0_age = {27, 35, 32, 29}; + std::vector v_1_id = {3, 5}; + std::vector v_1_name = {"lop", "ripple"}; + std::vector v_1_lang = {"java", "java"}; + for (int64_t i = 0; i < 4; i++) { + Vertex v(0, GRIN_DATATYPE::Int64, v_0_id[i], i); + v.SetVData(GRIN_DATATYPE::Int64, v_0_id[i]); + v.AddProperty("id", v_0_id[i]); + v.AddProperty("name", v_0_name[i]); + v.AddProperty("age", v_0_age[i]); + v.AddLabel("person"); + graph->AddVertex(v); + } + for (int64_t i = 0; i < 2; i++) { + Vertex v(1, GRIN_DATATYPE::Int64, v_1_id[i], i); + v.SetVData(GRIN_DATATYPE::String, v_1_name[i]); + v.AddProperty("id", v_1_id[i]); + v.AddProperty("name", v_1_name[i]); + v.AddProperty("lang", v_1_lang[i]); + v.AddLabel("software"); + graph->AddVertex(v); + } + + // add edge + std::vector e_0_src = {1, 1}; + std::vector e_0_dst = {2, 4}; + std::vector e_0_weight = {0.5, 1.0}; + std::vector e_1_src = {1, 4, 4, 6}; + std::vector e_1_dst = {3, 5, 3, 3}; + std::vector e_1_weight = {0.4, 1.0, 0.4, 0.2}; + for (int64_t i = 0; i < 2; i++) { + Edge e = graph->ConstructEdgeFromVertexOid(0, e_0_src[i], e_0_dst[i], i); + e.SetEData(GRIN_DATATYPE::Double, e_0_weight[i]); + e.AddProperty("weight", e_0_weight[i]); + e.AddLabel("knows"); + graph->AddEdge(e); + } + for (int64_t i = 0; i < 4; i++) { + Edge e = graph->ConstructEdgeFromVertexOid(1, e_1_src[i], e_1_dst[i], i); + e.SetEData(GRIN_DATATYPE::Double, e_1_weight[i]); + e.AddProperty("weight", e_1_weight[i]); + e.AddLabel("created"); + graph->AddEdge(e); + } + + // return + return graph; +} + +} // namespace DEMO_STORAGE_NAMESPACE diff --git a/demo_storage/src/storage.h b/demo_storage/src/storage.h new file mode 100644 index 0000000..0d75c4b --- /dev/null +++ b/demo_storage/src/storage.h @@ -0,0 +1,577 @@ +/** Copyright 2020 Alibaba Group Holding Limited. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef SRC_STORAGE_H_ +#define SRC_STORAGE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../predefine.h" + +#define DEMO_STORAGE_NAMESPACE demo_storage_namespace + +namespace DEMO_STORAGE_NAMESPACE { +// gid related functions +int64_t get_id_from_gid(const int64_t gid); +uint32_t get_type_id_from_gid(const int64_t gid); +int64_t generate_gid_from_type_id_and_id(uint32_t type_id, int64_t id); + +struct Property { + std::string name_; + GRIN_DATATYPE datatype_; + bool is_primary_; + Property(std::string name, GRIN_DATATYPE datatype, bool is_primary = false) + : name_(name), datatype_(datatype), is_primary_(is_primary) {} +}; + +class Vertex { + public: + // construct vertex with type and id in type + Vertex() : type_id_(GRIN_NULL_VERTEX_TYPE), id_(-1) { + oid_type_ = GRIN_DATATYPE::Undefined; + vdata_type_ = GRIN_DATATYPE::Undefined; + } + + explicit Vertex(uint32_t type_id, int64_t id = -1) + : type_id_(type_id), id_(id) { + oid_type_ = GRIN_DATATYPE::Undefined; + vdata_type_ = GRIN_DATATYPE::Undefined; + } + + // construct vertex with type, oid, and id in type + Vertex(uint32_t type_id, GRIN_DATATYPE oid_type, const std::any& oid, + int64_t id = -1) + : type_id_(type_id), id_(id), oid_type_(oid_type), oid_(oid) { + vdata_type_ = GRIN_DATATYPE::Undefined; + } + + public: + // get methods + uint32_t GetTypeId() const noexcept { return type_id_; } + int64_t GetId() const noexcept { return id_; } + + GRIN_DATATYPE GetOidType() const noexcept { return oid_type_; } + template + T GetOid() const { + return std::any_cast(oid_); + } + + GRIN_DATATYPE GetVDataType() const noexcept { return vdata_type_; } + template + T GetVData() const { + return std::any_cast(vdata_); + } + + template + T GetProperty(const std::string& property_name) const { + auto it = property_values_.find(property_name); + return std::any_cast(it->second); + } + + std::any GetPropertyAny(const std::string& property_name) const { + auto it = property_values_.find(property_name); + return it->second; + } + + const std::set& GetLabels() const noexcept { return labels_; } + bool HasLabel(const std::string& label) const noexcept { + return labels_.find(label) != labels_.end(); + } + + // set methods + void SetId(const int64_t id) noexcept { id_ = id; } + + void SetVData(const GRIN_DATATYPE vdata_type, + const std::any& vdata) noexcept { + vdata_type_ = vdata_type; + vdata_ = vdata; + } + + void AddProperty(const std::string property_name, + const std::any& property_value) noexcept { + property_values_.insert(std::make_pair(property_name, property_value)); + } + + void AddLabel(const std::string& label) noexcept { labels_.insert(label); } + + private: + uint32_t type_id_; + int64_t id_; + GRIN_DATATYPE oid_type_; + std::any oid_; + GRIN_DATATYPE vdata_type_; + std::any vdata_; + std::map property_values_; + std::set labels_; +}; + +class Edge { + public: + Edge() : type_id_(GRIN_NULL_EDGE_TYPE), source_(-1), dest_(-1), id_(-1) { + edata_type_ = GRIN_DATATYPE::Undefined; + } + // construct edge with type, gid of source & dest vertex, and id in type + Edge(uint32_t type_id, int64_t source, int64_t dest, int64_t id = -1) + : type_id_(type_id), source_(source), dest_(dest), id_(id) { + edata_type_ = GRIN_DATATYPE::Undefined; + } + + public: + // get methods + uint32_t GetTypeId() const noexcept { return type_id_; } + int64_t GetSource() const noexcept { return source_; } + int64_t GetDest() const noexcept { return dest_; } + int64_t GetId() const noexcept { return id_; } + + GRIN_DATATYPE GetEDataType() const noexcept { return edata_type_; } + template + T GetEData() const { + return std::any_cast(edata_); + } + + template + T GetProperty(const std::string& property_name) const { + auto it = property_values_.find(property_name); + return std::any_cast(it->second); + } + + std::any GetPropertyAny(const std::string& property_name) const { + auto it = property_values_.find(property_name); + return it->second; + } + + const std::set& GetLabels() const noexcept { return labels_; } + bool HasLabel(const std::string& label) const noexcept { + return labels_.find(label) != labels_.end(); + } + + // set methods + void SetId(const int64_t id) noexcept { id_ = id; } + + void SetEData(const GRIN_DATATYPE edata_type, + const std::any& edata) noexcept { + edata_type_ = edata_type; + edata_ = edata; + } + + void AddProperty(const std::string property_name, + const std::any& property_value) noexcept { + property_values_.insert(std::make_pair(property_name, property_value)); + } + + void AddLabel(const std::string& label) noexcept { labels_.insert(label); } + + private: + uint32_t type_id_; + int64_t source_, dest_; + int64_t id_; + GRIN_DATATYPE edata_type_; + std::any edata_; + std::map property_values_; + std::set labels_; +}; + +class Graph { + public: + // construct graph + Graph(std::string graph_name, uint32_t partition_num = 1, + uint32_t partition_id = 0, bool is_directed = true) + : graph_name_(graph_name), + partition_num_(partition_num), + partition_id_(partition_id), + is_directed_(is_directed) {} + + public: + // get methods + // get meta + const std::string& GetName() const noexcept { return graph_name_; } + bool IsDirected() const noexcept { return is_directed_; } + uint32_t GetPartitionNum() const noexcept { return partition_num_; } + uint32_t GetPartitionId() const noexcept { return partition_id_; } + + // get types + size_t GetVertexTypeNum() const noexcept { return vertex_types_.size(); } + size_t GetEdgeTypeNum() const noexcept { return edge_types_.size(); } + size_t GetVertexEdgeVertexTypeNum() const noexcept { + return vev_types_.size(); + } + const std::vector& GetVertexTypes() const noexcept { + return vertex_types_; + } + const std::vector& GetEdgeTypes() const noexcept { + return edge_types_; + } + const std::string& GetVertexTypeName(uint32_t type_id) const noexcept { + return vertex_types_[type_id]; + } + const std::string& GetEdgeTypeName(uint32_t type_id) const noexcept { + return edge_types_[type_id]; + } + const std::vector>& + GetVertexEdgeVertexTypes() const noexcept { + return vev_types_; + } + int32_t GetVertexTypeId(const std::string& vertex_type) const noexcept { + if (vertex_type_2_id_.find(vertex_type) == vertex_type_2_id_.end()) { + return -1; + } + return vertex_type_2_id_.at(vertex_type); + } + int32_t GetEdgeTypeId(const std::string& edge_type) const noexcept { + if (edge_type_2_id_.find(edge_type) == edge_type_2_id_.end()) { + return -1; + } + return edge_type_2_id_.at(edge_type); + } + + // get properties + size_t GetVertexPropertyNum(uint32_t type_id) const noexcept { + if (type_id >= vertex_properties_.size()) { + return 0; + } + return vertex_properties_[type_id].size(); + } + size_t GetEdgePropertyNum(uint32_t type_id) const noexcept { + if (type_id >= edge_properties_.size()) { + return 0; + } + return edge_properties_[type_id].size(); + } + const std::string& GetVertexPropertyName(uint32_t type_id, + uint32_t property_id) const + noexcept { + return vertex_properties_[type_id][property_id].name_; + } + const std::string& GetEdgePropertyName(uint32_t type_id, + uint32_t property_id) const noexcept { + return edge_properties_[type_id][property_id].name_; + } + const Property& GetVertexProperty(int64_t gid) const noexcept { + auto type_id = get_type_id_from_gid(gid); + auto property_id = get_id_from_gid(gid); + return vertex_properties_[type_id][property_id]; + } + const Property& GetEdgeProperty(int64_t gid) const noexcept { + auto type_id = get_type_id_from_gid(gid); + auto property_id = get_id_from_gid(gid); + return edge_properties_[type_id][property_id]; + } + const std::vector& GetVertexProperties(uint32_t type_id) const + noexcept { + return vertex_properties_[type_id]; + } + const std::vector& GetEdgeProperties(uint32_t type_id) const + noexcept { + return edge_properties_[type_id]; + } + int32_t GetVertexPropertyId(uint32_t vtype, std::string name) const noexcept { + if (vertex_property_2_id_[vtype].find(name) == + vertex_property_2_id_[vtype].end()) { + return -1; + } + return vertex_property_2_id_[vtype].at(name); + } + int32_t GetEdgePropertyId(uint32_t etype, std::string name) const noexcept { + if (edge_property_2_id_[etype].find(name) == + edge_property_2_id_[etype].end()) { + return -1; + } + return edge_property_2_id_[etype].at(name); + } + + // get vertex & edge number + size_t GetVertexNum(uint32_t type_id) const noexcept { + if (type_id >= vertices_.size()) { + return 0; + } + return vertices_[type_id].size(); + } + size_t GetEdgeNum(uint32_t type_id) const noexcept { + if (type_id >= edges_.size()) { + return 0; + } + return edges_[type_id].size(); + } + size_t GetPartitionedVertexNum(uint32_t type_id, uint32_t partition_id) const + noexcept { + size_t num = GetVertexNum(type_id); + size_t res = num / partition_num_; + if (partition_id < num % partition_num_) { + res++; + } + return res; + } + size_t GetPartitionedEdgeNum(uint32_t type_id, uint32_t partition_id) const + noexcept { + size_t num = GetEdgeNum(type_id); + size_t res = num / partition_num_; + if (partition_id < num % partition_num_) { + res++; + } + return res; + } + + // get vertices and edges + const Vertex& GetVertex(int64_t gid) const { + uint32_t type_id = get_type_id_from_gid(gid); + uint32_t id = get_id_from_gid(gid); + return vertices_[type_id][id]; + } + const Edge& GetEdge(int64_t gid) const { + uint32_t type_id = get_type_id_from_gid(gid); + uint32_t id = get_id_from_gid(gid); + return edges_[type_id][id]; + } + const std::vector& GetVertices(uint32_t type_id) const { + return vertices_[type_id]; + } + const std::vector& GetEdges(uint32_t type_id) const { + return edges_[type_id]; + } + size_t GetAdjacentListSize(uint32_t vtype_id, int64_t vid, uint32_t etype_id, + uint32_t partition_id, GRIN_DIRECTION dir) { + size_t size = 0; + auto key = std::make_tuple(vtype_id, vid, etype_id, partition_id); + if (!is_directed_ || dir == GRIN_DIRECTION::BOTH) { + if (both_adj_list_.find(key) != both_adj_list_.end()) { + size = both_adj_list_.at(key).size(); + } + } + if (dir == GRIN_DIRECTION::IN) { + if (in_adj_list_.find(key) != in_adj_list_.end()) { + size = in_adj_list_.at(key).size(); + } + } + if (dir == GRIN_DIRECTION::OUT) { + if (out_adj_list_.find(key) != out_adj_list_.end()) { + size = out_adj_list_.at(key).size(); + } + } + return size; + } + const std::vector& GetAdjacentList(uint32_t vtype_id, int64_t vid, + uint32_t etype_id, + uint32_t partition_id, + GRIN_DIRECTION dir) { + auto key = std::make_tuple(vtype_id, vid, etype_id, partition_id); + if (!is_directed_ || dir == GRIN_DIRECTION::BOTH) { + if (both_adj_list_.find(key) != both_adj_list_.end()) { + return both_adj_list_.at(key); + } + } + if (dir == GRIN_DIRECTION::IN) { + if (in_adj_list_.find(key) != in_adj_list_.end()) { + return in_adj_list_.at(key); + } + } + if (dir == GRIN_DIRECTION::OUT) { + if (out_adj_list_.find(key) != out_adj_list_.end()) { + return out_adj_list_.at(key); + } + } + return empty_adj_list_; + } + + public: + // gid & oid related functions + int64_t GetGidFromOidOfInt64(int64_t oid) const noexcept { + if (oid_int64_2_gid_.find(oid) != oid_int64_2_gid_.end()) { + return oid_int64_2_gid_.at(oid); + } + return -1; + } + int64_t GetGidFromOidOfString(std::string oid) const noexcept { + if (oid_string_2_gid_.find(oid) != oid_string_2_gid_.end()) { + return oid_string_2_gid_.at(oid); + } + return -1; + } + int64_t GetGidFromOid(const std::any& oid) const { + if (oid.type() == typeid(int64_t)) { + return GetGidFromOidOfInt64(std::any_cast(oid)); + } else if (oid.type() == typeid(std::string)) { + return GetGidFromOidOfString(std::any_cast(oid)); + } + return -1; + } + Edge ConstructEdgeFromVertexOid(uint32_t type_id, const std::any& source_oid, + const std::any& dest_oid, + int64_t edge_id = -1) const { + int64_t source_gid = GetGidFromOid(source_oid); + int64_t dest_gid = GetGidFromOid(dest_oid); + return Edge(type_id, source_gid, dest_gid, edge_id); + } + + public: + // partition related functions + uint32_t GetMasterPartitionIdFromVertexGid(const int64_t gid) const noexcept { + return gid % partition_num_; + } + uint32_t GetMasterPartitionIdFromEdgeGid(const int64_t gid) const noexcept { + return gid % partition_num_; + } + uint32_t GetMasterPartitionIdForVertex(const Vertex& vertex) const noexcept { + return vertex.GetId() % partition_num_; + } + uint32_t GetMasterPartitionIdForEdge(const Edge& edge) const noexcept { + return edge.GetId() % partition_num_; + } + + public: + // build graph methods + // add types + void AddVertexType(const std::string& vertex_type) noexcept { + if (vertex_type_2_id_.find(vertex_type) == vertex_type_2_id_.end()) { + vertex_type_2_id_[vertex_type] = vertex_types_.size(); + vertex_types_.push_back(vertex_type); + } + } + void AddEdgeType(const std::string& edge_type) noexcept { + if (edge_type_2_id_.find(edge_type) == edge_type_2_id_.end()) { + edge_type_2_id_[edge_type] = edge_types_.size(); + edge_types_.push_back(edge_type); + } + } + void AddVEVType(const std::string& src_type, const std::string& edge_type, + const std::string& dest_type) noexcept { + AddVertexType(src_type); + AddVertexType(dest_type); + AddEdgeType(edge_type); + vev_types_.push_back(std::make_tuple(GetVertexTypeId(src_type), + GetEdgeTypeId(edge_type), + GetVertexTypeId(dest_type))); + } + + // add properties + void AddVertexProperty(const std::string& vertex_type, + const Property& property) noexcept { + uint32_t type_id = vertex_type_2_id_[vertex_type]; + if (vertex_properties_.size() <= type_id) { + vertex_properties_.resize(type_id + 1); + vertex_property_2_id_.resize(type_id + 1); + } + if (vertex_property_2_id_[type_id].find(property.name_) == + vertex_property_2_id_[type_id].end()) { + vertex_property_2_id_[type_id][property.name_] = + vertex_properties_[type_id].size(); + vertex_properties_[type_id].push_back(property); + } + } + void AddEdgeProperty(const std::string& edge_type, + const Property& property) noexcept { + uint32_t type_id = edge_type_2_id_[edge_type]; + if (edge_properties_.size() <= type_id) { + edge_properties_.resize(type_id + 1); + edge_property_2_id_.resize(type_id + 1); + } + if (edge_property_2_id_[type_id].find(property.name_) == + edge_property_2_id_[type_id].end()) { + edge_property_2_id_[type_id][property.name_] = + edge_properties_[type_id].size(); + edge_properties_[type_id].push_back(property); + } + } + + // add vertices and edges + void AddVertex(Vertex& vertex) noexcept; // NOLINT + void AddEdge(Edge& edge) noexcept; // NOLINT + + private: + // meta + std::string graph_name_; + uint32_t partition_num_, partition_id_; + bool is_directed_; + // schema + std::vector vertex_types_, edge_types_; + std::map vertex_type_2_id_, edge_type_2_id_; + std::vector> vev_types_; + std::vector> vertex_properties_, edge_properties_; + std::vector> vertex_property_2_id_, + edge_property_2_id_; + // vertices and edges + std::vector> vertices_; + std::vector> edges_; + // adj_list, adj_list_[(vtype, vid, partition_id)] = vector of global eid of + // edges + std::map, + std::vector> + in_adj_list_, out_adj_list_, both_adj_list_; + std::vector empty_adj_list_; + // oid to gid + std::map oid_int64_2_gid_; + std::map oid_string_2_gid_; +}; + +class DemoStorage { + public: + DemoStorage() = default; + ~DemoStorage() { + for (auto& graph : graphs_) { + delete graph.second; + } + } + + public: + Graph* GetGraph(const std::string& graph_name) noexcept { + if (graphs_.find(graph_name) != graphs_.end()) { + return graphs_.at(graph_name); + } + return NULL; + } + + void PutGraph(const std::string& graph_name, Graph* graph) noexcept { + graphs_[graph_name] = graph; + } + + void RemoveGraph(const std::string& graph_name) noexcept { + if (graphs_.find(graph_name) != graphs_.end()) { + delete graphs_.at(graph_name); + graphs_.erase(graph_name); + } + } + + void Clear() noexcept { + for (auto& graph : graphs_) { + delete graph.second; + } + graphs_.clear(); + } + + void LoadModernGraph(const std::string& name, uint32_t partition_num = 1, + uint32_t partition_id = 0) noexcept { + Graph* graph = load_modern_graph(name, partition_num, partition_id); + graphs_[graph->GetName()] = graph; + } + + private: + Graph* load_modern_graph(const std::string& name, uint32_t partition_num, + uint32_t partition_id); + + private: + std::map graphs_; +}; + +extern DemoStorage demo_storage; + +} // namespace DEMO_STORAGE_NAMESPACE + +#endif // SRC_STORAGE_H_ From 486b5954193e143b5a13270bc8af29752ecc72e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Fri, 16 Jun 2023 09:57:25 +0800 Subject: [PATCH 02/48] Update predefine --- demo_storage/predefine.h | 81 ++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 41 deletions(-) diff --git a/demo_storage/predefine.h b/demo_storage/predefine.h index 9fa45fe..daef912 100644 --- a/demo_storage/predefine.h +++ b/demo_storage/predefine.h @@ -423,7 +423,6 @@ typedef enum { #define GRIN_TRAIT_FAST_VERTEX_REF #define GRIN_ENABLE_EDGE_REF #define GRIN_ASSUME_ALL_REPLICATE_PARTITION -#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_VERTEX_DATA #define GRIN_TRAIT_MASTER_VERTEX_MIRROR_PARTITION_LIST #define GRIN_TRAIT_MIRROR_VERTEX_MIRROR_PARTITION_LIST #define GRIN_TRAIT_MASTER_EDGE_MIRROR_PARTITION_LIST @@ -772,8 +771,9 @@ typedef enum { #define GRIN_WITH_VERTEX_LABEL #define GRIN_WITH_EDGE_LABEL #define GRIN_ASSUME_ALL_VERTEX_LIST_SORTED -#define GRIN_ENABLE_VERTEX_ORIGINAL_ID_OF_INT64 -#define GRIN_ENABLE_VERTEX_ORIGINAL_ID_OF_STRING +#define GRIN_ENABLE_VERTEX_INTERNAL_ID_INDEX +#define GRIN_ENABLE_VERTEX_PK_INDEX +#define GRIN_ENABLE_EDGE_PK_INDEX // GRIN_END // GRIN_FEATURE_DEPENDENCY @@ -782,44 +782,6 @@ typedef enum { #endif // GRIN_DOXYGEN_SKIP /* End of Section 4 */ -/** @name NullValues - * Macros for Null(invalid) values - */ -///@{ -/** @brief Null graph (invalid return value) */ -#define GRIN_NULL_GRAPH NULL -/** @brief Non-existing vertex (invalid return value) */ -#define GRIN_NULL_VERTEX -1 -/** @brief Non-existing edge (invalid return value) */ -#define GRIN_NULL_EDGE -1 -/** @brief Null list of any kind (invalid return value) */ -#define GRIN_NULL_LIST NULL -/** @brief Null list iterator of any kind (invalid return value) */ -#define GRIN_NULL_LIST_ITERATOR NULL -/** @brief Non-existing partition (invalid return value) */ -#define GRIN_NULL_PARTITION (unsigned)~0 -/** @brief Null vertex reference (invalid return value) */ -#define GRIN_NULL_VERTEX_REF -1 -/** @brief Null edge reference (invalid return value) */ -#define GRIN_NULL_EDGE_REF -1 -/** @brief Non-existing vertex type (invalid return value) */ -#define GRIN_NULL_VERTEX_TYPE (unsigned)~0 -/** @brief Non-existing edge type (invalid return value) */ -#define GRIN_NULL_EDGE_TYPE (unsigned)~0 -/** @brief Non-existing vertex property (invalid return value) */ -#define GRIN_NULL_VERTEX_PROPERTY (unsigned)~0 -/** @brief Non-existing vertex property (invalid return value) */ -#define GRIN_NULL_EDGE_PROPERTY (unsigned)~0 -/** @brief Null row (invalid return value) */ -#define GRIN_NULL_ROW NULL -/** @brief Null natural id of any kind (invalid return value) */ -#define GRIN_NULL_NATURAL_ID (unsigned)~0 -/** @brief Null size (invalid return value) */ -#define GRIN_NULL_SIZE (unsigned)~0 -/** @breif Null name (invalid return value) */ -#define GRIN_NULL_NAME NULL -///@} - /* Define the handlers using typedef */ typedef void *GRIN_GRAPH; typedef long long int GRIN_VERTEX; @@ -916,6 +878,43 @@ typedef char *GRIN_LABEL; typedef void *GRIN_LABEL_LIST; #endif +#define GRIN_NULL_GRAPH NULL +#define GRIN_NULL_VERTEX -1 +#define GRIN_NULL_EDGE -1 +#define GRIN_NULL_VERTEX_DATA NULL +#define GRIN_NULL_VERTEX_LIST NULL +#define GRIN_NULL_VERTEX_LIST_ITERATOR NULL +#define GRIN_NULL_ADJACENT_LIST NULL +#define GRIN_NULL_ADJACENT_LIST_ITERATOR NULL +#define GRIN_NULL_EDGE_DATA NULL +#define GRIN_NULL_EDGE_LIST NULL +#define GRIN_NULL_EDGE_LIST_ITERATOR NULL +#define GRIN_NULL_PARTITIONED_GRAPH NULL +#define GRIN_NULL_PARTITION (unsigned)~0 +#define GRIN_NULL_PARTITION_LIST NULL +#define GRIN_NULL_PARTITION_ID (unsigned)~0 +#define GRIN_NULL_VERTEX_REF -1 +#define GRIN_NULL_EDGE_REF -1 +#define GRIN_NULL_VERTEX_TYPE (unsigned)~0 +#define GRIN_NULL_VERTEX_TYPE_LIST NULL +#define GRIN_NULL_VERTEX_PROPERTY (unsigned)~0 +#define GRIN_NULL_VERTEX_PROPERTY_LIST NULL +#define GRIN_NULL_VERTEX_TYPE_ID (unsigned)~0 +#define GRIN_NULL_VERTEX_PROPERTY_ID (unsigned)~0 +#define GRIN_NULL_EDGE_TYPE (unsigned)~0 +#define GRIN_NULL_EDGE_TYPE_LIST NULL +#define GRIN_NULL_VEV_TYPE (unsigned)~0 +#define GRIN_NULL_VEV_TYPE_LIST NULL +#define GRIN_NULL_EDGE_PROPERTY (unsigned)~0 +#define GRIN_NULL_EDGE_PROPERTY_LIST NULL +#define GRIN_NULL_EDGE_TYPE_ID (unsigned)~0 +#define GRIN_NULL_EDGE_PROPERTY_ID (unsigned)~0 +#define GRIN_NULL_ROW NULL +#define GRIN_NULL_LABEL NULL +#define GRIN_NULL_LABEL_LIST NULL +#define GRIN_NULL_SIZE (unsigned)~0 +#define GRIN_NULL_NAME NULL + #ifdef __cplusplus } #endif From 671e5d70c0d22206596cc491426835a68cc41322 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Fri, 16 Jun 2023 16:14:31 +0800 Subject: [PATCH 03/48] Update --- demo_storage/predefine.h | 3 ++- demo_storage/src/storage.cc | 4 ++-- demo_storage/src/storage.h | 31 ++++++++++++++++++++++--------- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/demo_storage/predefine.h b/demo_storage/predefine.h index daef912..a81ba31 100644 --- a/demo_storage/predefine.h +++ b/demo_storage/predefine.h @@ -670,6 +670,7 @@ typedef enum { #define GRIN_TRAIT_NATURAL_ID_FOR_EDGE_TYPE #define GRIN_ENABLE_EDGE_PRIMARY_KEYS #define GRIN_TRAIT_NATURAL_ID_FOR_EDGE_PROPERTY +#define GRIN_TRAIT_SPECIFIC_VEV_RELATION // GRIN_END // GRIN_FEATURE_DEPENDENCY @@ -874,7 +875,7 @@ typedef void *GRIN_ROW; #endif #if defined(GRIN_WITH_VERTEX_LABEL) || defined(GRIN_WITH_EDGE_LABEL) -typedef char *GRIN_LABEL; +typedef void *GRIN_LABEL; typedef void *GRIN_LABEL_LIST; #endif diff --git a/demo_storage/src/storage.cc b/demo_storage/src/storage.cc index 660bf0f..e8a2e94 100644 --- a/demo_storage/src/storage.cc +++ b/demo_storage/src/storage.cc @@ -99,8 +99,8 @@ Graph* DemoStorage::load_modern_graph(const std::string& name, graph->AddEdgeType("knows"); graph->AddEdgeType("created"); // add VEV type - graph->AddVEVType("person", "knows", "person"); - graph->AddVEVType("person", "created", "software"); + graph->AddVEVType("person", "knows", "person", MANY_TO_MANY); + graph->AddVEVType("person", "created", "software", ONE_TO_MANY); // add vertex property Property vp_0_0("id", GRIN_DATATYPE::Int64, true); diff --git a/demo_storage/src/storage.h b/demo_storage/src/storage.h index 0d75c4b..3cbfed3 100644 --- a/demo_storage/src/storage.h +++ b/demo_storage/src/storage.h @@ -24,7 +24,6 @@ limitations under the License. #include #include #include - #include "../predefine.h" #define DEMO_STORAGE_NAMESPACE demo_storage_namespace @@ -35,6 +34,13 @@ int64_t get_id_from_gid(const int64_t gid); uint32_t get_type_id_from_gid(const int64_t gid); int64_t generate_gid_from_type_id_and_id(uint32_t type_id, int64_t id); +typedef enum { + ONE_TO_ONE = 0, + ONE_TO_MANY = 1, + MANY_TO_ONE = 2, + MANY_TO_MANY = 3 +} VEV_RELATION_TYPE; + struct Property { std::string name_; GRIN_DATATYPE datatype_; @@ -226,7 +232,8 @@ class Graph { const std::string& GetEdgeTypeName(uint32_t type_id) const noexcept { return edge_types_[type_id]; } - const std::vector>& + const std::vector< + std::pair, VEV_RELATION_TYPE>>& GetVertexEdgeVertexTypes() const noexcept { return vev_types_; } @@ -333,12 +340,12 @@ class Graph { // get vertices and edges const Vertex& GetVertex(int64_t gid) const { uint32_t type_id = get_type_id_from_gid(gid); - uint32_t id = get_id_from_gid(gid); + int64_t id = get_id_from_gid(gid); return vertices_[type_id][id]; } const Edge& GetEdge(int64_t gid) const { uint32_t type_id = get_type_id_from_gid(gid); - uint32_t id = get_id_from_gid(gid); + int64_t id = get_id_from_gid(gid); return edges_[type_id][id]; } const std::vector& GetVertices(uint32_t type_id) const { @@ -452,13 +459,17 @@ class Graph { } } void AddVEVType(const std::string& src_type, const std::string& edge_type, - const std::string& dest_type) noexcept { + const std::string& dest_type, + const VEV_RELATION_TYPE vev_relation_type) noexcept { AddVertexType(src_type); AddVertexType(dest_type); AddEdgeType(edge_type); - vev_types_.push_back(std::make_tuple(GetVertexTypeId(src_type), - GetEdgeTypeId(edge_type), - GetVertexTypeId(dest_type))); + auto edge_type_id = GetEdgeTypeId(edge_type); + auto src_type_id = GetVertexTypeId(src_type); + auto dest_type_id = GetVertexTypeId(dest_type); + vev_types_.push_back( + std::make_pair(std::make_tuple(src_type_id, edge_type_id, dest_type_id), + vev_relation_type)); } // add properties @@ -503,7 +514,9 @@ class Graph { // schema std::vector vertex_types_, edge_types_; std::map vertex_type_2_id_, edge_type_2_id_; - std::vector> vev_types_; + std::vector< + std::pair, VEV_RELATION_TYPE>> + vev_types_; std::vector> vertex_properties_, edge_properties_; std::vector> vertex_property_2_id_, edge_property_2_id_; From 74d46328f6b3655ed01723090a09ade321af0471 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Wed, 28 Jun 2023 17:54:50 +0800 Subject: [PATCH 04/48] Rebase on version0.1.1 --- demo_storage/predefine.h | 783 +++--------------------------------- demo_storage/src/storage.cc | 3 + demo_storage/src/storage.h | 1 - 3 files changed, 69 insertions(+), 718 deletions(-) diff --git a/demo_storage/predefine.h b/demo_storage/predefine.h index a81ba31..14616b8 100644 --- a/demo_storage/predefine.h +++ b/demo_storage/predefine.h @@ -15,163 +15,55 @@ limitations under the License. /** * @file predefine.h - * @brief Pre-defined macros for storage features. - * The macros are divided into several sections such as topology, partition, - * and so on. - * In each section, the first part lists all available macros, and undefines - * all GRIN_ASSUME_ macros by default. - * After that is the MOST IMPORTANT part for storage implementors, i.e., the - * StorageSpecific area. Storage implementors should turn ON/OFF the macros in - * this area based the features of the storage. The final part is the rule part - * to handle dependencies between macros which should not be edited. + * @brief This template file consists of four parts: + * 1. The predefined enumerate types of GRIN, which should NOT be modified. + * 2. The supported macros which should be specified by storage implementors + * based on storage features. + * 3. The typedefs of the enabled handles. This should be specified by storage. + * 4. The corresponding null values of the enabled handles. This should be + * specified by storage. */ -#ifndef GRIN_INCLUDE_PREDEFINE_H_ -#define GRIN_INCLUDE_PREDEFINE_H_ - -#include -#include - #ifdef __cplusplus extern "C" { #endif +#include +#include + +/* 1. Predefined enumerate types of GRIN */ /// Enumerates the directions of edges with respect to a certain vertex typedef enum { - IN = 0, ///< incoming - OUT = 1, ///< outgoing - BOTH = 2, ///< incoming & outgoing + IN = 0, ///< incoming + OUT = 1, ///< outgoing + BOTH = 2, ///< incoming & outgoing } GRIN_DIRECTION; /// Enumerates the datatype supported in the storage typedef enum { - Undefined = 0, ///< other unknown types - Int32 = 1, ///< int - UInt32 = 2, ///< unsigned int - Int64 = 3, ///< long int - UInt64 = 4, ///< unsigned long int - Float = 5, ///< float - Double = 6, ///< double - String = 7, ///< string - Date32 = 8, ///< date - Time32 = 9, ///< Time32 - Timestamp64 = 10, ///< Timestamp + Undefined = 0, ///< other unknown types + Int32 = 1, ///< int + UInt32 = 2, ///< unsigned int + Int64 = 3, ///< long int + UInt64 = 4, ///< unsigned long int + Float = 5, ///< float + Double = 6, ///< double + String = 7, ///< string + Date32 = 8, ///< date + Time32 = 9, ///< Time32 + Timestamp64 = 10, ///< Timestamp } GRIN_DATATYPE; /// Enumerates the error codes of grin typedef enum { - NO_ERROR = 0, ///< success - UNKNOWN_ERROR = 1, ///< unknown error - INVALID_VALUE = 2, ///< invalid value - UNKNOWN_DATATYPE = 3, ///< unknown datatype + NO_ERROR = 0, ///< success + UNKNOWN_ERROR = 1, ///< unknown error + INVALID_VALUE = 2, ///< invalid value + UNKNOWN_DATATYPE = 3, ///< unknown datatype } GRIN_ERROR_CODE; -/* Section 1: Toplogy */ - -/** @name TopologyMacros - * @brief Macros for basic graph topology features - */ -///@{ -/** @ingroup TopologyMacros - * @brief The storage only support directed graphs. - */ -#define GRIN_ASSUME_HAS_DIRECTED_GRAPH - -/** @ingroup TopologyMacros - * @brief The storage only support undirected graphs. - */ -#define GRIN_ASSUME_HAS_UNDIRECTED_GRAPH - -/** @ingroup TopologyMacros - * @brief The storage only support graphs with single - * edge between a pair of vertices. - */ -#define GRIN_ASSUME_HAS_MULTI_EDGE_GRAPH - -/** @ingroup TopologyMacros - * @brief There is data on vertex. E.g., the PageRank value of a vertex. - */ -#define GRIN_WITH_VERTEX_DATA - -/** @ingroup TopologyMacros - * @brief There is data on edge. E.g., the weight of an edge. - */ -#define GRIN_WITH_EDGE_DATA - -/** @ingroup TopologyMacros - * @brief Enable the vertex list structure. - * The vertex list related APIs follow the design of GRIN List. - */ -#define GRIN_ENABLE_VERTEX_LIST - -/** @ingroup TopologyMacros - * @brief Enable the vertex list array-style retrieval. - * The vertex list related APIs follow the design of GRIN List. - */ -#define GRIN_ENABLE_VERTEX_LIST_ARRAY - -/** @ingroup TopologyMacros - * @brief Enable the vertex list iterator. - * The vertex list iterator related APIs follow the design of GRIN Iterator. - */ -#define GRIN_ENABLE_VERTEX_LIST_ITERATOR - -/** @ingroup TopologyMacros - * @brief Enable the edge list structure. - * The edge list related APIs follow the design of GRIN List. - */ -#define GRIN_ENABLE_EDGE_LIST - -/** @ingroup TopologyMacros - * @brief Enable the edge list array-style retrieval. - * The edge list related APIs follow the design of GRIN List. - */ -#define GRIN_ENABLE_EDGE_LIST_ARRAY - -/** @ingroup TopologyMacros - * @brief Enable the edge list iterator. - * The edge list iterator related APIs follow the design of GRIN Iterator. - */ -#define GRIN_ENABLE_EDGE_LIST_ITERATOR - -/** @ingroup TopologyMacros - * @brief Enable the adjacent list structure. - * The adjacent list related APIs follow the design of GRIN List. - */ -#define GRIN_ENABLE_ADJACENT_LIST - -/** @ingroup TopologyMacros - * @brief Enable the adjacent list array-style retrieval. - * The adjacent list related APIs follow the design of GRIN List. - */ -#define GRIN_ENABLE_ADJACENT_LIST_ARRAY - -/** @ingroup TopologyMacros - * @brief Enable the adjacent list iterator. - * The adjacent list iterator related APIs follow the design of GRIN Iterator. - */ -#define GRIN_ENABLE_ADJACENT_LIST_ITERATOR -///@} - -#ifndef GRIN_DOXYGEN_SKIP -// GRIN_DEFAULT_DISABLE -#undef GRIN_ASSUME_HAS_DIRECTED_GRAPH -#undef GRIN_ASSUME_HAS_UNDIRECTED_GRAPH -#undef GRIN_ASSUME_HAS_MULTI_EDGE_GRAPH -#undef GRIN_WITH_VERTEX_DATA -#undef GRIN_WITH_EDGE_DATA -#undef GRIN_ENABLE_VERTEX_LIST -#undef GRIN_ENABLE_VERTEX_LIST_ARRAY -#undef GRIN_ENABLE_VERTEX_LIST_ITERATOR -#undef GRIN_ENABLE_EDGE_LIST -#undef GRIN_ENABLE_EDGE_LIST_ARRAY -#undef GRIN_ENABLE_EDGE_LIST_ITERATOR -#undef GRIN_ENABLE_ADJACENT_LIST -#undef GRIN_ENABLE_ADJACENT_LIST_ARRAY -#undef GRIN_ENABLE_ADJACENT_LIST_ITERATOR -// GRIN_END - -// GRIN_STORAGE_ENABLE +/* 2. Define supported macros based on storage features */ +// Topology #define GRIN_ASSUME_HAS_DIRECTED_GRAPH #define GRIN_ASSUME_HAS_UNDIRECTED_GRAPH #define GRIN_ASSUME_HAS_MULTI_EDGE_GRAPH @@ -186,644 +78,102 @@ typedef enum { #define GRIN_ENABLE_ADJACENT_LIST #define GRIN_ENABLE_ADJACENT_LIST_ARRAY #define GRIN_ENABLE_ADJACENT_LIST_ITERATOR -// GRIN_END - -// GRIN_FEATURE_DEPENDENCY -// GRIN_END - -#endif // GRIN_DOXYGEN_SKIP -/* End of Section 1 */ - -/* Section 2. Partition */ - -/** @name PartitionMacros - * @brief Macros for partitioned graph features - */ -///@{ -/** @ingroup PartitionMacros - * @brief Enable partitioned graph. A partitioned graph usually contains - * several fragments (i.e., local graphs) that are distributedly stored - * in a cluster. In GRIN, GRIN_GRAPH represents to a single fragment that can - * be locally accessed. - */ +// Partition #define GRIN_ENABLE_GRAPH_PARTITION - -/** @ingroup PartitionMacros - * @brief The storage provides natural number IDs for partitions. - * It follows the design of natural number ID trait in GRIN. - */ #define GRIN_TRAIT_NATURAL_ID_FOR_PARTITION - -/** @ingroup PartitionMacros - * @brief The storage provides reference of vertex that can be - * recognized in other partitions where the vertex also appears. - */ #define GRIN_ENABLE_VERTEX_REF - -/** @ingroup PartitionMacros - * @brief The storage provides fast reference of vertex, which means - * the vertex ref can be serialized into a int64 using - * grin_serialize_vertex_ref_as_int64 - */ #define GRIN_TRAIT_FAST_VERTEX_REF - -/** @ingroup PartitionMacros - * @brief The storage provides reference of edge that can be - * recognized in other partitions where the edge also appears. - */ #define GRIN_ENABLE_EDGE_REF -///@} - -/** @name PartitionStrategyMacros - * @brief Macros to define partition strategy assumptions, a partition strategy - * can be seen as a combination of detail partition assumptions which are - * defined after the strategies. Please refer to the documents for strategy - * details. - */ -///@{ -/** @ingroup PartitionStrategyMacros - * @brief The storage ONLY uses all-replicate partition strategy. This means the - * storage's replicate the graph among all partitions. - */ #define GRIN_ASSUME_ALL_REPLICATE_PARTITION - -/** @ingroup PartitionStrategyMacros - * @brief The storage ONLY uses edge-cut partition strategy. This means the - * storage's entire partition strategy complies with edge-cut strategy - * definition in GRIN. - */ -#define GRIN_ASSUME_EDGE_CUT_PARTITION - -/** @ingroup PartitionStrategyMacros - * @brief The storage ONLY uses edge-cut partition & edges only follow src - * strategy. This means the storage's entire partition strategy complies with - * edge-cut strategy definition in GRIN, and edges are partitioned to the - * partition of the source vertex. - */ -#define GRIN_ASSUME_EDGE_CUT_FOLLOW_SRC_PARTITION - -/** @ingroup PartitionStrategyMacros - * @brief The storage ONLY uses edge-cut partition & edges only follow dst - * strategy. This means the storage's entire partition strategy complies with - * edge-cut strategy definition in GRIN, and edges are partitioned to the - * partition of the destination vertex. - */ -#define GRIN_ASSUME_EDGE_CUT_FOLLOW_DST_PARTITION - -/** @ingroup PartitionStrategyMacros - * @brief The storage ONLY uses vertex-cut partition strategy. This means the - * storage's entire partition strategy complies with vertex-cut strategy - * definition in GRIN. - */ -#define GRIN_ASSUME_VERTEX_CUT_PARTITION -///@} - -/** @name PartitionAssumptionMacros - * @brief Macros to define detailed partition assumptions with respect to the - * concept of local complete. Please refer to the documents for the meaning of - * local complete. - */ -///@{ -/** @ingroup PartitionAssumptionMacros - * @brief Assume the vertex data are only stored together with master vertices. - */ -#define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_VERTEX_DATA - -/** @ingroup PartitionAssumptionMacros - * @brief Assume the vertex data are replicated on both master and mirror - * vertices. - */ +// #define GRIN_ASSUME_EDGE_CUT_PARTITION +// #define GRIN_ASSUME_EDGE_CUT_FOLLOW_SRC_PARTITION +// #define GRIN_ASSUME_EDGE_CUT_FOLLOW_DST_PARTITION +// #define GRIN_ASSUME_VERTEX_CUT_PARTITION +// #define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_VERTEX_DATA #define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_VERTEX_DATA - -/** @ingroup PartitionAssumptionMacros - * @brief Assume the edge data are only stored together with master edges. - */ -#define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_EDGE_DATA - -/** @ingroup PartitionAssumptionMacros - * @brief Assume the edge data are replicated on both master and mirror edges. - */ +// #define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_EDGE_DATA #define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_EDGE_DATA -///@} - -/** @name TraitMirrorPartitionMacros - * @brief Macros for storage that provides the partition list where the mirror - * vertices are located. This trait is usually enabled by storages using - * vertex-cut partition strategy. - */ -///@{ -/** @ingroup TraitMirrorPartitionMacros - * @brief The storage provides the partition list where the mirror - * vertices are located of a local master vertex. - */ #define GRIN_TRAIT_MASTER_VERTEX_MIRROR_PARTITION_LIST - -/** @ingroup TraitMirrorPartitionMacros - * @brief The storage provides the partition list where the mirror - * vertices are located of a local mirror vertex - */ #define GRIN_TRAIT_MIRROR_VERTEX_MIRROR_PARTITION_LIST - -/** @ingroup TraitMirrorPartitionMacros - * @brief The storage provides the partition list where the mirror - * edges are located of a local master edge - */ #define GRIN_TRAIT_MASTER_EDGE_MIRROR_PARTITION_LIST - -/** @ingroup TraitMirrorPartitionMacros - * @brief The storage provides the partition list where the mirror - * edges are located of a local mirror edge - */ #define GRIN_TRAIT_MIRROR_EDGE_MIRROR_PARTITION_LIST -///@} - -/** @name TraitFilterMacros - * @brief Macros for storage that provides filtering ability of partitions for - * structures like vertex list or adjacent list. This trait is usually enabled - * for efficient graph traversal. - */ -///@{ -/** @ingroup TraitFilterMacros - * @brief The storage provides a filtering predicate of master vertices - * for vertex list iterator. That means, the caller can use the predicate - * to make a master-only vertex list iterator from the original iterator. - */ #define GRIN_TRAIT_SELECT_MASTER_FOR_VERTEX_LIST - -/** @ingroup TraitFilterMacros - * @brief The storage provides a filtering predicate of single partition - * vertices for vertex list iterator. That means, the caller can use the - * predicate to make a single-partition vertex list iterator from the original - * iterator. - */ #define GRIN_TRAIT_SELECT_PARTITION_FOR_VERTEX_LIST - -/** @ingroup TraitFilterMacros - * @brief The storage provides a filtering predicate of master edges - * for edge list iterator. That means, the caller can use the predicate - * to make a master-only edge list iterator from the original iterator. - */ #define GRIN_TRAIT_SELECT_MASTER_FOR_EDGE_LIST - -/** @ingroup TraitFilterMacros - * @brief The storage provides a filtering predicate of single partition edges - * for edge list iterator. That means, the caller can use the predicate - * to make a single-partition edge list iterator from the original iterator. - */ #define GRIN_TRAIT_SELECT_PARTITION_FOR_EDGE_LIST - -/** @ingroup TraitFilterMacros - * @brief The storage provides a filtering predicate of master neighbors - * for adjacent list iterator. That means, the caller can use the predicate - * to make a master-only adjacent list iterator from the original iterator. - */ #define GRIN_TRAIT_SELECT_MASTER_NEIGHBOR_FOR_ADJACENT_LIST - -/** @ingroup TraitFilterMacros - * @brief The storage provides a filtering predicate of single-partition - * vertices for adjacent list iterator. That means, the caller can use the - * predicate to make a single-partition adjacent list iterator from the original - * iterator. - */ #define GRIN_TRAIT_SELECT_NEIGHBOR_PARTITION_FOR_ADJACENT_LIST -///@} - -#ifndef GRIN_DOXYGEN_SKIP -// GRIN_DEFAULT_DISABLE -#undef GRIN_ENABLE_GRAPH_PARTITION -#undef GRIN_TRAIT_NATURAL_ID_FOR_PARTITION -#undef GRIN_ENABLE_VERTEX_REF -#undef GRIN_TRAIT_FAST_VERTEX_REF -#undef GRIN_ENABLE_EDGE_REF -#undef GRIN_ASSUME_ALL_REPLICATE_PARTITION -#undef GRIN_ASSUME_EDGE_CUT_PARTITION -#undef GRIN_ASSUME_EDGE_CUT_FOLLOW_SRC_PARTITION -#undef GRIN_ASSUME_EDGE_CUT_FOLLOW_DST_PARTITION -#undef GRIN_ASSUME_VERTEX_CUT_PARTITION -#undef GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_VERTEX_DATA -#undef GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_VERTEX_DATA -#undef GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_EDGE_DATA -#undef GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_EDGE_DATA -#undef GRIN_TRAIT_MASTER_VERTEX_MIRROR_PARTITION_LIST -#undef GRIN_TRAIT_MIRROR_VERTEX_MIRROR_PARTITION_LIST -#undef GRIN_TRAIT_MASTER_EDGE_MIRROR_PARTITION_LIST -#undef GRIN_TRAIT_MIRROR_EDGE_MIRROR_PARTITION_LIST -#undef GRIN_TRAIT_SELECT_MASTER_FOR_VERTEX_LIST -#undef GRIN_TRAIT_SELECT_PARTITION_FOR_VERTEX_LIST -#undef GRIN_TRAIT_SELECT_MASTER_FOR_EDGE_LIST -#undef GRIN_TRAIT_SELECT_PARTITION_FOR_EDGE_LIST -#undef GRIN_TRAIT_SELECT_MASTER_NEIGHBOR_FOR_ADJACENT_LIST -#undef GRIN_TRAIT_SELECT_NEIGHBOR_PARTITION_FOR_ADJACENT_LIST -// GRIN_END - -// GRIN_STORAGE_ENABLE -#define GRIN_ENABLE_GRAPH_PARTITION -#define GRIN_TRAIT_NATURAL_ID_FOR_PARTITION -#define GRIN_ENABLE_VERTEX_REF -#define GRIN_TRAIT_FAST_VERTEX_REF -#define GRIN_ENABLE_EDGE_REF -#define GRIN_ASSUME_ALL_REPLICATE_PARTITION -#define GRIN_TRAIT_MASTER_VERTEX_MIRROR_PARTITION_LIST -#define GRIN_TRAIT_MIRROR_VERTEX_MIRROR_PARTITION_LIST -#define GRIN_TRAIT_MASTER_EDGE_MIRROR_PARTITION_LIST -#define GRIN_TRAIT_MIRROR_EDGE_MIRROR_PARTITION_LIST -#define GRIN_TRAIT_SELECT_MASTER_FOR_VERTEX_LIST -#define GRIN_TRAIT_SELECT_PARTITION_FOR_VERTEX_LIST -#define GRIN_TRAIT_SELECT_MASTER_FOR_EDGE_LIST -#define GRIN_TRAIT_SELECT_PARTITION_FOR_EDGE_LIST -#define GRIN_TRAIT_SELECT_MASTER_NEIGHBOR_FOR_ADJACENT_LIST -#define GRIN_TRAIT_SELECT_NEIGHBOR_PARTITION_FOR_ADJACENT_LIST -// GRIN_END - -// GRIN_FEATURE_DEPENDENCY -#ifdef GRIN_ASSUME_ALL_REPLICATE_PARTITION -#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_VERTEX_DATA -#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_EDGE_DATA -#endif - -#ifdef GRIN_ASSUME_EDGE_CUT_PARTITION -#define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_VERTEX_DATA -#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_EDGE_DATA -#endif - -#ifdef GRIN_ASSUME_EDGE_CUT_FOLLOW_SRC_PARTITION -#define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_VERTEX_DATA -#define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_EDGE_DATA -#endif - -#ifdef GRIN_ASSUME_EDGE_CUT_FOLLOW_DST_PARTITION -#define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_VERTEX_DATA -#define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_EDGE_DATA -#endif - -#ifdef GRIN_ASSUME_VERTEX_CUT_PARTITION -#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_VERTEX_DATA -#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_EDGE_DATA -#define GRIN_TRAIT_MASTER_VERTEX_MIRROR_PARTITION_LIST -#endif -// GRIN_END - -#endif // GRIN_DOXY_SKIP -/* End of Section 2 */ - -/* Section 3. Property */ - -/** @name PropertyMacros - * @brief Macros for basic property graph features - */ -///@{ -/** @ingroup PropertyMacros - * @brief Enable the pure data structure Row - */ +// Property #define GRIN_ENABLE_ROW - -/** @ingroup PropertyMacros - * @brief This trait is used to indicate the storage can return a pointer to the - * value of a property. - */ #define GRIN_TRAIT_CONST_VALUE_PTR - -/** @ingroup PropertyMacros - * @brief There are properties bound to vertices. When vertices are typed, - * vertex properties are bound to vertex types, according to the definition of - * vertex type. - */ #define GRIN_WITH_VERTEX_PROPERTY - -/** @ingroup PropertyMacros - * @brief There are property names for vertex properties. The relationship - * between property name and properties is one-to-many, because properties bound - * to different vertex/edge types are distinguished even they may share the same - * property name. Please refer to the design of Property for details. - */ #define GRIN_WITH_VERTEX_PROPERTY_NAME - -/** @ingroup PropertyMacros - * @brief There are unique names for each vertex type. - */ #define GRIN_WITH_VERTEX_TYPE_NAME - -/** @ingroup PropertyMacros - * @brief The storage provides natural number IDs for vertex types. - * It follows the design of natural ID trait in GRIN. - */ #define GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_TYPE - -/** @ingroup PropertyMacros - * @brief There are primary keys for vertices. Vertex primary keys is - * a set of vertex properties whose values can distinguish vertices. When - * vertices are typed, each vertex type has its own primary keys which - * distinguishes the vertices of that type. - * - * With primary keys, one can get the vertex from the graph or a certain type - * by providing the values of the primary keys. The macro is unset if - * GRIN_WITH_VERTEX_PROPERTY is NOT defined, in which case, one can use - * ORIGINAL_ID when vertices have no properties. - */ #define GRIN_ENABLE_VERTEX_PRIMARY_KEYS - -/** @ingroup PropertyMacros - * @brief The storage provides natural number IDs for properties bound to - * a certain vertex type. - * It follows the design of natural ID trait in GRIN. - */ #define GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_PROPERTY - -/** @ingroup PropertyMacros - * @brief There are properties bound to edges. When edges are typed, edge - * properties are bound to edge types, according to the definition of edge type. - */ #define GRIN_WITH_EDGE_PROPERTY - -/** @ingroup PropertyMacros - * @brief There are property names for edge properties. The relationship between - * property name and properties is one-to-many, because properties bound to - * different vertex/edge types are distinguished even they may share the same - * property name. Please refer to the design of Property for details. - */ #define GRIN_WITH_EDGE_PROPERTY_NAME - -/** @ingroup PropertyMacros - * @brief There are unique names for each edge type. - */ #define GRIN_WITH_EDGE_TYPE_NAME - -/** @ingroup PropertyMacros - * @brief The storage provides natural number IDs for edge types. - * It follows the design of natural ID trait in GRIN. - */ #define GRIN_TRAIT_NATURAL_ID_FOR_EDGE_TYPE - -/** @ingroup PropertyMacros - * @brief There are primary keys for edges. Edge primary keys is - * a set of edge properties whose values can distinguish edges. When edges are - * typed, each edge type has its own primary keys which distinguishes the edges - * of that type. - * - * With primary keys, one can get the edge from the graph or a certain type - * by providing the values of the primary keys. The macro is unset if - * GRIN_WITH_EDGE_PROPERTY is NOT defined. - */ #define GRIN_ENABLE_EDGE_PRIMARY_KEYS - -/** @ingroup PropertyMacros - * @brief The storage provides natural number IDs for properties bound to - * a certain edge type. - * It follows the design of natural ID trait in GRIN. - */ #define GRIN_TRAIT_NATURAL_ID_FOR_EDGE_PROPERTY -///@} - -/** @name TraitFilterTypeMacros - * @brief Macros of traits to filter vertex/edge type for - * structures like vertex list and adjacent list. - */ -///@{ -/** @ingroup TraitFilterTypeMacros - * @brief The storage provides specific relationship description for each - * vertex-edge-vertex type traid. This means further optimizations can be - * applied by the callers for vev traid under certain relationships, such as - * one-to-one, one-to-many, or many-to-one. - */ #define GRIN_TRAIT_SPECIFIC_VEV_RELATION -///@} - -/** @name PropetyAssumptionMacros - * @brief Macros of assumptions for property local complete, and particularly - * define the by type local complete assumptions for hybrid partiton strategy. - */ -///@{ -/** @ingroup PropetyAssumptionMacros - * @brief Assume full property values of a vertex are ONLY stored with master - * vertices. - */ -#define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_VERTEX_PROPERTY - -/** @ingroup PropetyAssumptionMacros - * @brief Assume full property values of a vertex are replicated with master and - * mirror vertices. - */ -#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_VERTEX_PROPERTY - -/** @ingroup PropetyAssumptionMacros - * @brief Assume full property values of a vertex are split among master and - * mirror vertices. - */ -#define GRIN_ASSUME_SPLIT_MASTER_MIRROR_PARTITION_FOR_VERTEX_PROPERTY - -/** @ingroup PropetyAssumptionMacros - * @brief Assume full property values of an edge are ONLY stored with master - * edges. - */ -#define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_EDGE_PROPERTY - -/** @ingroup PropetyAssumptionMacros - * @brief Assume full property values of an edge are replicated with master and - * mirror edges. - */ -#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_EDGE_PROPERTY - -/** @ingroup PropetyAssumptionMacros - * @brief Assume full property values of an edge are split among master and - * mirror edges. - */ -#define GRIN_ASSUME_SPLIT_MASTER_MIRROR_PARTITION_FOR_EDGE_PROPERTY -///@} - -#ifndef GRIN_DOXYGEN_SKIP -// GRIN_DEFAULT_DISABLE -#undef GRIN_ENABLE_ROW -#undef GRIN_TRAIT_CONST_VALUE_PTR -#undef GRIN_WITH_VERTEX_PROPERTY -#undef GRIN_WITH_VERTEX_PROPERTY_NAME -#undef GRIN_WITH_VERTEX_TYPE_NAME -#undef GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_TYPE -#undef GRIN_ENABLE_VERTEX_PRIMARY_KEYS -#undef GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_PROPERTY -#undef GRIN_WITH_EDGE_PROPERTY -#undef GRIN_WITH_EDGE_PROPERTY_NAME -#undef GRIN_WITH_EDGE_TYPE_NAME -#undef GRIN_TRAIT_NATURAL_ID_FOR_EDGE_TYPE -#undef GRIN_ENABLE_EDGE_PRIMARY_KEYS -#undef GRIN_TRAIT_NATURAL_ID_FOR_EDGE_PROPERTY -#undef GRIN_TRAIT_SPECIFIC_VEV_RELATION -#undef GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_VERTEX_PROPERTY -#undef GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_VERTEX_PROPERTY -#undef GRIN_ASSUME_SPLIT_MASTER_MIRROR_PARTITION_FOR_VERTEX_PROPERTY -#undef GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_EDGE_PROPERTY -#undef GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_EDGE_PROPERTY -#undef GRIN_ASSUME_SPLIT_MASTER_MIRROR_PARTITION_FOR_EDGE_PROPERTY -// GRIN_END - -// GRIN_STORAGE_ENABLE -#define GRIN_ENABLE_ROW -#define GRIN_TRAIT_CONST_VALUE_PTR -#define GRIN_WITH_VERTEX_PROPERTY -#define GRIN_WITH_VERTEX_PROPERTY_NAME -#define GRIN_WITH_VERTEX_TYPE_NAME -#define GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_TYPE -#define GRIN_ENABLE_VERTEX_PRIMARY_KEYS -#define GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_PROPERTY -#define GRIN_WITH_EDGE_PROPERTY -#define GRIN_WITH_EDGE_PROPERTY_NAME -#define GRIN_WITH_EDGE_TYPE_NAME -#define GRIN_TRAIT_NATURAL_ID_FOR_EDGE_TYPE -#define GRIN_ENABLE_EDGE_PRIMARY_KEYS -#define GRIN_TRAIT_NATURAL_ID_FOR_EDGE_PROPERTY -#define GRIN_TRAIT_SPECIFIC_VEV_RELATION -// GRIN_END - -// GRIN_FEATURE_DEPENDENCY -#ifdef GRIN_ASSUME_ALL_REPLICATE_PARTITION +// #define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_VERTEX_PROPERTY #define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_VERTEX_PROPERTY +// #define GRIN_ASSUME_SPLIT_MASTER_MIRROR_PARTITION_FOR_VERTEX_PROPERTY +// #define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_EDGE_PROPERTY #define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_EDGE_PROPERTY -#endif - -#ifdef GRIN_ASSUME_EDGE_CUT_PARTITION -#define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_VERTEX_PROPERTY -#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_EDGE_PROPERTY -#endif - -#ifdef GRIN_ASSUME_EDGE_CUT_FOLLOW_SRC_PARTITION -#define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_VERTEX_PROPERTY -#define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_EDGE_PROPERTY -#endif - -#ifdef GRIN_ASSUME_EDGE_CUT_FOLLOW_DST_PARTITION -#define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_VERTEX_PROPERTY -#define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_EDGE_PROPERTY -#endif - -#ifdef GRIN_ASSUME_VERTEX_CUT_PARTITION -#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_VERTEX_PROPERTY -#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_EDGE_PROPERTY -#endif - -#ifdef GRIN_ENABLE_VERTEX_PRIMARY_KEYS -#define GRIN_ENABLE_ROW -#endif - -#ifdef GRIN_ENABLE_EDGE_PRIMARY_KEYS -#define GRIN_ENABLE_ROW -#endif -// GRIN_END - -#endif // GRIN_DOXY_SKIP -/* End of Section 3 */ - -/* Section 4. Index */ -/** @name IndexLabelMacros - * @brief Macros for label features - */ -///@{ -/** @ingroup IndexLabelMacros - * @brief Enable vertex label on graph. - */ -#define GRIN_WITH_VERTEX_LABEL - -/** @ingroup IndexLabelMacros - * @brief Enable edge label on graph. - */ -#define GRIN_WITH_EDGE_LABEL -///@} - -/** @name IndexOrderMacros - * @brief Macros for ordering features. - * Please refer to the order section in the documents for details. - */ -///@{ -/** @ingroup IndexOrderMacros - * @brief assume all vertex list are sorted. - * We will expend the assumption to support master/mirror or - * by type in the future if needed. - */ -#define GRIN_ASSUME_ALL_VERTEX_LIST_SORTED -///@} - -/** @name IndexOIDMacros - * @brief Macros for label features - */ -///@{ -/** @ingroup IndexOIDMacros - * @brief There is original ID of type int64 for each vertex - * This facilitates queries starting from a specific vertex, - * since one can get the vertex handler directly using its original ID. - */ -#define GRIN_ENABLE_VERTEX_ORIGINAL_ID_OF_INT64 - -/** @ingroup IndexOIDMacros - * @brief There is original ID of type string for each vertex - * This facilitates queries starting from a specific vertex, - * since one can get the vertex handler directly using its original ID. - */ -#define GRIN_ENABLE_VERTEX_ORIGINAL_ID_OF_STRING -///@} - -#ifndef GRIN_DOXYGEN_SKIP -// GRIN_DEFAULT_DISABLE -#undef GRIN_WITH_VERTEX_LABEL -#undef GRIN_WITH_EDGE_LABEL -#undef GRIN_ASSUME_ALL_VERTEX_LIST_SORTED -#undef GRIN_ENABLE_VERTEX_ORIGINAL_ID_OF_INT64 -#undef GRIN_ENABLE_VERTEX_ORIGINAL_ID_OF_STRING -// GRIN_END - -// GRIN_STORAGE_ENABLE -#define GRIN_WITH_VERTEX_LABEL -#define GRIN_WITH_EDGE_LABEL +// #define GRIN_ASSUME_SPLIT_MASTER_MIRROR_PARTITION_FOR_EDGE_PROPERTY +// Index +// #define GRIN_WITH_VERTEX_LABEL +// #define GRIN_WITH_EDGE_LABEL #define GRIN_ASSUME_ALL_VERTEX_LIST_SORTED #define GRIN_ENABLE_VERTEX_INTERNAL_ID_INDEX #define GRIN_ENABLE_VERTEX_PK_INDEX #define GRIN_ENABLE_EDGE_PK_INDEX -// GRIN_END -// GRIN_FEATURE_DEPENDENCY -// GRIN_END - -#endif // GRIN_DOXYGEN_SKIP -/* End of Section 4 */ - -/* Define the handlers using typedef */ +/* 3. Define the handles using typedef */ typedef void *GRIN_GRAPH; typedef long long int GRIN_VERTEX; typedef long long int GRIN_EDGE; #ifdef GRIN_WITH_VERTEX_DATA -typedef void *GRIN_VERTEX_DATA; +typedef void* GRIN_VERTEX_DATA; #endif #ifdef GRIN_ENABLE_VERTEX_LIST -typedef void *GRIN_VERTEX_LIST; +typedef void* GRIN_VERTEX_LIST; #endif #ifdef GRIN_ENABLE_VERTEX_LIST_ITERATOR -typedef void *GRIN_VERTEX_LIST_ITERATOR; +typedef void* GRIN_VERTEX_LIST_ITERATOR; #endif #ifdef GRIN_ENABLE_ADJACENT_LIST -typedef void *GRIN_ADJACENT_LIST; +typedef void* GRIN_ADJACENT_LIST; #endif #ifdef GRIN_ENABLE_ADJACENT_LIST_ITERATOR -typedef void *GRIN_ADJACENT_LIST_ITERATOR; +typedef void* GRIN_ADJACENT_LIST_ITERATOR; #endif #ifdef GRIN_WITH_EDGE_DATA -typedef void *GRIN_EDGE_DATA; +typedef void* GRIN_EDGE_DATA; #endif #ifdef GRIN_ENABLE_EDGE_LIST -typedef void *GRIN_EDGE_LIST; +typedef void* GRIN_EDGE_LIST; #endif #ifdef GRIN_ENABLE_EDGE_LIST_ITERATOR -typedef void *GRIN_EDGE_LIST_ITERATOR; +typedef void* GRIN_EDGE_LIST_ITERATOR; #endif #ifdef GRIN_ENABLE_GRAPH_PARTITION -typedef void *GRIN_PARTITIONED_GRAPH; +typedef void* GRIN_PARTITIONED_GRAPH; typedef unsigned GRIN_PARTITION; -typedef void *GRIN_PARTITION_LIST; +typedef void* GRIN_PARTITION_LIST; #endif #ifdef GRIN_TRAIT_NATURAL_ID_FOR_PARTITION @@ -840,9 +190,9 @@ typedef long long int GRIN_EDGE_REF; #ifdef GRIN_WITH_VERTEX_PROPERTY typedef unsigned GRIN_VERTEX_TYPE; -typedef void *GRIN_VERTEX_TYPE_LIST; +typedef void* GRIN_VERTEX_TYPE_LIST; typedef unsigned GRIN_VERTEX_PROPERTY; -typedef void *GRIN_VERTEX_PROPERTY_LIST; +typedef void* GRIN_VERTEX_PROPERTY_LIST; #endif #ifdef GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_TYPE @@ -855,11 +205,11 @@ typedef unsigned GRIN_VERTEX_PROPERTY_ID; #ifdef GRIN_WITH_EDGE_PROPERTY typedef unsigned GRIN_EDGE_TYPE; -typedef void *GRIN_EDGE_TYPE_LIST; +typedef void* GRIN_EDGE_TYPE_LIST; typedef unsigned GRIN_VEV_TYPE; -typedef void *GRIN_VEV_TYPE_LIST; +typedef void* GRIN_VEV_TYPE_LIST; typedef unsigned GRIN_EDGE_PROPERTY; -typedef void *GRIN_EDGE_PROPERTY_LIST; +typedef void* GRIN_EDGE_PROPERTY_LIST; #endif #ifdef GRIN_TRAIT_NATURAL_ID_FOR_EDGE_TYPE @@ -871,14 +221,15 @@ typedef unsigned GRIN_EDGE_PROPERTY_ID; #endif #ifdef GRIN_ENABLE_ROW -typedef void *GRIN_ROW; +typedef void* GRIN_ROW; #endif #if defined(GRIN_WITH_VERTEX_LABEL) || defined(GRIN_WITH_EDGE_LABEL) -typedef void *GRIN_LABEL; -typedef void *GRIN_LABEL_LIST; +typedef void* GRIN_LABEL; +typedef void* GRIN_LABEL_LIST; #endif +/* 4. Define invalid values for returns of handles */ #define GRIN_NULL_GRAPH NULL #define GRIN_NULL_VERTEX -1 #define GRIN_NULL_EDGE -1 @@ -919,5 +270,3 @@ typedef void *GRIN_LABEL_LIST; #ifdef __cplusplus } #endif - -#endif // GRIN_INCLUDE_PREDEFINE_H_ diff --git a/demo_storage/src/storage.cc b/demo_storage/src/storage.cc index e8a2e94..13cdf7e 100644 --- a/demo_storage/src/storage.cc +++ b/demo_storage/src/storage.cc @@ -13,6 +13,9 @@ See the License for the specific language governing permissions and limitations under the License. */ +// predefine for GRIN +#include "../predefine.h" +// storage headers #include "src/storage.h" namespace DEMO_STORAGE_NAMESPACE { diff --git a/demo_storage/src/storage.h b/demo_storage/src/storage.h index 3cbfed3..b81f415 100644 --- a/demo_storage/src/storage.h +++ b/demo_storage/src/storage.h @@ -24,7 +24,6 @@ limitations under the License. #include #include #include -#include "../predefine.h" #define DEMO_STORAGE_NAMESPACE demo_storage_namespace From 7d313fa93b72c08b02ebf33d67896936ebcb0f3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Thu, 29 Jun 2023 17:04:45 +0800 Subject: [PATCH 05/48] Re-org storage & add methods for loading modern graph --- demo_storage/CMakeLists.txt | 21 +++++++++-- demo_storage/storage/loadmoderngraph.cc | 29 ++++++++++++++ demo_storage/storage/loadmoderngraph.h | 29 ++++++++++++++ demo_storage/{src => storage}/storage.cc | 10 ++--- demo_storage/{src => storage}/storage.h | 48 ++++++++++++++++-------- 5 files changed, 112 insertions(+), 25 deletions(-) create mode 100644 demo_storage/storage/loadmoderngraph.cc create mode 100644 demo_storage/storage/loadmoderngraph.h rename demo_storage/{src => storage}/storage.cc (97%) rename demo_storage/{src => storage}/storage.h (92%) diff --git a/demo_storage/CMakeLists.txt b/demo_storage/CMakeLists.txt index d48653a..2e8e529 100644 --- a/demo_storage/CMakeLists.txt +++ b/demo_storage/CMakeLists.txt @@ -87,7 +87,7 @@ find_package(Protobuf REQUIRED) find_package(glog REQUIRED) -file(GLOB_RECURSE DEMO_GRIN_SRC_FILES "src/*.cc") +file(GLOB_RECURSE DEMO_GRIN_SRC_FILES "storage/*.cc" "src/*.cc") message(${DEMO_GRIN_SRC_FILES}) @@ -136,16 +136,29 @@ if (BUILD_TESTS) target_include_directories(${E_NAME} SYSTEM BEFORE PRIVATE ${PROJECT_SOURCE_DIR}/../include ${Protobuf_INCLUDE_DIRS}) target_link_libraries(${E_NAME} PRIVATE demo-grin Threads::Threads ${CMAKE_DL_LIBS} ${Protobuf_LIBRARIES} glog::glog) endforeach() + + file(GLOB C_TEST_FILES RELATIVE "${PROJECT_SOURCE_DIR}/test" "${PROJECT_SOURCE_DIR}/test/*.c") + + foreach(f ${C_TEST_FILES}) + string(REGEX MATCH "^(.*)\\.[^.]*$" dummy ${f}) + set(E_NAME ${CMAKE_MATCH_1}) + message(STATUS "Found C test for demo storage - " ${E_NAME}) + add_executable(C_${E_NAME} test/${E_NAME}.c) + target_include_directories(C_${E_NAME} SYSTEM BEFORE PRIVATE ${PROJECT_SOURCE_DIR}/../include ${Protobuf_INCLUDE_DIRS}) + target_link_libraries(C_${E_NAME} PRIVATE demo-grin Threads::Threads ${CMAKE_DL_LIBS} ${Protobuf_LIBRARIES} glog::glog) + endforeach() endif() # ------------------------------------------------------------------------------ # Format code & cpplint # ------------------------------------------------------------------------------ -file(GLOB_RECURSE FILES_NEED_FORMAT "src/*.h" "src/*.cc" - "test/*.h" "test/*.cc") +file(GLOB_RECURSE FILES_NEED_FORMAT "storage/*.h" "storage/*.cc" + "src/*.h" "src/*.cc" + "test/*.h" "test/*.cc") list(REMOVE_ITEM FILES_NEED_FORMAT "${PROJECT_SOURCE_DIR}/src/common/graph.pb.h" "${PROJECT_SOURCE_DIR}/src/common/graph.pb.cc") -file(GLOB_RECURSE FILES_NEED_LINT "src/*.h" "src/*.cc" +file(GLOB_RECURSE FILES_NEED_LINT "storage/*.h" "storage/*.cc" + "src/*.h" "src/*.cc" "test/*.h" "test/*.cc") list(REMOVE_ITEM FILES_NEED_LINT "${PROJECT_SOURCE_DIR}/src/common/graph.pb.h" "${PROJECT_SOURCE_DIR}/src/common/graph.pb.cc") diff --git a/demo_storage/storage/loadmoderngraph.cc b/demo_storage/storage/loadmoderngraph.cc new file mode 100644 index 0000000..ef1263c --- /dev/null +++ b/demo_storage/storage/loadmoderngraph.cc @@ -0,0 +1,29 @@ +/** Copyright 2020 Alibaba Group Holding Limited. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// predefine for GRIN +#include "../predefine.h" +// storage headers +#include "storage/loadmoderngraph.h" +#include "storage/storage.h" + +#define DEMO_STORAGE_NAMESPACE demo_storage_namespace + +void demo_storage_load_modern_graph(const char* graph_name, + unsigned partition_num, + unsigned partition_id) { + using DEMO_STORAGE_NAMESPACE::demo_storage; + demo_storage.LoadModernGraph(graph_name, partition_num, partition_id); +} diff --git a/demo_storage/storage/loadmoderngraph.h b/demo_storage/storage/loadmoderngraph.h new file mode 100644 index 0000000..edffb17 --- /dev/null +++ b/demo_storage/storage/loadmoderngraph.h @@ -0,0 +1,29 @@ +/** Copyright 2020 Alibaba Group Holding Limited. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef STORAGE_LOADMODERNGRAPH_H_ +#define STORAGE_LOADMODERNGRAPH_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +void demo_storage_load_modern_graph(const char*, unsigned, unsigned); + +#ifdef __cplusplus +} +#endif + +#endif // STORAGE_LOADMODERNGRAPH_H_ diff --git a/demo_storage/src/storage.cc b/demo_storage/storage/storage.cc similarity index 97% rename from demo_storage/src/storage.cc rename to demo_storage/storage/storage.cc index 13cdf7e..f8de662 100644 --- a/demo_storage/src/storage.cc +++ b/demo_storage/storage/storage.cc @@ -16,7 +16,7 @@ limitations under the License. // predefine for GRIN #include "../predefine.h" // storage headers -#include "src/storage.h" +#include "storage/storage.h" namespace DEMO_STORAGE_NAMESPACE { DemoStorage demo_storage; @@ -75,18 +75,18 @@ void Graph::AddEdge(Edge& edge) noexcept { // NOLINT both_adj_list_[std::make_tuple(source_type_id, source_id, type_id, dest_partition_id)] - .push_back(edge.GetId()); + .push_back(edge.GetGid()); both_adj_list_[std::make_tuple(dest_type_id, dest_id, type_id, source_partition_id)] - .push_back(edge.GetId()); + .push_back(edge.GetGid()); if (is_directed_) { in_adj_list_[std::make_tuple(dest_type_id, dest_id, type_id, source_partition_id)] - .push_back(edge.GetId()); + .push_back(edge.GetGid()); out_adj_list_[std::make_tuple(source_type_id, source_id, type_id, dest_partition_id)] - .push_back(edge.GetId()); + .push_back(edge.GetGid()); } } diff --git a/demo_storage/src/storage.h b/demo_storage/storage/storage.h similarity index 92% rename from demo_storage/src/storage.h rename to demo_storage/storage/storage.h index b81f415..df5a984 100644 --- a/demo_storage/src/storage.h +++ b/demo_storage/storage/storage.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -#ifndef SRC_STORAGE_H_ -#define SRC_STORAGE_H_ +#ifndef STORAGE_STORAGE_H_ +#define STORAGE_STORAGE_H_ #include #include @@ -73,6 +73,9 @@ class Vertex { // get methods uint32_t GetTypeId() const noexcept { return type_id_; } int64_t GetId() const noexcept { return id_; } + int64_t GetGid() const noexcept { + return generate_gid_from_type_id_and_id(type_id_, id_); + } GRIN_DATATYPE GetOidType() const noexcept { return oid_type_; } template @@ -146,6 +149,9 @@ class Edge { int64_t GetSource() const noexcept { return source_; } int64_t GetDest() const noexcept { return dest_; } int64_t GetId() const noexcept { return id_; } + int64_t GetGid() const noexcept { + return generate_gid_from_type_id_and_id(type_id_, id_); + } GRIN_DATATYPE GetEDataType() const noexcept { return edata_type_; } template @@ -522,8 +528,7 @@ class Graph { // vertices and edges std::vector> vertices_; std::vector> edges_; - // adj_list, adj_list_[(vtype, vid, partition_id)] = vector of global eid of - // edges + // adj_list_[(vtype, vid, partition_id)] = vector of global eid for edges std::map, std::vector> in_adj_list_, out_adj_list_, both_adj_list_; @@ -543,21 +548,30 @@ class DemoStorage { } public: - Graph* GetGraph(const std::string& graph_name) noexcept { - if (graphs_.find(graph_name) != graphs_.end()) { - return graphs_.at(graph_name); + Graph* GetGraph(const std::string& graph_name, uint32_t partition_num, + uint32_t partition_id) noexcept { + auto tuple = std::make_tuple(graph_name, partition_num, partition_id); + if (graphs_.find(tuple) != graphs_.end()) { + return graphs_.at(tuple); } return NULL; } - void PutGraph(const std::string& graph_name, Graph* graph) noexcept { - graphs_[graph_name] = graph; + void PutGraph(const std::string& graph_name, uint32_t partition_num, + uint32_t partition_id, Graph* graph) noexcept { + auto tuple = std::make_tuple(graph_name, partition_num, partition_id); + if (graphs_.find(tuple) != graphs_.end()) { + delete graphs_.at(tuple); + } + graphs_[tuple] = graph; } - void RemoveGraph(const std::string& graph_name) noexcept { - if (graphs_.find(graph_name) != graphs_.end()) { - delete graphs_.at(graph_name); - graphs_.erase(graph_name); + void RemoveGraph(const std::string& graph_name, uint32_t partition_num, + uint32_t partition_id) noexcept { + auto tuple = std::make_tuple(graph_name, partition_num, partition_id); + if (graphs_.find(tuple) != graphs_.end()) { + delete graphs_.at(tuple); + graphs_.erase(tuple); } } @@ -571,7 +585,8 @@ class DemoStorage { void LoadModernGraph(const std::string& name, uint32_t partition_num = 1, uint32_t partition_id = 0) noexcept { Graph* graph = load_modern_graph(name, partition_num, partition_id); - graphs_[graph->GetName()] = graph; + graphs_[std::make_tuple(graph->GetName(), partition_num, partition_id)] = + graph; } private: @@ -579,11 +594,12 @@ class DemoStorage { uint32_t partition_id); private: - std::map graphs_; + // graphs_[graph_name][partition_num][partition_id] = pointer of graph + std::map, Graph*> graphs_; }; extern DemoStorage demo_storage; } // namespace DEMO_STORAGE_NAMESPACE -#endif // SRC_STORAGE_H_ +#endif // STORAGE_STORAGE_H_ From a5da9331f2c020e5ad7a6609041bd6606ad7ba70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Fri, 30 Jun 2023 15:30:05 +0800 Subject: [PATCH 06/48] Add src directory for GRIN --- demo_storage/src/predefine.h | 156 +++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 demo_storage/src/predefine.h diff --git a/demo_storage/src/predefine.h b/demo_storage/src/predefine.h new file mode 100644 index 0000000..42109c8 --- /dev/null +++ b/demo_storage/src/predefine.h @@ -0,0 +1,156 @@ +/** Copyright 2020 Alibaba Group Holding Limited. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef SRC_PREDEFINE_H_ +#define SRC_PREDEFINE_H_ + +#include +#include +#include + +#include "../predefine.h" +#include "storage/storage.h" + +typedef DEMO_STORAGE_NAMESPACE::Graph GRIN_GRAPH_T; +typedef DEMO_STORAGE_NAMESPACE::Vertex GRIN_VERTEX_T; +typedef DEMO_STORAGE_NAMESPACE::Edge GRIN_EDGE_T; +typedef DEMO_STORAGE_NAMESPACE::Property GRIN_PROPERTY_T; + +typedef std::vector GRIN_VERTEX_TYPE_LIST_T; +typedef std::vector GRIN_VERTEX_PROPERTY_LIST_T; +typedef std::vector GRIN_EDGE_TYPE_LIST_T; +typedef std::vector GRIN_EDGE_PROPERTY_LIST_T; +typedef std::vector GRIN_VEV_TYPE_LIST_T; +typedef std::vector GRIN_PARTITION_LIST_T; + +typedef std::vector GRIN_ROW_T; + +typedef enum { + ALL_PARTITION = 0, + ONE_PARTITION = 1, + ALL_BUT_ONE_PARTITION = 2, + PARTITION_TYPE_MAX = 3 +} PARTITION_TYPE_IN_LIST; + +struct GRIN_PARTITIONED_GRAPH_T { + std::string name; + unsigned partition_num; + GRIN_PARTITIONED_GRAPH_T(std::string _name, unsigned _partition_num) + : name(_name), partition_num(_partition_num) {} +}; + +struct GRIN_VERTEX_LIST_T { + unsigned type_id; + PARTITION_TYPE_IN_LIST partition_type; + // only used when partition_type is ONE_PARTITION/ALL_BUT_ONE_PARTITION + unsigned partition_id; + GRIN_VERTEX_LIST_T(unsigned _type_id, + PARTITION_TYPE_IN_LIST _partition_type = ALL_PARTITION, + unsigned _partition_id = 0) + : type_id(_type_id), + partition_type(_partition_type), + partition_id(_partition_id) {} +}; + +struct GRIN_VERTEX_LIST_ITERATOR_T { + unsigned type_id; + PARTITION_TYPE_IN_LIST partition_type; + // only used when partition_type is ONE_PARTITION/ALL_BUT_ONE_PARTITION + unsigned partition_id; + int64_t current_offset; + GRIN_VERTEX_LIST_ITERATOR_T(unsigned _type_id, + PARTITION_TYPE_IN_LIST _partition_type, + unsigned _partition_id, int64_t _current_offset) + : type_id(_type_id), + partition_type(_partition_type), + partition_id(_partition_id), + current_offset(_current_offset) {} +}; + +struct GRIN_EDGE_LIST_T { + unsigned type_id; + PARTITION_TYPE_IN_LIST partition_type; + // only used when partition_type is ONE_PARTITION/ALL_BUT_ONE_PARTITION + unsigned partition_id; + GRIN_EDGE_LIST_T(unsigned _type_id, + PARTITION_TYPE_IN_LIST _partition_type = ALL_PARTITION, + unsigned _partition_id = 0) + : type_id(_type_id), + partition_type(_partition_type), + partition_id(_partition_id) {} +}; + +struct GRIN_EDGE_LIST_ITERATOR_T { + unsigned type_id; + PARTITION_TYPE_IN_LIST partition_type; + // only used when partition_type is ONE_PARTITION/ALL_BUT_ONE_PARTITION + unsigned partition_id; + int64_t current_offset; + GRIN_EDGE_LIST_ITERATOR_T(unsigned _type_id, + PARTITION_TYPE_IN_LIST _partition_type, + unsigned _partition_id, int64_t _current_offset) + : type_id(_type_id), + partition_type(_partition_type), + partition_id(_partition_id), + current_offset(_current_offset) {} +}; + +struct GRIN_ADJACENT_LIST_T { + unsigned vtype_id; + int64_t vid; + GRIN_DIRECTION dir; + unsigned etype_id; + PARTITION_TYPE_IN_LIST partition_type; + // only used when partition_type is ONE_PARTITION/ALL_BUT_ONE_PARTITION + unsigned partition_id; + GRIN_ADJACENT_LIST_T(unsigned _vtype_id, int64_t _vid, GRIN_DIRECTION _dir, + unsigned _etype_id, + PARTITION_TYPE_IN_LIST _partition_type = ALL_PARTITION, + unsigned _partition_id = 0) + : vtype_id(_vtype_id), + vid(_vid), + dir(_dir), + etype_id(_etype_id), + partition_type(_partition_type), + partition_id(_partition_id) {} +}; + +struct GRIN_ADJACENT_LIST_ITERATOR_T { + unsigned vtype_id; + int64_t vid; + GRIN_DIRECTION dir; + unsigned etype_id; + PARTITION_TYPE_IN_LIST partition_type; + // only used when partition_type is ONE_PARTITION/ALL_BUT_ONE_PARTITION + unsigned partition_id; + unsigned current_partition; + int64_t current_offset; + GRIN_ADJACENT_LIST_ITERATOR_T(unsigned _vtype_id, int64_t _vid, + GRIN_DIRECTION _dir, unsigned _etype_id, + PARTITION_TYPE_IN_LIST _partition_type, + unsigned _partition_id, + unsigned _current_partition, + int64_t _current_offset) + : vtype_id(_vtype_id), + vid(_vid), + dir(_dir), + etype_id(_etype_id), + partition_type(_partition_type), + partition_id(_partition_id), + current_partition(_current_partition), + current_offset(_current_offset) {} +}; + +#endif // SRC_PREDEFINE_H_ From b3540164d11bd475a39915ef776aa5561c1eac65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Fri, 30 Jun 2023 15:30:25 +0800 Subject: [PATCH 07/48] Add test directory --- demo_storage/test/test.c | 1061 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 1061 insertions(+) create mode 100644 demo_storage/test/test.c diff --git a/demo_storage/test/test.c b/demo_storage/test/test.c new file mode 100644 index 0000000..c272df5 --- /dev/null +++ b/demo_storage/test/test.c @@ -0,0 +1,1061 @@ +#include +#include +#include +#include +// predefine for GRIN +#include "predefine.h" +// storage headers +#include "storage/loadmoderngraph.h" +// GRIN headers +#include "common/error.h" +#include "index/internal_id.h" +#include "index/label.h" +#include "index/order.h" +#include "index/pk.h" +#include "partition/partition.h" +#include "partition/reference.h" +#include "partition/topology.h" +#include "property/partition.h" +#include "property/primarykey.h" +#include "property/property.h" +#include "property/propertylist.h" +#include "property/row.h" +#include "property/topology.h" +#include "property/type.h" +#include "topology/adjacentlist.h" +#include "topology/edgelist.h" +#include "topology/structure.h" +#include "topology/vertexlist.h" + + +#define FOR_VERTEX_BEGIN(g, vl, v) \ + GRIN_VERTEX_LIST_ITERATOR __vli = grin_get_vertex_list_begin(g, vl); \ + unsigned __vcnt = 0; \ + while (!grin_is_vertex_list_end(g, __vli)) { \ + GRIN_VERTEX v = grin_get_vertex_from_iter(g, __vli); \ + +#ifdef GRIN_WITH_VERTEX_PROPERTY +#define FOR_VERTEX_END(g, vl, v) \ + grin_destroy_vertex(g, v); \ + __vcnt++; \ + grin_get_next_vertex_list_iter(g, __vli); \ + } \ + printf("vertex type %s, checked: %u\n", vt_names[__vtl_i], __vcnt); + +#define FOR_VERTEX_LIST_BEGIN(g, vl) \ +{ GRIN_VERTEX_TYPE_LIST __vtl = grin_get_vertex_type_list(g); \ + size_t __vtl_sz = grin_get_vertex_type_list_size(g, __vtl); \ + for (size_t __vtl_i = 0; __vtl_i < __vtl_sz; ++__vtl_i) { \ + GRIN_VERTEX_TYPE __vt = grin_get_vertex_type_from_list(g, __vtl, __vtl_i); \ + GRIN_VERTEX_LIST vl = grin_get_vertex_list_by_type(g, __vt); \ + grin_destroy_vertex_type(g, __vt); + +#define FOR_VERTEX_LIST_SELECT_MASTER_BEGIN(g, vl) \ +{ GRIN_VERTEX_TYPE_LIST __vtl = grin_get_vertex_type_list(g); \ + size_t __vtl_sz = grin_get_vertex_type_list_size(g, __vtl); \ + for (size_t __vtl_i = 0; __vtl_i < __vtl_sz; ++__vtl_i) { \ + GRIN_VERTEX_TYPE __vt = grin_get_vertex_type_from_list(g, __vtl, __vtl_i); \ + GRIN_VERTEX_LIST vl = grin_get_vertex_list_by_type_select_master(g, __vt); \ + grin_destroy_vertex_type(g, __vt); + +#define FOR_VERTEX_LIST_SELECT_MIRROR_BEGIN(g, vl) \ +{ GRIN_VERTEX_TYPE_LIST __vtl = grin_get_vertex_type_list(g); \ + size_t __vtl_sz = grin_get_vertex_type_list_size(g, __vtl); \ + for (size_t __vtl_i = 0; __vtl_i < __vtl_sz; ++__vtl_i) { \ + GRIN_VERTEX_TYPE __vt = grin_get_vertex_type_from_list(g, __vtl, __vtl_i); \ + GRIN_VERTEX_LIST vl = grin_get_vertex_list_by_type_select_mirror(g, __vt); \ + grin_destroy_vertex_type(g, __vt); + +#define FOR_VERTEX_LIST_END(g, vl) \ + grin_destroy_vertex_list(g, vl); \ + } \ + grin_destroy_vertex_type_list(g, __vtl);} +#else +#define FOR_VERTEX_END(g, vl) \ + grin_destroy_vertex(g, v); \ + __vcnt++; \ + grin_get_next_vertex_list_iter(g, __vli); \ + } \ + printf("vertex checked: %u\n", __vcnt); + +#define FOR_VERTEX_LIST_BEGIN(g, vl) \ + GRIN_VERTEX_LIST vl = grin_get_vertex_list(g); + +#define FOR_VERTEX_LIST_SELECT_MASTER_BEGIN(g, vl) \ + GRIN_VERTEX_LIST vl = grin_get_vertex_list_select_master(g); + +#define FOR_VERTEX_LIST_SELECT_MIRROR_BEGIN(g, vl) \ + GRIN_VERTEX_LIST vl = grin_get_vertex_list_select_mirror(g); + +#define FOR_VERTEX_LIST_END(g, vl) \ + grin_destroy_vertex_list(g, vl); +#endif + + + +#ifdef GRIN_WITH_EDGE_PROPERTY +#define FOR_ADJ_LIST_BEGIN(g, dir, v, al) \ +{ GRIN_EDGE_TYPE_LIST __etl = grin_get_edge_type_list(g); \ + size_t __etl_size = grin_get_edge_type_list_size(g, __etl); \ + for (size_t __etl_i = 0; __etl_i < __etl_size; ++__etl_i) { \ + GRIN_EDGE_TYPE __et = grin_get_edge_type_from_list(g, __etl, __etl_i); \ + GRIN_ADJACENT_LIST al = grin_get_adjacent_list_by_edge_type(g, dir, v, __et); \ + grin_destroy_edge_type(g, __et); +#define FOR_ADJ_LIST_END(g, al) \ + grin_destroy_adjacent_list(g, al); \ + } \ + grin_destroy_edge_type_list(g, __etl);} +#else +#define FOR_ADJ_LIST_BEGIN(g, dir, v, al) \ + GRIN_ADJACENT_LIST al = grin_get_adjacent_list(g, dir, v); +#define FOR_ADJ_LIST_END(g, al) \ + grin_destroy_adjacent_list(g, al); +#endif + + +const char *vt_names[] = {"person", "software"}; +const char *et_names[] = {"created", "knows"}; + +const char *v_names[][4] = { + {"josh", "vadas", "peter", "marko"}, + {"lop", "ripple", "wrong", "wrong"} +}; // TODO align with order in local graph + +GRIN_GRAPH get_graph(int argc, char** argv, int p) { +#ifdef GRIN_ENABLE_GRAPH_PARTITION + GRIN_PARTITIONED_GRAPH pg = + grin_get_partitioned_graph_from_storage(argv[1]); + GRIN_PARTITION_LIST local_partitions = grin_get_local_partition_list(pg); + assert(p < grin_get_partition_list_size(pg, local_partitions)); + GRIN_PARTITION partition = + grin_get_partition_from_list(pg, local_partitions, p); + GRIN_PARTITION_ID partition_id = grin_get_partition_id(pg, partition); + GRIN_PARTITION p1 = grin_get_partition_by_id(pg, partition_id); + if (!grin_equal_partition(pg, partition, p1)) { + printf("partition not match\n"); + } + grin_destroy_partition(pg, p1); + GRIN_GRAPH g = grin_get_local_graph_by_partition(pg, partition); + grin_destroy_partition(pg, partition); + grin_destroy_partition_list(pg, local_partitions); + grin_destroy_partitioned_graph(pg); +#else + GRIN_GRAPH g = grin_get_graph_from_storage(argv[1]); +#endif + return g; +} + + +#ifdef GRIN_ENABLE_GRAPH_PARTITION +GRIN_VERTEX get_one_master_person(GRIN_GRAPH g) { + GRIN_VERTEX_TYPE vt = grin_get_vertex_type_by_name(g, "person"); + GRIN_VERTEX_LIST vl = grin_get_vertex_list_by_type_select_master(g, vt); + grin_destroy_vertex_type(g, vt); + GRIN_VERTEX_LIST_ITERATOR vli = grin_get_vertex_list_begin(g, vl); + GRIN_VERTEX v = grin_get_vertex_from_iter(g, vli); + grin_destroy_vertex_list_iter(g, vli); + grin_destroy_vertex_list(g, vl); +#ifdef GRIN_ENABLE_VERTEX_INTERNAL_ID_INDEX + printf("Got vertex %s\n", v_names[vt][grin_get_vertex_internal_id_by_type(g, vt, v)]); +#endif + return v; +} +#endif + + +GRIN_VERTEX get_one_person(GRIN_GRAPH g) { + GRIN_VERTEX_TYPE vt = grin_get_vertex_type_by_name(g, "person"); + GRIN_VERTEX_LIST vl = grin_get_vertex_list_by_type(g, vt); + grin_destroy_vertex_type(g, vt); + GRIN_VERTEX_LIST_ITERATOR vli = grin_get_vertex_list_begin(g, vl); + GRIN_VERTEX v = grin_get_vertex_from_iter(g, vli); + grin_destroy_vertex_list_iter(g, vli); + grin_destroy_vertex_list(g, vl); +#ifdef GRIN_ENABLE_VERTEX_INTERNAL_ID_INDEX + printf("Got vertex %s\n", v_names[vt][grin_get_vertex_internal_id_by_type(g, vt, v)]); +#endif + return v; +} + + +void test_property_type(int argc, char** argv) { + printf("+++++++++++++++++++++ Test property/type +++++++++++++++++++++\n"); + + GRIN_GRAPH g = get_graph(argc, argv, 0); + + printf("------------ Vertex Type ------------\n"); + GRIN_VERTEX_TYPE_LIST vtl = grin_get_vertex_type_list(g); + size_t vtl_size = grin_get_vertex_type_list_size(g, vtl); + printf("vertex type list size: %zu\n", vtl_size); + + for (size_t i = 0; i < vtl_size; ++i) { + printf("------------ Iterate the %zu-th vertex type ------------\n", i); + GRIN_VERTEX_TYPE vt = grin_get_vertex_type_from_list(g, vtl, i); +#ifdef GRIN_WITH_VERTEX_TYPE_NAME + const char* vt_name = grin_get_vertex_type_name(g, vt); + printf("vertex type name: %s\n", vt_name); + GRIN_VERTEX_TYPE vt0 = grin_get_vertex_type_by_name(g, vt_name); + if (!grin_equal_vertex_type(g, vt, vt0)) { + printf("vertex type name not match\n"); + } + grin_destroy_vertex_type(g, vt0); +#endif +#ifdef GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_TYPE + printf("vertex type id: %u\n", grin_get_vertex_type_id(g, vt)); + GRIN_VERTEX_TYPE vt1 = + grin_get_vertex_type_by_id(g, grin_get_vertex_type_id(g, vt)); + if (!grin_equal_vertex_type(g, vt, vt1)) { + printf("vertex type id not match\n"); + } + grin_destroy_vertex_type(g, vt1); +#endif + } + grin_destroy_vertex_type_list(g, vtl); + + printf( + "------------ Create a vertex type list of one type \"person\" " + "------------\n"); + GRIN_VERTEX_TYPE_LIST vtl2 = grin_create_vertex_type_list(g); +#ifdef GRIN_WITH_VERTEX_TYPE_NAME + GRIN_VERTEX_TYPE vt2_w = grin_get_vertex_type_by_name(g, "knows"); + if (vt2_w == GRIN_NULL_VERTEX_TYPE) { + printf("(Correct) vertex type of knows does not exists\n"); + } + GRIN_VERTEX_TYPE vt2 = grin_get_vertex_type_by_name(g, "person"); + if (vt2 == GRIN_NULL_VERTEX_TYPE) { + printf("(Wrong) vertex type of person can not be found\n"); + } else { + const char* vt2_name = grin_get_vertex_type_name(g, vt2); + printf("vertex type name: %s\n", vt2_name); + } +#else + GRIN_VERTEX_TYPE vt2 = get_one_vertex_type(g); +#endif + grin_insert_vertex_type_to_list(g, vtl2, vt2); + size_t vtl2_size = grin_get_vertex_type_list_size(g, vtl2); + printf("created vertex type list size: %zu\n", vtl2_size); + GRIN_VERTEX_TYPE vt3 = grin_get_vertex_type_from_list(g, vtl2, 0); + if (!grin_equal_vertex_type(g, vt2, vt3)) { + printf("vertex type not match\n"); + } + grin_destroy_vertex_type(g, vt2); + grin_destroy_vertex_type(g, vt3); + grin_destroy_vertex_type_list(g, vtl2); + + // edge + printf("------------ Edge Type ------------\n"); + GRIN_EDGE_TYPE_LIST etl = grin_get_edge_type_list(g); + size_t etl_size = grin_get_edge_type_list_size(g, etl); + printf("edge type list size: %zu\n", etl_size); + + for (size_t i = 0; i < etl_size; ++i) { + printf("------------ Iterate the %zu-th edge type ------------\n", i); + GRIN_EDGE_TYPE et = grin_get_edge_type_from_list(g, etl, i); +#ifdef GRIN_WITH_EDGE_TYPE_NAME + const char* et_name = grin_get_edge_type_name(g, et); + printf("edge type name: %s\n", et_name); + GRIN_EDGE_TYPE et0 = grin_get_edge_type_by_name(g, et_name); + if (!grin_equal_edge_type(g, et, et0)) { + printf("edge type name not match\n"); + } + grin_destroy_edge_type(g, et0); +#endif +#ifdef GRIN_TRAIT_NATURAL_ID_FOR_EDGE_TYPE + printf("edge type id: %u\n", grin_get_edge_type_id(g, et)); + GRIN_EDGE_TYPE et1 = + grin_get_edge_type_by_id(g, grin_get_edge_type_id(g, et)); + if (!grin_equal_edge_type(g, et, et1)) { + printf("edge type id not match\n"); + } + grin_destroy_edge_type(g, et1); +#endif + // relation + GRIN_VERTEX_TYPE_LIST src_vtl = grin_get_src_types_by_edge_type(g, et); + size_t src_vtl_size = grin_get_vertex_type_list_size(g, src_vtl); + printf("source vertex type list size: %zu\n", src_vtl_size); + + GRIN_VERTEX_TYPE_LIST dst_vtl = grin_get_dst_types_by_edge_type(g, et); + size_t dst_vtl_size = grin_get_vertex_type_list_size(g, dst_vtl); + printf("destination vertex type list size: %zu\n", dst_vtl_size); + + if (src_vtl_size != dst_vtl_size) { + printf("source and destination vertex type list size not match\n"); + } + for (size_t j = 0; j < src_vtl_size; ++j) { + GRIN_VERTEX_TYPE src_vt = grin_get_vertex_type_from_list(g, src_vtl, j); + GRIN_VERTEX_TYPE dst_vt = grin_get_vertex_type_from_list(g, dst_vtl, j); + const char* src_vt_name = grin_get_vertex_type_name(g, src_vt); + const char* dst_vt_name = grin_get_vertex_type_name(g, dst_vt); + const char* et_name = grin_get_edge_type_name(g, et); + printf("edge type name: %s-%s-%s\n", src_vt_name, et_name, dst_vt_name); + grin_destroy_vertex_type(g, src_vt); + grin_destroy_vertex_type(g, dst_vt); + } + grin_destroy_vertex_type_list(g, src_vtl); + grin_destroy_vertex_type_list(g, dst_vtl); + } + grin_destroy_edge_type_list(g, etl); + + printf( + "------------ Create an edge type list of one type \"created\" " + "------------\n"); + GRIN_EDGE_TYPE_LIST etl2 = grin_create_edge_type_list(g); +#ifdef GRIN_WITH_EDGE_TYPE_NAME + GRIN_EDGE_TYPE et2_w = grin_get_edge_type_by_name(g, "person"); + if (et2_w == GRIN_NULL_EDGE_TYPE) { + printf("(Correct) edge type of person does not exists\n"); + } + GRIN_EDGE_TYPE et2 = grin_get_edge_type_by_name(g, "created"); + if (et2 == GRIN_NULL_EDGE_TYPE) { + printf("(Wrong) edge type of created can not be found\n"); + } else { + const char* et2_name = grin_get_edge_type_name(g, et2); + printf("edge type name: %s\n", et2_name); + } +#else + GRIN_EDGE_TYPE et2 = get_one_edge_type(g); +#endif + grin_insert_edge_type_to_list(g, etl2, et2); + size_t etl2_size = grin_get_edge_type_list_size(g, etl2); + printf("created edge type list size: %zu\n", etl2_size); + GRIN_EDGE_TYPE et3 = grin_get_edge_type_from_list(g, etl2, 0); + if (!grin_equal_edge_type(g, et2, et3)) { + printf("edge type not match\n"); + } + grin_destroy_edge_type(g, et2); + grin_destroy_edge_type(g, et3); + grin_destroy_edge_type_list(g, etl2); + + grin_destroy_graph(g); +} + +void test_property_vertex_property_value(int argc, char** argv) { + printf("------------ Test Vertex property value ------------\n"); + GRIN_GRAPH g = get_graph(argc, argv, 0); + +// value check + printf("------ check value ------\n"); +FOR_VERTEX_LIST_SELECT_MASTER_BEGIN(g, vl) + GRIN_VERTEX_PROPERTY_LIST vpl = grin_get_vertex_property_list_by_type(g, __vt); + size_t vpl_size = grin_get_vertex_property_list_size(g, vpl); + FOR_VERTEX_BEGIN(g, vl, v) + #ifdef GRIN_ENABLE_VERTEX_INTERNAL_ID_INDEX + long long int vid = grin_get_vertex_internal_id_by_type(g, __vt, v); + #else + long long int vid = __vcnt; + #endif + #ifdef GRIN_ENABLE_ROW + GRIN_ROW row = grin_get_vertex_row(g, v); + #endif + for (size_t j = 0; j < vpl_size; ++j) { + GRIN_VERTEX_PROPERTY vp = grin_get_vertex_property_from_list(g, vpl, j); + GRIN_DATATYPE dt = grin_get_vertex_property_datatype(g, vp); + if (dt == Int64) { + long long int pv = + grin_get_vertex_property_value_of_int64(g, v, vp); + assert(grin_get_last_error_code() == NO_ERROR); + #ifdef GRIN_ENABLE_ROW + long long int rv = grin_get_int64_from_row(g, row, j); + assert(pv == rv); + #endif + #ifdef GRIN_WITH_VERTEX_PROPERTY_NAME + printf("%s %s: %lld\n", v_names[__vt][vid], grin_get_vertex_property_name(g, __vt, vp), pv); + #else + printf("%s %zu: %lld\n", v_names[__vt][vid], j, pv); + #endif + } else if (dt == String) { + const char* pv = + grin_get_vertex_property_value_of_string(g, v, vp); + assert(grin_get_last_error_code() == NO_ERROR); + #ifdef GRIN_ENABLE_ROW + const char* rv = grin_get_string_from_row(g, row, j); + assert(strcmp(pv, rv) == 0); + #endif + #ifdef GRIN_WITH_VERTEX_PROPERTY_NAME + printf("%s %s: %s\n", v_names[__vt][vid], grin_get_vertex_property_name(g, __vt, vp), pv); + #else + printf("%s %zu: %s\n", v_names[__vt][vid], j, pv); + #endif + grin_destroy_string_value(g, pv); + grin_destroy_string_value(g, rv); + } + grin_destroy_vertex_property(g, vp); + } + #ifdef GRIN_ENABLE_ROW + grin_destroy_row(g, row); + #endif + FOR_VERTEX_END(g, vl, v) + grin_destroy_vertex_property_list(g, vpl); +FOR_VERTEX_LIST_END(g, vl) + +// check schema + printf("------ check schema ------\n"); + GRIN_VERTEX_TYPE_LIST vtl = grin_get_vertex_type_list(g); + size_t vtl_size = grin_get_vertex_type_list_size(g, vtl); + for (size_t i = 0; i < vtl_size; ++i) { + GRIN_VERTEX_TYPE vt = grin_get_vertex_type_from_list(g, vtl, i); + GRIN_VERTEX_PROPERTY_LIST vpl = grin_get_vertex_property_list_by_type(g, vt); + size_t vpl_size = grin_get_vertex_property_list_size(g, vpl); + for (size_t j = 0; j < vpl_size; ++j) { + GRIN_VERTEX_PROPERTY vp = grin_get_vertex_property_from_list(g, vpl, j); + GRIN_VERTEX_TYPE vt1 = grin_get_vertex_type_from_property(g, vp); + assert(grin_equal_vertex_type(g, vt, vt1)); + grin_destroy_vertex_type(g, vt1); + + #ifdef GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_PROPERTY + unsigned int id = grin_get_vertex_property_id(g, vt, vp); + GRIN_VERTEX_PROPERTY vp1 = grin_get_vertex_property_by_id(g, vt, id); + assert(grin_equal_vertex_property(g, vp, vp1)); + grin_destroy_vertex_property(g, vp1); + #else + unsigned int id = i; + #endif + + #ifdef GRIN_WITH_VERTEX_PROPERTY_NAME + const char* vp_name = grin_get_vertex_property_name(g, vt, vp); + GRIN_VERTEX_PROPERTY vp2 = + grin_get_vertex_property_by_name(g, vt, vp_name); + assert(grin_equal_vertex_property(g, vp, vp2)); + #else + const char* vp_name = "unknown"; + #endif + printf("%s %u %s checked\n", vt_names[i], id, vp_name); + } + grin_destroy_vertex_property_list(g, vpl); + + // corner case + #ifdef GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_PROPERTY + GRIN_VERTEX_PROPERTY vp3 = grin_get_vertex_property_by_id(g, vt, vpl_size); + assert(vp3 == GRIN_NULL_VERTEX_PROPERTY); + #endif + + #ifdef GRIN_WITH_VERTEX_PROPERTY_NAME + GRIN_VERTEX_PROPERTY vp4 = + grin_get_vertex_property_by_name(g, vt, "unknown"); + assert(vp4 == GRIN_NULL_VERTEX_PROPERTY); + #endif + grin_destroy_vertex_type(g, vt); + } + grin_destroy_vertex_type_list(g, vtl); + + // corner case +#ifdef GRIN_WITH_VERTEX_PROPERTY_NAME + GRIN_VERTEX_PROPERTY_LIST vpl1 = + grin_get_vertex_properties_by_name(g, "unknown"); + assert(vpl1 == GRIN_NULL_VERTEX_PROPERTY_LIST); + + GRIN_VERTEX_PROPERTY_LIST vpl2 = + grin_get_vertex_properties_by_name(g, "name"); + assert(vpl2 != GRIN_NULL_VERTEX_PROPERTY_LIST); + + size_t vpl2_size = grin_get_vertex_property_list_size(g, vpl2); + for (size_t i = 0; i < vpl2_size; ++i) { + GRIN_VERTEX_PROPERTY vp5 = + grin_get_vertex_property_from_list(g, vpl2, i); + GRIN_VERTEX_TYPE vt5 = grin_get_vertex_type_from_property(g, vp5); + const char* vp5_name = grin_get_vertex_property_name(g, vt5, vp5); + assert(strcmp(vp5_name, "name") == 0); + } + grin_destroy_vertex_property_list(g, vpl2); +#endif + + grin_destroy_graph(g); +} + +void test_property_edge_property_value(int argc, char** argv, GRIN_DIRECTION dir) { + printf("------------ Test Edge property value ------------\n"); + GRIN_GRAPH g = get_graph(argc, argv, 0); + +// value check + printf("------ check value ------\n"); +FOR_VERTEX_LIST_SELECT_MASTER_BEGIN(g, vl) + FOR_VERTEX_BEGIN(g, vl, v) + FOR_ADJ_LIST_BEGIN(g, dir, v, al) + GRIN_EDGE_PROPERTY_LIST epl = grin_get_edge_property_list_by_type(g, __et); + size_t epl_size = grin_get_edge_property_list_size(g, epl); + + GRIN_ADJACENT_LIST_ITERATOR ali = grin_get_adjacent_list_begin(g, al); + size_t acnt = 0; + while (!grin_is_adjacent_list_end(g, ali)) { + GRIN_EDGE e = grin_get_edge_from_adjacent_list_iter(g, ali); + GRIN_VERTEX u = grin_get_neighbor_from_adjacent_list_iter(g, ali); + #ifdef GRIN_ENABLE_VERTEX_INTERNAL_ID_INDEX + GRIN_VERTEX_TYPE ut = grin_get_vertex_type(g, u); + long long int vid = grin_get_vertex_internal_id_by_type(g, __vt, v); + long long int uid = grin_get_vertex_internal_id_by_type(g, ut, u); + grin_destroy_vertex_type(g, ut); + #else + long long int vid = __vcnt; + long long int uid = acnt; + #endif + #ifdef GRIN_ENABLE_ROW + GRIN_ROW row = grin_get_edge_row(g, e); + #endif + for (size_t j = 0; j < epl_size; ++j) { + GRIN_EDGE_PROPERTY ep = grin_get_edge_property_from_list(g, epl, j); + GRIN_DATATYPE dt = grin_get_edge_property_datatype(g, ep); + if (dt == Int64) { + long long int pv = + grin_get_edge_property_value_of_int64(g, e, ep); + assert(grin_get_last_error_code() == NO_ERROR); + #ifdef GRIN_ENABLE_ROW + long long int rv = grin_get_int64_from_row(g, row, j); + assert(pv == rv); + #endif + #ifdef GRIN_WITH_EDGE_PROPERTY_NAME + printf("%s %s %s: %lld\n", v_names[__vt][vid], v_names[ut][uid], + grin_get_edge_property_name(g, __et, ep), pv); + #else + printf("%s %zu %lld: %lld\n", v_names[__vt][vid], j, uid, pv); + #endif + } else if (dt == Double) { + double pv = grin_get_edge_property_value_of_double(g, e, ep); + assert(grin_get_last_error_code() == NO_ERROR); + #ifdef GRIN_ENABLE_ROW + double rv = grin_get_double_from_row(g, row, j); + assert(pv == rv); + #endif + #ifdef GRIN_WITH_EDGE_PROPERTY_NAME + printf("%s %s %s: %lf\n", v_names[__vt][vid], v_names[ut][uid], + grin_get_edge_property_name(g, __et, ep), pv); + #else + printf("%s %zu %lld: %lf\n", v_names[__vt][vid], j, uid, pv); + #endif + } else if (dt == String) { + const char* pv = grin_get_edge_property_value_of_string(g, e, ep); + assert(grin_get_last_error_code() == NO_ERROR); + #ifdef GRIN_ENABLE_ROW + const char* rv = grin_get_string_from_row(g, row, j); + assert(strcmp(pv, rv) == 0); + #endif + #ifdef GRIN_WITH_EDGE_PROPERTY_NAME + printf("%s %s %s: %s\n", v_names[__vt][vid], v_names[ut][uid], + grin_get_edge_property_name(g, __et, ep), pv); + #else + printf("%s %zu %lld: %s\n", v_names[__vt][vid], j, uid, pv); + #endif + } + } + #ifdef GRIN_ENABLE_ROW + grin_destroy_row(g, row); + #endif + grin_destroy_edge(g, e); + grin_destroy_vertex(g, u); + acnt++; + grin_get_next_adjacent_list_iter(g, ali); + } + grin_destroy_adjacent_list_iter(g, ali); + grin_destroy_edge_property_list(g, epl); + FOR_ADJ_LIST_END(g, al) + FOR_VERTEX_END(g, vl, v) +FOR_VERTEX_LIST_END(g, vl) + +// check schema + printf("------ check schema ------\n"); + GRIN_EDGE_TYPE_LIST etl = grin_get_edge_type_list(g); + size_t etl_size = grin_get_edge_type_list_size(g, etl); + for (size_t i = 0; i < etl_size; ++i) { + GRIN_EDGE_TYPE et = grin_get_edge_type_from_list(g, etl, i); + GRIN_EDGE_PROPERTY_LIST epl = grin_get_edge_property_list_by_type(g, et); + size_t epl_size = grin_get_edge_property_list_size(g, epl); + for (size_t j = 0; j < epl_size; ++j) { + GRIN_EDGE_PROPERTY ep = grin_get_edge_property_from_list(g, epl, j); + GRIN_EDGE_TYPE et1 = grin_get_edge_type_from_property(g, ep); + assert(grin_equal_edge_type(g, et, et1)); + grin_destroy_edge_type(g, et1); + + #ifdef GRIN_TRAIT_NATURAL_ID_FOR_EDGE_PROPERTY + unsigned int id = grin_get_edge_property_id(g, et, ep); + GRIN_EDGE_PROPERTY ep1 = grin_get_edge_property_by_id(g, et, id); + assert(grin_equal_edge_property(g, ep, ep1)); + grin_destroy_edge_property(g, ep1); + #else + unsigned int id = i; + #endif + + #ifdef GRIN_WITH_EDGE_PROPERTY_NAME + const char* ep_name = grin_get_edge_property_name(g, et, ep); + GRIN_EDGE_PROPERTY ep2 = + grin_get_edge_property_by_name(g, et, ep_name); + assert(grin_equal_edge_property(g, ep, ep2)); + #else + const char* ep_name = "unknown"; + #endif + printf("%s %u %s checked\n", et_names[i], id, ep_name); + } + grin_destroy_edge_property_list(g, epl); + + // corner case + #ifdef GRIN_TRAIT_NATURAL_ID_FOR_EDGE_PROPERTY + GRIN_EDGE_PROPERTY ep3 = grin_get_edge_property_by_id(g, et, epl_size); + assert(ep3 == GRIN_NULL_EDGE_PROPERTY); + #endif + + #ifdef GRIN_WITH_EDGE_PROPERTY_NAME + GRIN_EDGE_PROPERTY ep4 = + grin_get_edge_property_by_name(g, et, "unknown"); + assert(ep4 == GRIN_NULL_EDGE_PROPERTY); + #endif + grin_destroy_edge_type(g, et); + } + grin_destroy_edge_type_list(g, etl); + + // corner case +#ifdef GRIN_WITH_EDGE_PROPERTY_NAME + GRIN_EDGE_PROPERTY_LIST epl1 = + grin_get_edge_properties_by_name(g, "unknown"); + assert(epl1 == GRIN_NULL_EDGE_PROPERTY_LIST); + + GRIN_EDGE_PROPERTY_LIST epl2 = + grin_get_edge_properties_by_name(g, "weight"); + assert(epl2 != GRIN_NULL_EDGE_PROPERTY_LIST); + + size_t epl2_size = grin_get_edge_property_list_size(g, epl2); + for (size_t i = 0; i < epl2_size; ++i) { + GRIN_EDGE_PROPERTY ep5 = + grin_get_edge_property_from_list(g, epl2, i); + GRIN_EDGE_TYPE et5 = grin_get_edge_type_from_property(g, ep5); + const char* ep5_name = grin_get_edge_property_name(g, et5, ep5); + assert(strcmp(ep5_name, "weight") == 0); + } + grin_destroy_edge_property_list(g, epl2); +#endif + + grin_destroy_graph(g); +} + + +#ifdef GRIN_ENABLE_VERTEX_PRIMARY_KEYS +void test_property_primary_key(int argc, char** argv) { + printf( + "+++++++++++++++++++++ Test property/primary key " + "+++++++++++++++++++++\n"); + GRIN_GRAPH g = get_graph(argc, argv, 0); + GRIN_VERTEX_TYPE_LIST vtl = grin_get_vertex_types_with_primary_keys(g); + size_t vtl_size = grin_get_vertex_type_list_size(g, vtl); + printf("vertex type num with primary key: %zu\n", vtl_size); + + unsigned id_type[7] = {~0, 0, 0, 1, 0, 1, 0}; + + for (size_t i = 0; i < vtl_size; ++i) { + GRIN_VERTEX_TYPE vt = grin_get_vertex_type_from_list(g, vtl, i); + const char* vt_name = grin_get_vertex_type_name(g, vt); + printf("vertex type name: %s\n", vt_name); + + GRIN_VERTEX_PROPERTY_LIST vpl = grin_get_primary_keys_by_vertex_type(g, vt); + size_t vpl_size = grin_get_vertex_property_list_size(g, vpl); + assert(vpl_size == 1); + + for (size_t j = 0; j < vpl_size; ++j) { + GRIN_VERTEX_PROPERTY vp = grin_get_vertex_property_from_list(g, vpl, j); + const char* vp_name = grin_get_vertex_property_name(g, vt, vp); + printf("primary key name: %s\n", vp_name); + grin_destroy_vertex_property(g, vp); + } + + GRIN_VERTEX_PROPERTY vp = grin_get_vertex_property_from_list(g, vpl, 0); + GRIN_DATATYPE dt = grin_get_vertex_property_datatype(g, vp); + + for (size_t j = 1; j <= 6; ++j) { + GRIN_ROW r = grin_create_row(g); + assert(dt == Int64); + grin_insert_int64_to_row(g, r, j); +#ifdef GRIN_ENABLE_VERTEX_PK_INDEX + GRIN_VERTEX v = grin_get_vertex_by_primary_keys_row(g, vt, r); + if (v != GRIN_NULL_VERTEX && id_type[j] == i) { + GRIN_ROW nr = grin_get_vertex_primary_keys_row(g, v); + long long int k = grin_get_int64_from_row(g, nr, 0); + assert(k == j); + grin_destroy_row(g, nr); + grin_destroy_vertex(g, v); + } +#endif + grin_destroy_row(g, r); + } + + grin_destroy_vertex_property(g, vp); + grin_destroy_vertex_property_list(g, vpl); + grin_destroy_vertex_type(g, vt); + } + + grin_destroy_vertex_type_list(g, vtl); + grin_destroy_graph(g); +} +#endif + +void test_error_code(int argc, char** argv) { + printf("+++++++++++++++++++++ Test error code +++++++++++++++++++++\n"); + GRIN_GRAPH g = get_graph(argc, argv, 0); + + GRIN_VERTEX_TYPE vt1 = grin_get_vertex_type_by_name(g, "person"); + GRIN_VERTEX_TYPE vt2 = grin_get_vertex_type_by_name(g, "software"); + GRIN_VERTEX_PROPERTY vp = grin_get_vertex_property_by_name(g, vt2, "lang"); +#ifdef GRIN_ENABLE_GRAPH_PARTITION + GRIN_VERTEX v = get_one_master_person(g); +#else + GRIN_VERTEX v = get_one_person(g); +#endif + + const char* value = grin_get_vertex_property_value_of_string(g, v, vp); + assert(grin_get_last_error_code() == INVALID_VALUE); +} + + +void test_property(int argc, char** argv) { + test_property_type(argc, argv); + test_property_vertex_property_value(argc, argv); + test_property_edge_property_value(argc, argv, OUT); + test_property_edge_property_value(argc, argv, IN); +#ifdef GRIN_ENABLE_VERTEX_PRIMARY_KEYS + test_property_primary_key(argc, argv); +#endif +#ifdef GRIN_WITH_VERTEX_PROPERTY_NAME + // test_error_code(argc, argv); +#endif +} + + +void test_partition_reference(int argc, char** argv) { + printf("+++++++++++++++++++++ Test partition/reference +++++++++++++++++++++\n"); + GRIN_PARTITIONED_GRAPH pg = grin_get_partitioned_graph_from_storage(argv[1]); + GRIN_PARTITION_LIST local_partitions = grin_get_local_partition_list(pg); + assert(grin_get_partition_list_size(pg, local_partitions) >= 2); + + GRIN_PARTITION p0 = grin_get_partition_from_list(pg, local_partitions, 0); + GRIN_PARTITION p1 = grin_get_partition_from_list(pg, local_partitions, 1); + GRIN_GRAPH g0 = grin_get_local_graph_by_partition(pg, p0); + GRIN_GRAPH g1 = grin_get_local_graph_by_partition(pg, p1); + +FOR_VERTEX_LIST_BEGIN(g0, vl0) + size_t mcnt = 0; + FOR_VERTEX_BEGIN(g0, vl0, v0) + GRIN_VERTEX_REF vref0 = grin_get_vertex_ref_by_vertex(g0, v0); + if (grin_is_master_vertex(g0, v0)) { + mcnt++; +#ifdef GRIN_TRAIT_FAST_VERTEX_REF + long long int sref = grin_serialize_vertex_ref_as_int64(g0, vref0); + GRIN_VERTEX_REF vref1 = grin_deserialize_int64_to_vertex_ref(g0, sref); +#else + const char* sref = grin_serialize_vertex_ref(g0, vref0); + GRIN_VERTEX_REF vref1 = grin_deserialize_vertex_ref(g0, sref); + grin_destroy_string_value(g0, sref); +#endif + GRIN_VERTEX v1 = grin_get_vertex_from_vertex_ref(g0, vref1); + if (!grin_equal_vertex(g0, v0, v1)) { + printf("vertex not match after deserialize\n"); + } + GRIN_PARTITION p = grin_get_master_partition_from_vertex_ref(g0, vref0); + if (!grin_equal_partition(g0, p, p0)) { + printf("(Wrong) partition not match in vertex ref\n"); + } + grin_destroy_partition(pg, p); + grin_destroy_vertex(g0, v1); + grin_destroy_vertex_ref(g0, vref1); + } else if (grin_is_mirror_vertex(g0, v0)) { +#ifdef GRIN_TRAIT_FAST_VERTEX_REF + long long int sref = grin_serialize_vertex_ref_as_int64(g0, vref0); + GRIN_VERTEX_REF vref1 = grin_deserialize_int64_to_vertex_ref(g1, sref); +#else + const char* sref = grin_serialize_vertex_ref(g0, vref0); + GRIN_VERTEX_REF vref1 = grin_deserialize_vertex_ref(g1, sref); + grin_destroy_string_value(g0, sref); +#endif + GRIN_VERTEX v1 = grin_get_vertex_from_vertex_ref(g1, vref1); + if (!grin_is_master_vertex(g1, v1)) { + printf("(Wrong) vertex not master after deserialize\n"); + } + GRIN_PARTITION p = grin_get_master_partition_from_vertex_ref(g0, vref0); + if (!grin_equal_partition(g0, p, p1)) { + printf("(Wrong) partition not match in vertex ref\n"); + } + grin_destroy_partition(pg, p); + grin_destroy_vertex(g1, v1); + grin_destroy_vertex_ref(g1, vref1); + } else { + printf("(Wrong) vertex other than master or mirror\n"); + } + grin_destroy_vertex_ref(g0, vref0); + FOR_VERTEX_END(g0, vl0, v0) + printf("master checked: %zu\n", mcnt); +FOR_VERTEX_LIST_END(g0, vl0) + + grin_destroy_partition(pg, p0); + grin_destroy_partition(pg, p1); + grin_destroy_graph(g0); + grin_destroy_graph(g1); + grin_destroy_partition_list(pg, local_partitions); + grin_destroy_partitioned_graph(pg); +} + + +void test_partition_topology(int argc, char** argv) { + printf("+++++++++++++++++++++ Test partition/topology +++++++++++++++++++++\n"); + GRIN_GRAPH g = get_graph(argc, argv, 0); + + printf("----- check master ----- \n"); +FOR_VERTEX_LIST_SELECT_MASTER_BEGIN(g, vl) + FOR_VERTEX_BEGIN(g, vl, v) + #ifdef GRIN_ENABLE_VERTEX_LIST_ARRAY + GRIN_VERTEX v1 = grin_get_vertex_from_list(g, vl, __vcnt); + assert(grin_equal_vertex(g, v, v1)); + grin_destroy_vertex(g, v1); + #endif + assert(grin_is_master_vertex(g, v)); + FOR_VERTEX_END(g, vl, v) +FOR_VERTEX_LIST_END(g, vl) + + printf("----- check mirror ----- \n"); +FOR_VERTEX_LIST_SELECT_MIRROR_BEGIN(g, vl) + FOR_VERTEX_BEGIN(g, vl, v) + #ifdef GRIN_ENABLE_VERTEX_LIST_ARRAY + GRIN_VERTEX v1 = grin_get_vertex_from_list(g, vl, __vcnt); + assert(grin_equal_vertex(g, v, v1)); + grin_destroy_vertex(g, v1); + #endif + assert(grin_is_mirror_vertex(g, v)); + FOR_VERTEX_END(g, vl, v) +FOR_VERTEX_LIST_END(g, vl) + + grin_destroy_graph(g); +} + +void test_partition(int argc, char** argv) { +#ifdef GRIN_ENABLE_GRAPH_PARTITION + test_partition_reference(argc, argv); + test_partition_topology(argc, argv); +#endif +} + + +void test_topology_structure(int argc, char** argv) { + printf("+++++++++++++++++++++ Test topology/structure +++++++++++++++++++++\n"); + GRIN_GRAPH g = get_graph(argc, argv, 0); +#ifndef GRIN_WITH_VERTEX_PROPERTY + printf("vertex num: %zu\n", grin_get_vertex_num(g)); +#endif + +#ifndef GRIN_WITH_EDGE_PROPERTY + printf("edge num: %zu\n", grin_get_edge_num(g)); +#endif + grin_destroy_graph(g); +} + + +void test_topology_vertex_list(int argc, char** argv) { + printf("+++++++++++++++++++++ Test topology/vertex_list +++++++++++++++++++++\n"); + GRIN_GRAPH g = get_graph(argc, argv, 0); + +FOR_VERTEX_LIST_BEGIN(g, vl) + FOR_VERTEX_BEGIN(g, vl, v) + #ifdef GRIN_ENABLE_VERTEX_LIST_ARRAY + GRIN_VERTEX v1 = grin_get_vertex_from_list(g, vl, __vcnt); + assert(grin_equal_vertex(g, v, v1)); + grin_destroy_vertex(g, v1); + #endif + FOR_VERTEX_END(g, vl, v) +FOR_VERTEX_LIST_END(g, vl) + + grin_destroy_graph(g); +} + + +void test_topology_adjacent_list(int argc, char** argv, GRIN_DIRECTION dir) { + if (dir == IN) { + printf("+++++++++++++++++++++ Test topology/adjacent_list IN +++++++++++++++++++++\n"); + } else { + printf("+++++++++++++++++++++ Test topology/adjacent_list OUT +++++++++++++++++++++\n"); + } + + GRIN_GRAPH g = get_graph(argc, argv, 0); + +FOR_VERTEX_LIST_BEGIN(g, vl) + FOR_VERTEX_BEGIN(g, vl, v) + #ifdef GRIN_ENABLE_VERTEX_INTERNAL_ID_INDEX + long long int vid = grin_get_vertex_internal_id_by_type(g, __vt, v); + #else + long long int vid = __vcnt; + #endif + #ifdef GRIN_ENABLE_GRAPH_PARTITION + if (!grin_is_master_vertex(g, v)) { + grin_destroy_vertex(g, v); + grin_get_next_vertex_list_iter(g, __vli); + continue; + } + #endif + + FOR_ADJ_LIST_BEGIN(g, dir, v, al) + GRIN_ADJACENT_LIST_ITERATOR ali = grin_get_adjacent_list_begin(g, al); + size_t acnt = 0; + while (!grin_is_adjacent_list_end(g, ali)) { + GRIN_EDGE e = grin_get_edge_from_adjacent_list_iter(g, ali); + GRIN_VERTEX v1 = grin_get_src_vertex_from_edge(g, e); + GRIN_VERTEX v2 = grin_get_dst_vertex_from_edge(g, e); + GRIN_VERTEX u = grin_get_neighbor_from_adjacent_list_iter(g, ali); + + #ifdef GRIN_ENABLE_ADJACENT_LIST_ARRAY + GRIN_EDGE e1 = grin_get_edge_from_adjacent_list(g, al, acnt); + GRIN_VERTEX e1v1 = grin_get_src_vertex_from_edge(g, e1); + GRIN_VERTEX e1v2 = grin_get_dst_vertex_from_edge(g, e1); + assert(grin_equal_vertex(g, v1, e1v1)); + assert(grin_equal_vertex(g, v2, e1v2)); + grin_destroy_edge(g, e1); + grin_destroy_vertex(g, e1v1); + grin_destroy_vertex(g, e1v2); + #endif + + if (dir == OUT) { + assert(grin_equal_vertex(g, v, v1)); + assert(grin_equal_vertex(g, v2, u)); + } else { + assert(grin_equal_vertex(g, v, v2)); + assert(grin_equal_vertex(g, v1, u)); + } + + grin_destroy_vertex(g, v1); + grin_destroy_vertex(g, v2); + grin_destroy_vertex(g, u); + grin_destroy_edge(g, e); + + acnt++; + grin_get_next_adjacent_list_iter(g, ali); + } + #ifdef GRIN_ENABLE_ADJAECENT_LIST_ARRAY + assert(acnt == grin_get_adjacent_list_size(g, al)); + #endif + grin_destroy_adjacent_list_iter(g, ali); + #ifdef GRIN_WITH_EDGE_PROPERTY + printf("vertex %s adjlist, edgetype: %s, checked num: %zu\n", v_names[__vt][vid], et_names[__etl_i], acnt); + #else + printf("vertex %s adjlist, checked num: %zu\n", v_names[__vt][vid], acnt); + #endif + FOR_ADJ_LIST_END(g, al) + FOR_VERTEX_END(g, vl, v) +FOR_VERTEX_LIST_END(g, vl) + grin_destroy_graph(g); +} + + +void test_topology(int argc, char** argv) { + test_topology_structure(argc, argv); + test_topology_vertex_list(argc, argv); + test_topology_adjacent_list(argc, argv, OUT); + test_topology_adjacent_list(argc, argv, IN); +} + +#if defined(GRIN_ASSUME_ALL_VERTEX_LIST_SORTED) && defined(GRIN_ENABLE_VERTEX_LIST_ARRAY) +void test_index_order(int argc, char** argv) { + printf("+++++++++++++++++++++ Test index order +++++++++++++++++++++\n"); + GRIN_GRAPH g = get_graph(argc, argv, 0); + +FOR_VERTEX_LIST_BEGIN(g, vl) + FOR_VERTEX_BEGIN(g, vl, v) + size_t pos = grin_get_position_of_vertex_from_sorted_list(g, vl, v); + assert(pos == __vcnt); + FOR_VERTEX_END(g, vl, v) + +#ifdef GRIN_ENABLE_GRAPH_PARTITION +{ + GRIN_VERTEX_LIST mvlist = grin_get_vertex_list_by_type_select_master(g, __vt); + size_t mvlist_sz = grin_get_vertex_list_size(g, mvlist); + for (size_t i = 0; i < mvlist_sz; ++i) { + GRIN_VERTEX v = grin_get_vertex_from_list(g, mvlist, i); + size_t pos = grin_get_position_of_vertex_from_sorted_list(g, mvlist, v); + assert(pos == i); + size_t pos1 = grin_get_position_of_vertex_from_sorted_list(g, vl, v); + GRIN_VERTEX v1 = grin_get_vertex_from_list(g, vl, pos1); + assert(grin_equal_vertex(g, v, v1)); + grin_destroy_vertex(g, v1); + grin_destroy_vertex(g, v); + } + grin_destroy_vertex_list(g, mvlist); +} +{ + GRIN_VERTEX_LIST mvlist = grin_get_vertex_list_by_type_select_mirror(g, __vt); + size_t mvlist_sz = grin_get_vertex_list_size(g, mvlist); + for (size_t i = 0; i < mvlist_sz; ++i) { + GRIN_VERTEX v = grin_get_vertex_from_list(g, mvlist, i); + size_t pos = grin_get_position_of_vertex_from_sorted_list(g, mvlist, v); + assert(pos == i); + size_t pos1 = grin_get_position_of_vertex_from_sorted_list(g, vl, v); + GRIN_VERTEX v1 = grin_get_vertex_from_list(g, vl, pos1); + assert(grin_equal_vertex(g, v, v1)); + grin_destroy_vertex(g, v1); + grin_destroy_vertex(g, v); + } + grin_destroy_vertex_list(g, mvlist); +} +#endif +FOR_VERTEX_LIST_END(g, vl) + + grin_destroy_graph(g); +} +#endif + +void test_index_internal_id(int argc, char** argv) { + printf("+++++++++++++++++++++ Test index internal id +++++++++++++++++++++\n"); + GRIN_GRAPH g = get_graph(argc, argv, 0); + +FOR_VERTEX_LIST_BEGIN(g, vl) + long long int min = grin_get_vertex_internal_id_lower_bound_by_type(g, __vt); + long long int max = grin_get_vertex_internal_id_upper_bound_by_type(g, __vt); + FOR_VERTEX_BEGIN(g, vl, v) +#ifdef GRIN_ENABLE_VERTEX_INTERNAL_ID_INDEX + long long int oid = grin_get_vertex_internal_id_by_type(g, __vt, v); + assert(oid >= min && oid < max); + GRIN_VERTEX v1 = grin_get_vertex_by_internal_id_by_type(g, __vt, oid); + assert(grin_equal_vertex(g, v, v1)); + grin_destroy_vertex(g, v1); +#endif + FOR_VERTEX_END(g, vl, v) +FOR_VERTEX_LIST_END(g, vl) + + grin_destroy_graph(g); +} + + +void test_index(int argc, char** argv) { +#if defined(GRIN_ASSUME_ALL_VERTEX_LIST_SORTED) && defined(GRIN_ENABLE_VERTEX_LIST_ARRAY) + test_index_order(argc, argv); +#endif +#ifdef GRIN_ENABLE_VERTEX_INTERNAL_ID_INDEX + test_index_internal_id(argc, argv); +#endif +} + +void test_vertex_property_value(int argc, char** argv) { + GRIN_GRAPH g = get_graph(argc, argv, 0); + GRIN_VERTEX_TYPE vt = grin_get_vertex_type_by_name(g, "person"); + GRIN_VERTEX_PROPERTY vp = grin_get_vertex_property_by_name(g, vt, "age"); + GRIN_VERTEX v = get_one_master_person(g); + struct timeval t1, t2; + gettimeofday(&t1, NULL); + for (int i = 0; i < 1000000; ++i) { + long long int age = grin_get_vertex_property_value_of_int64(g, v, vp); + } + gettimeofday(&t2, NULL); + double elapsedTime = (t2.tv_sec - t1.tv_sec) * 1000.0; + elapsedTime += (t2.tv_usec - t1.tv_usec) / 1000.0; + printf("%f ms.\n", elapsedTime); + grin_destroy_vertex(g, v); + grin_destroy_vertex_property(g, vp); + grin_destroy_vertex_type(g, vt); + grin_destroy_graph(g); +} + +void test_perf(int argc, char** argv) { + test_vertex_property_value(argc, argv); +} + +int main(int argc, char** argv) { + // load modern graph by settting partition number and partition id + unsigned partition_num = 2; + demo_storage_load_modern_graph("modern_graph", partition_num, 0); + demo_storage_load_modern_graph("modern_graph", partition_num, 1); + // execute tests + test_index(argc, argv); + test_property(argc, argv); + test_partition(argc, argv); + test_topology(argc, argv); + test_perf(argc, argv); + return 0; +} From bf3175731dc0531df6cebfd7e28338ee0a4a5e97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Fri, 30 Jun 2023 15:35:47 +0800 Subject: [PATCH 08/48] Add gitignore --- demo_storage/.gitignore | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 demo_storage/.gitignore diff --git a/demo_storage/.gitignore b/demo_storage/.gitignore new file mode 100644 index 0000000..39f7f2a --- /dev/null +++ b/demo_storage/.gitignore @@ -0,0 +1,4 @@ +/build/ +/build-*/ +/src/common/graph.pb.* +.DS_store From 94002a083c8c61aedee00c0d23ea5f05aae995a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Fri, 30 Jun 2023 15:58:00 +0800 Subject: [PATCH 09/48] Update & refine --- demo_storage/storage/loadmoderngraph.h | 2 ++ demo_storage/storage/storage.h | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/demo_storage/storage/loadmoderngraph.h b/demo_storage/storage/loadmoderngraph.h index edffb17..23dad8e 100644 --- a/demo_storage/storage/loadmoderngraph.h +++ b/demo_storage/storage/loadmoderngraph.h @@ -20,6 +20,8 @@ limitations under the License. extern "C" { #endif +// Load a modern graph into the demo storage, +// assigning the graph_name, partition_num and partition_id void demo_storage_load_modern_graph(const char*, unsigned, unsigned); #ifdef __cplusplus diff --git a/demo_storage/storage/storage.h b/demo_storage/storage/storage.h index df5a984..7f49d55 100644 --- a/demo_storage/storage/storage.h +++ b/demo_storage/storage/storage.h @@ -50,12 +50,13 @@ struct Property { class Vertex { public: - // construct vertex with type and id in type + // default constructor Vertex() : type_id_(GRIN_NULL_VERTEX_TYPE), id_(-1) { oid_type_ = GRIN_DATATYPE::Undefined; vdata_type_ = GRIN_DATATYPE::Undefined; } + // construct vertex with type and id in type, without oid explicit Vertex(uint32_t type_id, int64_t id = -1) : type_id_(type_id), id_(id) { oid_type_ = GRIN_DATATYPE::Undefined; @@ -134,6 +135,7 @@ class Vertex { class Edge { public: + // default constructor Edge() : type_id_(GRIN_NULL_EDGE_TYPE), source_(-1), dest_(-1), id_(-1) { edata_type_ = GRIN_DATATYPE::Undefined; } @@ -342,7 +344,7 @@ class Graph { return res; } - // get vertices and edges + // get vertices, edges, and adjacent lists const Vertex& GetVertex(int64_t gid) const { uint32_t type_id = get_type_id_from_gid(gid); int64_t id = get_id_from_gid(gid); @@ -582,6 +584,8 @@ class DemoStorage { graphs_.clear(); } + public: + // method for loading an example graph: modern_graph void LoadModernGraph(const std::string& name, uint32_t partition_num = 1, uint32_t partition_id = 0) noexcept { Graph* graph = load_modern_graph(name, partition_num, partition_id); From 076ad4b0d14f33cc5845bd3c8f9fddc62cb0d9d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Tue, 4 Jul 2023 13:53:23 +0800 Subject: [PATCH 10/48] Implement struture related APIs --- demo_storage/src/topology/structure.cc | 159 +++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 demo_storage/src/topology/structure.cc diff --git a/demo_storage/src/topology/structure.cc b/demo_storage/src/topology/structure.cc new file mode 100644 index 0000000..b547d74 --- /dev/null +++ b/demo_storage/src/topology/structure.cc @@ -0,0 +1,159 @@ +/** Copyright 2020 Alibaba Group Holding Limited. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include + +#include "src/predefine.h" +#include "storage/storage.h" +// GRIN headers +#include "topology/structure.h" + +GRIN_GRAPH grin_get_graph_from_storage(const char* uri) { + if (uri == NULL) + return GRIN_NULL_GRAPH; + using DEMO_STORAGE_NAMESPACE::demo_storage; + std::string path(uri); + std::string prefix = "demo_storage://"; + if (path.find(prefix) == 0) { + std::string name = path.substr(prefix.size()); + return demo_storage.GetGraph(name, 1, 0); + } else { + return GRIN_NULL_GRAPH; + } +} + +void grin_destroy_graph(GRIN_GRAPH g) { return; } + +// Graph +#if defined(GRIN_ASSUME_HAS_DIRECTED_GRAPH) && \ + defined(GRIN_ASSUME_HAS_UNDIRECTED_GRAPH) +bool grin_is_directed(GRIN_GRAPH g) { + auto _g = static_cast(g); + return _g->IsDirected(); +} +#endif + +#ifdef GRIN_ASSUME_HAS_MULTI_EDGE_GRAPH +bool grin_is_multigraph(GRIN_GRAPH) { return true; } +#endif + +#if !defined(GRIN_WITH_VERTEX_PROPERTY) +size_t grin_get_vertex_num(GRIN_GRAPH); +#endif + +#if !defined(GRIN_WITH_EDGE_PROPERTY) +size_t grin_get_edge_num(GRIN_GRAPH); +#endif + +// Vertex +void grin_destroy_vertex(GRIN_GRAPH g, GRIN_VERTEX v) { return; } + +bool grin_equal_vertex(GRIN_GRAPH g, GRIN_VERTEX v1, GRIN_VERTEX v2) { + return v1 == v2; +} + +// Data +#ifdef GRIN_WITH_VERTEX_DATA +GRIN_DATATYPE grin_get_vertex_data_datatype(GRIN_GRAPH g, GRIN_VERTEX v) { + auto _g = static_cast(g); + auto& _v = _g->GetVertex(v); + return _v.GetVDataType(); +} + +const void* grin_get_vertex_data_value(GRIN_GRAPH g, GRIN_VERTEX v) { + auto _g = static_cast(g); + auto& _v = _g->GetVertex(v); + auto type = _v.GetVDataType(); + switch (type) { + case GRIN_DATATYPE::Int32: + return &_v.GetVData(); + case GRIN_DATATYPE::UInt32: + return &_v.GetVData(); + case GRIN_DATATYPE::Int64: + return &_v.GetVData(); + case GRIN_DATATYPE::UInt64: + return &_v.GetVData(); + case GRIN_DATATYPE::Float: + return &_v.GetVData(); + case GRIN_DATATYPE::Double: + return &_v.GetVData(); + case GRIN_DATATYPE::String: + return _v.GetVData().c_str(); + case GRIN_DATATYPE::Date32: + return &_v.GetVData(); + case GRIN_DATATYPE::Time32: + return &_v.GetVData(); + case GRIN_DATATYPE::Timestamp64: + return &_v.GetVData(); + default: + return GRIN_NULL_VERTEX_DATA; + } + return GRIN_NULL_VERTEX_DATA; +} +#endif + +// Edge +void grin_destroy_edge(GRIN_GRAPH g, GRIN_EDGE e) { return; } + +GRIN_VERTEX grin_get_src_vertex_from_edge(GRIN_GRAPH g, GRIN_EDGE e) { + auto _g = static_cast(g); + auto& _e = _g->GetEdge(e); + return _e.GetSource(); +} + +GRIN_VERTEX grin_get_dst_vertex_from_edge(GRIN_GRAPH g, GRIN_EDGE e) { + auto _g = static_cast(g); + auto& _e = _g->GetEdge(e); + return _e.GetDest(); +} + +#ifdef GRIN_WITH_EDGE_DATA +GRIN_DATATYPE grin_get_edge_data_datatype(GRIN_GRAPH g, GRIN_EDGE e) { + auto _g = static_cast(g); + auto& _e = _g->GetEdge(e); + return _e.GetEDataType(); +} + +const void* grin_get_edge_data_value(GRIN_GRAPH g, GRIN_EDGE e) { + auto _g = static_cast(g); + auto& _e = _g->GetEdge(e); + auto type = _e.GetEDataType(); + switch (type) { + case GRIN_DATATYPE::Int32: + return &_e.GetEData(); + case GRIN_DATATYPE::UInt32: + return &_e.GetEData(); + case GRIN_DATATYPE::Int64: + return &_e.GetEData(); + case GRIN_DATATYPE::UInt64: + return &_e.GetEData(); + case GRIN_DATATYPE::Float: + return &_e.GetEData(); + case GRIN_DATATYPE::Double: + return &_e.GetEData(); + case GRIN_DATATYPE::String: + return _e.GetEData().c_str(); + case GRIN_DATATYPE::Date32: + return &_e.GetEData(); + case GRIN_DATATYPE::Time32: + return &_e.GetEData(); + case GRIN_DATATYPE::Timestamp64: + return &_e.GetEData(); + default: + return GRIN_NULL_EDGE_DATA; + } + return GRIN_NULL_EDGE_DATA; +} +#endif From d60317f0067150330bbd2689c400685ed5151d11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Tue, 4 Jul 2023 13:53:47 +0800 Subject: [PATCH 11/48] Implement partition related APIs --- demo_storage/src/partition/partition.cc | 137 ++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 demo_storage/src/partition/partition.cc diff --git a/demo_storage/src/partition/partition.cc b/demo_storage/src/partition/partition.cc new file mode 100644 index 0000000..a954e8b --- /dev/null +++ b/demo_storage/src/partition/partition.cc @@ -0,0 +1,137 @@ +/** Copyright 2020 Alibaba Group Holding Limited. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include +#include + +#include "src/predefine.h" +#include "storage/storage.h" +// GRIN headers +#include "partition/partition.h" + +#ifdef GRIN_ENABLE_GRAPH_PARTITION +GRIN_PARTITIONED_GRAPH grin_get_partitioned_graph_from_storage( + const char* uri) { + if (uri == NULL) { + return GRIN_NULL_GRAPH; + } + std::string path(uri); + auto pos0 = path.find("demo_storage://"); + auto pos1 = path.find("?partition_num="); + if (pos0 == 0 && pos1 != std::string::npos) { + std::string name = path.substr(pos0 + 15, pos1 - pos0 - 15); + std::string partition_num = path.substr(pos1 + 15); + return new GRIN_PARTITIONED_GRAPH_T(name, std::stoi(partition_num)); + } else { + return GRIN_NULL_GRAPH; + } +} + +void grin_destroy_partitioned_graph(GRIN_PARTITIONED_GRAPH pg) { + auto _pg = static_cast(pg); + delete _pg; +} + +size_t grin_get_total_partitions_number(GRIN_PARTITIONED_GRAPH pg) { + auto _pg = static_cast(pg); + return _pg->partition_num; +} + +GRIN_PARTITION_LIST grin_get_local_partition_list(GRIN_PARTITIONED_GRAPH pg) { + auto _pg = static_cast(pg); + auto pl = new GRIN_PARTITION_LIST_T(); + using DEMO_STORAGE_NAMESPACE::demo_storage; + for (auto p = 0; p < _pg->partition_num; ++p) { + auto graph = demo_storage.GetGraph(_pg->name, _pg->partition_num, p); + if (graph != NULL) + pl->push_back(p); + } + return pl; +} + +void grin_destroy_partition_list(GRIN_PARTITIONED_GRAPH pg, + GRIN_PARTITION_LIST pl) { + auto _pl = static_cast(pl); + delete _pl; +} + +GRIN_PARTITION_LIST grin_create_partition_list(GRIN_PARTITIONED_GRAPH pg) { + return new GRIN_PARTITION_LIST_T(); +} + +bool grin_insert_partition_to_list(GRIN_PARTITIONED_GRAPH pg, + GRIN_PARTITION_LIST pl, GRIN_PARTITION p) { + auto _pl = static_cast(pl); + _pl->push_back(p); + return true; +} + +size_t grin_get_partition_list_size(GRIN_PARTITIONED_GRAPH pg, + GRIN_PARTITION_LIST pl) { + auto _pl = static_cast(pl); + return _pl->size(); +} + +GRIN_PARTITION grin_get_partition_from_list(GRIN_PARTITIONED_GRAPH pg, + GRIN_PARTITION_LIST pl, + size_t idx) { + auto _pl = static_cast(pl); + return (*_pl)[idx]; +} + +bool grin_equal_partition(GRIN_PARTITIONED_GRAPH pg, GRIN_PARTITION p1, + GRIN_PARTITION p2) { + return p1 == p2; +} + +void grin_destroy_partition(GRIN_PARTITIONED_GRAPH pg, GRIN_PARTITION p) { + return; +} + +const void* grin_get_partition_info(GRIN_PARTITIONED_GRAPH pg, + GRIN_PARTITION p) { + std::stringstream ss; + auto _pg = static_cast(pg); + ss << "graph name: " << _pg->name; + ss << "; partition num: " << _pg->partition_num; + ss << "; partition id: " << p; + int len = ss.str().length() + 1; + char* out = new char[len]; + snprintf(out, len, "%s", ss.str().c_str()); + return out; +} + +GRIN_GRAPH grin_get_local_graph_by_partition(GRIN_PARTITIONED_GRAPH pg, + GRIN_PARTITION p) { + auto _pg = static_cast(pg); + using DEMO_STORAGE_NAMESPACE::demo_storage; + auto graph = demo_storage.GetGraph(_pg->name, _pg->partition_num, p); + if (graph == NULL || graph->GetPartitionId() != p) + return GRIN_NULL_GRAPH; + return graph; +} +#endif + +#ifdef GRIN_TRAIT_NATURAL_ID_FOR_PARTITION +GRIN_PARTITION grin_get_partition_by_id(GRIN_PARTITIONED_GRAPH pg, + GRIN_PARTITION_ID id) { + return id; +} + +GRIN_PARTITION_ID grin_get_partition_id(GRIN_PARTITIONED_GRAPH pg, + GRIN_PARTITION p) { + return p; +} +#endif From 3e532110ecc4fd3befec6eca6a5ae80865fd07f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Tue, 4 Jul 2023 17:07:08 +0800 Subject: [PATCH 12/48] Add dir for demo_storage in /storage/ --- storage/demo_storage/predefine.h | 272 +++++++++++++++++++++++++++++++ 1 file changed, 272 insertions(+) create mode 100644 storage/demo_storage/predefine.h diff --git a/storage/demo_storage/predefine.h b/storage/demo_storage/predefine.h new file mode 100644 index 0000000..14616b8 --- /dev/null +++ b/storage/demo_storage/predefine.h @@ -0,0 +1,272 @@ +/** Copyright 2020 Alibaba Group Holding Limited. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/** + * @file predefine.h + * @brief This template file consists of four parts: + * 1. The predefined enumerate types of GRIN, which should NOT be modified. + * 2. The supported macros which should be specified by storage implementors + * based on storage features. + * 3. The typedefs of the enabled handles. This should be specified by storage. + * 4. The corresponding null values of the enabled handles. This should be + * specified by storage. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +/* 1. Predefined enumerate types of GRIN */ +/// Enumerates the directions of edges with respect to a certain vertex +typedef enum { + IN = 0, ///< incoming + OUT = 1, ///< outgoing + BOTH = 2, ///< incoming & outgoing +} GRIN_DIRECTION; + +/// Enumerates the datatype supported in the storage +typedef enum { + Undefined = 0, ///< other unknown types + Int32 = 1, ///< int + UInt32 = 2, ///< unsigned int + Int64 = 3, ///< long int + UInt64 = 4, ///< unsigned long int + Float = 5, ///< float + Double = 6, ///< double + String = 7, ///< string + Date32 = 8, ///< date + Time32 = 9, ///< Time32 + Timestamp64 = 10, ///< Timestamp +} GRIN_DATATYPE; + +/// Enumerates the error codes of grin +typedef enum { + NO_ERROR = 0, ///< success + UNKNOWN_ERROR = 1, ///< unknown error + INVALID_VALUE = 2, ///< invalid value + UNKNOWN_DATATYPE = 3, ///< unknown datatype +} GRIN_ERROR_CODE; + +/* 2. Define supported macros based on storage features */ +// Topology +#define GRIN_ASSUME_HAS_DIRECTED_GRAPH +#define GRIN_ASSUME_HAS_UNDIRECTED_GRAPH +#define GRIN_ASSUME_HAS_MULTI_EDGE_GRAPH +#define GRIN_WITH_VERTEX_DATA +#define GRIN_WITH_EDGE_DATA +#define GRIN_ENABLE_VERTEX_LIST +#define GRIN_ENABLE_VERTEX_LIST_ARRAY +#define GRIN_ENABLE_VERTEX_LIST_ITERATOR +#define GRIN_ENABLE_EDGE_LIST +#define GRIN_ENABLE_EDGE_LIST_ARRAY +#define GRIN_ENABLE_EDGE_LIST_ITERATOR +#define GRIN_ENABLE_ADJACENT_LIST +#define GRIN_ENABLE_ADJACENT_LIST_ARRAY +#define GRIN_ENABLE_ADJACENT_LIST_ITERATOR +// Partition +#define GRIN_ENABLE_GRAPH_PARTITION +#define GRIN_TRAIT_NATURAL_ID_FOR_PARTITION +#define GRIN_ENABLE_VERTEX_REF +#define GRIN_TRAIT_FAST_VERTEX_REF +#define GRIN_ENABLE_EDGE_REF +#define GRIN_ASSUME_ALL_REPLICATE_PARTITION +// #define GRIN_ASSUME_EDGE_CUT_PARTITION +// #define GRIN_ASSUME_EDGE_CUT_FOLLOW_SRC_PARTITION +// #define GRIN_ASSUME_EDGE_CUT_FOLLOW_DST_PARTITION +// #define GRIN_ASSUME_VERTEX_CUT_PARTITION +// #define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_VERTEX_DATA +#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_VERTEX_DATA +// #define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_EDGE_DATA +#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_EDGE_DATA +#define GRIN_TRAIT_MASTER_VERTEX_MIRROR_PARTITION_LIST +#define GRIN_TRAIT_MIRROR_VERTEX_MIRROR_PARTITION_LIST +#define GRIN_TRAIT_MASTER_EDGE_MIRROR_PARTITION_LIST +#define GRIN_TRAIT_MIRROR_EDGE_MIRROR_PARTITION_LIST +#define GRIN_TRAIT_SELECT_MASTER_FOR_VERTEX_LIST +#define GRIN_TRAIT_SELECT_PARTITION_FOR_VERTEX_LIST +#define GRIN_TRAIT_SELECT_MASTER_FOR_EDGE_LIST +#define GRIN_TRAIT_SELECT_PARTITION_FOR_EDGE_LIST +#define GRIN_TRAIT_SELECT_MASTER_NEIGHBOR_FOR_ADJACENT_LIST +#define GRIN_TRAIT_SELECT_NEIGHBOR_PARTITION_FOR_ADJACENT_LIST +// Property +#define GRIN_ENABLE_ROW +#define GRIN_TRAIT_CONST_VALUE_PTR +#define GRIN_WITH_VERTEX_PROPERTY +#define GRIN_WITH_VERTEX_PROPERTY_NAME +#define GRIN_WITH_VERTEX_TYPE_NAME +#define GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_TYPE +#define GRIN_ENABLE_VERTEX_PRIMARY_KEYS +#define GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_PROPERTY +#define GRIN_WITH_EDGE_PROPERTY +#define GRIN_WITH_EDGE_PROPERTY_NAME +#define GRIN_WITH_EDGE_TYPE_NAME +#define GRIN_TRAIT_NATURAL_ID_FOR_EDGE_TYPE +#define GRIN_ENABLE_EDGE_PRIMARY_KEYS +#define GRIN_TRAIT_NATURAL_ID_FOR_EDGE_PROPERTY +#define GRIN_TRAIT_SPECIFIC_VEV_RELATION +// #define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_VERTEX_PROPERTY +#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_VERTEX_PROPERTY +// #define GRIN_ASSUME_SPLIT_MASTER_MIRROR_PARTITION_FOR_VERTEX_PROPERTY +// #define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_EDGE_PROPERTY +#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_EDGE_PROPERTY +// #define GRIN_ASSUME_SPLIT_MASTER_MIRROR_PARTITION_FOR_EDGE_PROPERTY +// Index +// #define GRIN_WITH_VERTEX_LABEL +// #define GRIN_WITH_EDGE_LABEL +#define GRIN_ASSUME_ALL_VERTEX_LIST_SORTED +#define GRIN_ENABLE_VERTEX_INTERNAL_ID_INDEX +#define GRIN_ENABLE_VERTEX_PK_INDEX +#define GRIN_ENABLE_EDGE_PK_INDEX + +/* 3. Define the handles using typedef */ +typedef void *GRIN_GRAPH; +typedef long long int GRIN_VERTEX; +typedef long long int GRIN_EDGE; + +#ifdef GRIN_WITH_VERTEX_DATA +typedef void* GRIN_VERTEX_DATA; +#endif + +#ifdef GRIN_ENABLE_VERTEX_LIST +typedef void* GRIN_VERTEX_LIST; +#endif + +#ifdef GRIN_ENABLE_VERTEX_LIST_ITERATOR +typedef void* GRIN_VERTEX_LIST_ITERATOR; +#endif + +#ifdef GRIN_ENABLE_ADJACENT_LIST +typedef void* GRIN_ADJACENT_LIST; +#endif + +#ifdef GRIN_ENABLE_ADJACENT_LIST_ITERATOR +typedef void* GRIN_ADJACENT_LIST_ITERATOR; +#endif + +#ifdef GRIN_WITH_EDGE_DATA +typedef void* GRIN_EDGE_DATA; +#endif + +#ifdef GRIN_ENABLE_EDGE_LIST +typedef void* GRIN_EDGE_LIST; +#endif + +#ifdef GRIN_ENABLE_EDGE_LIST_ITERATOR +typedef void* GRIN_EDGE_LIST_ITERATOR; +#endif + +#ifdef GRIN_ENABLE_GRAPH_PARTITION +typedef void* GRIN_PARTITIONED_GRAPH; +typedef unsigned GRIN_PARTITION; +typedef void* GRIN_PARTITION_LIST; +#endif + +#ifdef GRIN_TRAIT_NATURAL_ID_FOR_PARTITION +typedef unsigned GRIN_PARTITION_ID; +#endif + +#ifdef GRIN_ENABLE_VERTEX_REF +typedef long long int GRIN_VERTEX_REF; +#endif + +#ifdef GRIN_ENABLE_EDGE_REF +typedef long long int GRIN_EDGE_REF; +#endif + +#ifdef GRIN_WITH_VERTEX_PROPERTY +typedef unsigned GRIN_VERTEX_TYPE; +typedef void* GRIN_VERTEX_TYPE_LIST; +typedef unsigned GRIN_VERTEX_PROPERTY; +typedef void* GRIN_VERTEX_PROPERTY_LIST; +#endif + +#ifdef GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_TYPE +typedef unsigned GRIN_VERTEX_TYPE_ID; +#endif + +#ifdef GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_PROPERTY +typedef unsigned GRIN_VERTEX_PROPERTY_ID; +#endif + +#ifdef GRIN_WITH_EDGE_PROPERTY +typedef unsigned GRIN_EDGE_TYPE; +typedef void* GRIN_EDGE_TYPE_LIST; +typedef unsigned GRIN_VEV_TYPE; +typedef void* GRIN_VEV_TYPE_LIST; +typedef unsigned GRIN_EDGE_PROPERTY; +typedef void* GRIN_EDGE_PROPERTY_LIST; +#endif + +#ifdef GRIN_TRAIT_NATURAL_ID_FOR_EDGE_TYPE +typedef unsigned GRIN_EDGE_TYPE_ID; +#endif + +#ifdef GRIN_TRAIT_NATURAL_ID_FOR_EDGE_PROPERTY +typedef unsigned GRIN_EDGE_PROPERTY_ID; +#endif + +#ifdef GRIN_ENABLE_ROW +typedef void* GRIN_ROW; +#endif + +#if defined(GRIN_WITH_VERTEX_LABEL) || defined(GRIN_WITH_EDGE_LABEL) +typedef void* GRIN_LABEL; +typedef void* GRIN_LABEL_LIST; +#endif + +/* 4. Define invalid values for returns of handles */ +#define GRIN_NULL_GRAPH NULL +#define GRIN_NULL_VERTEX -1 +#define GRIN_NULL_EDGE -1 +#define GRIN_NULL_VERTEX_DATA NULL +#define GRIN_NULL_VERTEX_LIST NULL +#define GRIN_NULL_VERTEX_LIST_ITERATOR NULL +#define GRIN_NULL_ADJACENT_LIST NULL +#define GRIN_NULL_ADJACENT_LIST_ITERATOR NULL +#define GRIN_NULL_EDGE_DATA NULL +#define GRIN_NULL_EDGE_LIST NULL +#define GRIN_NULL_EDGE_LIST_ITERATOR NULL +#define GRIN_NULL_PARTITIONED_GRAPH NULL +#define GRIN_NULL_PARTITION (unsigned)~0 +#define GRIN_NULL_PARTITION_LIST NULL +#define GRIN_NULL_PARTITION_ID (unsigned)~0 +#define GRIN_NULL_VERTEX_REF -1 +#define GRIN_NULL_EDGE_REF -1 +#define GRIN_NULL_VERTEX_TYPE (unsigned)~0 +#define GRIN_NULL_VERTEX_TYPE_LIST NULL +#define GRIN_NULL_VERTEX_PROPERTY (unsigned)~0 +#define GRIN_NULL_VERTEX_PROPERTY_LIST NULL +#define GRIN_NULL_VERTEX_TYPE_ID (unsigned)~0 +#define GRIN_NULL_VERTEX_PROPERTY_ID (unsigned)~0 +#define GRIN_NULL_EDGE_TYPE (unsigned)~0 +#define GRIN_NULL_EDGE_TYPE_LIST NULL +#define GRIN_NULL_VEV_TYPE (unsigned)~0 +#define GRIN_NULL_VEV_TYPE_LIST NULL +#define GRIN_NULL_EDGE_PROPERTY (unsigned)~0 +#define GRIN_NULL_EDGE_PROPERTY_LIST NULL +#define GRIN_NULL_EDGE_TYPE_ID (unsigned)~0 +#define GRIN_NULL_EDGE_PROPERTY_ID (unsigned)~0 +#define GRIN_NULL_ROW NULL +#define GRIN_NULL_LABEL NULL +#define GRIN_NULL_LABEL_LIST NULL +#define GRIN_NULL_SIZE (unsigned)~0 +#define GRIN_NULL_NAME NULL + +#ifdef __cplusplus +} +#endif From e315288995ca34b6916cc3741160feae8eb58b6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Tue, 4 Jul 2023 17:11:02 +0800 Subject: [PATCH 13/48] Add codegen for demo_storage --- rust/grin_demo_storage.h | 43 +++++++++++++++++++ rust/grin_demo_storage.rs | 89 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 rust/grin_demo_storage.h create mode 100644 rust/grin_demo_storage.rs diff --git a/rust/grin_demo_storage.h b/rust/grin_demo_storage.h new file mode 100644 index 0000000..f6b6c9a --- /dev/null +++ b/rust/grin_demo_storage.h @@ -0,0 +1,43 @@ +#define GRIN_FEATURES_ENABLE_DEMOSTORAGE +#define GRIN_RUST_CODEGEN + +#include "storage/demo_storage/predefine.h" + +#ifdef GRIN_RUST_CODEGEN +/// GRIN_FEATURES_ENABLE_DEMOSTORAGE +/// RUST_KEEP pub const GRIN_NULL_DATATYPE: GrinDatatype = GRIN_DATATYPE_UNDEFINED; +/// RUST_KEEP pub const GRIN_NULL_GRAPH: GrinGraph = std::ptr::null_mut(); +/// RUST_KEEP pub const GRIN_NULL_VERTEX: GrinVertex = -1; +/// RUST_KEEP pub const GRIN_NULL_EDGE: GrinEdge = -1; +/// RUST_KEEP pub const GRIN_NULL_VERTEX_DATA: GrinVertexData = std::ptr::null_mut(); +/// RUST_KEEP pub const GRIN_NULL_VERTEX_LIST: GrinVertexList = std::ptr::null_mut(); +/// RUST_KEEP pub const GRIN_NULL_VERTEX_LIST_ITERATOR: GrinVertexListIterator = std::ptr::null_mut(); +/// RUST_KEEP pub const GRIN_NULL_ADJACENT_LIST: GrinAdjacentList = std::ptr::null_mut(); +/// RUST_KEEP pub const GRIN_NULL_ADJACENT_LIST_ITERATOR: GrinAdjacentListIterator = std::ptr::null_mut(); +/// RUST_KEEP pub const GRIN_NULL_EDGE_DATA: GrinEdgeData = std::ptr::null_mut(); +/// RUST_KEEP pub const GRIN_NULL_EDGE_LIST: GrinEdgeList = std::ptr::null_mut(); +/// RUST_KEEP pub const GRIN_NULL_EDGE_LIST_ITERATOR: GrinEdgeListIterator = std::ptr::null_mut(); +/// RUST_KEEP pub const GRIN_NULL_PARTITIONED_GRAPH: GrinPartitionedGraph = std::ptr::null_mut(); +/// RUST_KEEP pub const GRIN_NULL_PARTITION: GrinPartition = u32::MAX; +/// RUST_KEEP pub const GRIN_NULL_PARTITION_LIST: GrinPartitionList = std::ptr::null_mut(); +/// RUST_KEEP pub const GRIN_NULL_PARTITION_ID: GrinPartitionId = u32::MAX; +/// RUST_KEEP pub const GRIN_NULL_VERTEX_REF: GrinVertexRef = -1; +/// RUST_KEEP pub const GRIN_NULL_EDGE_REF: GrinEdgeRef = -1; +/// RUST_KEEP pub const GRIN_NULL_VERTEX_TYPE: GrinVertexType = u32::MAX; +/// RUST_KEEP pub const GRIN_NULL_VERTEX_TYPE_LIST: GrinVertexTypeList = std::ptr::null_mut(); +/// RUST_KEEP pub const GRIN_NULL_VERTEX_PROPERTY: GrinVertexProperty = u32::MAX; +/// RUST_KEEP pub const GRIN_NULL_VERTEX_PROPERTY_LIST: GrinVertexPropertyList = std::ptr::null_mut(); +/// RUST_KEEP pub const GRIN_NULL_VERTEX_TYPE_ID: GrinVertexTypeId = u32::MAX; +/// RUST_KEEP pub const GRIN_NULL_VERTEX_PROPERTY_ID: GrinVertexPropertyId = u32::MAX; +/// RUST_KEEP pub const GRIN_NULL_EDGE_TYPE: GrinEdgeType = u32::MAX; +/// RUST_KEEP pub const GRIN_NULL_EDGE_TYPE_LIST: GrinEdgeTypeList = std::ptr::null_mut(); +/// RUST_KEEP pub const GRIN_NULL_VEV_TYPE: GrinVevType = u32::MAX; +/// RUST_KEEP pub const GRIN_NULL_VEV_TYPE_LIST: GrinVevTypeList = std::ptr::null_mut(); +/// RUST_KEEP pub const GRIN_NULL_EDGE_PROPERTY: GrinEdgeProperty = u32::MAX; +/// RUST_KEEP pub const GRIN_NULL_EDGE_PROPERTY_LIST: GrinEdgePropertyList = std::ptr::null_mut(); +/// RUST_KEEP pub const GRIN_NULL_EDGE_TYPE_ID: GrinEdgeTypeId = u32::MAX; +/// RUST_KEEP pub const GRIN_NULL_EDGE_PROPERTY_ID: GrinEdgePropertyId = u32::MAX; +/// RUST_KEEP pub const GRIN_NULL_ROW: GrinRow = std::ptr::null_mut(); +/// RUST_KEEP pub const GRIN_NULL_SIZE: u32 = u32::MAX; +int __rust_keep_grin_null; +#endif diff --git a/rust/grin_demo_storage.rs b/rust/grin_demo_storage.rs new file mode 100644 index 0000000..236bad9 --- /dev/null +++ b/rust/grin_demo_storage.rs @@ -0,0 +1,89 @@ +/* automatically generated by rust-bindgen 0.66.1 */ + +pub const __bool_true_false_are_defined: u32 = 1; +pub const true_: u32 = 1; +pub const false_: u32 = 0; +pub const GRIN_NULL_VERTEX: i32 = -1; +pub const GRIN_NULL_EDGE: i32 = -1; +pub const GRIN_NULL_VERTEX_REF: i32 = -1; +pub const GRIN_NULL_EDGE_REF: i32 = -1; +pub type wchar_t = ::std::os::raw::c_int; +pub type max_align_t = u128; +#[doc = "< incoming"] +pub const GRIN_DIRECTION_IN: GRIN_DIRECTION = 0; +#[doc = "< outgoing"] +pub const GRIN_DIRECTION_OUT: GRIN_DIRECTION = 1; +#[doc = "< incoming & outgoing"] +pub const GRIN_DIRECTION_BOTH: GRIN_DIRECTION = 2; +#[doc = " Enumerates the directions of edges with respect to a certain vertex"] +pub type GRIN_DIRECTION = ::std::os::raw::c_uint; +#[doc = "< other unknown types"] +pub const GRIN_DATATYPE_Undefined: GRIN_DATATYPE = 0; +#[doc = "< int"] +pub const GRIN_DATATYPE_Int32: GRIN_DATATYPE = 1; +#[doc = "< unsigned int"] +pub const GRIN_DATATYPE_UInt32: GRIN_DATATYPE = 2; +#[doc = "< long int"] +pub const GRIN_DATATYPE_Int64: GRIN_DATATYPE = 3; +#[doc = "< unsigned long int"] +pub const GRIN_DATATYPE_UInt64: GRIN_DATATYPE = 4; +#[doc = "< float"] +pub const GRIN_DATATYPE_Float: GRIN_DATATYPE = 5; +#[doc = "< double"] +pub const GRIN_DATATYPE_Double: GRIN_DATATYPE = 6; +#[doc = "< string"] +pub const GRIN_DATATYPE_String: GRIN_DATATYPE = 7; +#[doc = "< date"] +pub const GRIN_DATATYPE_Date32: GRIN_DATATYPE = 8; +#[doc = "< Time32"] +pub const GRIN_DATATYPE_Time32: GRIN_DATATYPE = 9; +#[doc = "< Timestamp"] +pub const GRIN_DATATYPE_Timestamp64: GRIN_DATATYPE = 10; +#[doc = " Enumerates the datatype supported in the storage"] +pub type GRIN_DATATYPE = ::std::os::raw::c_uint; +#[doc = "< success"] +pub const GRIN_ERROR_CODE_NO_ERROR: GRIN_ERROR_CODE = 0; +#[doc = "< unknown error"] +pub const GRIN_ERROR_CODE_UNKNOWN_ERROR: GRIN_ERROR_CODE = 1; +#[doc = "< invalid value"] +pub const GRIN_ERROR_CODE_INVALID_VALUE: GRIN_ERROR_CODE = 2; +#[doc = "< unknown datatype"] +pub const GRIN_ERROR_CODE_UNKNOWN_DATATYPE: GRIN_ERROR_CODE = 3; +#[doc = " Enumerates the error codes of grin"] +pub type GRIN_ERROR_CODE = ::std::os::raw::c_uint; +pub type GRIN_GRAPH = *mut ::std::os::raw::c_void; +pub type GRIN_VERTEX = ::std::os::raw::c_longlong; +pub type GRIN_EDGE = ::std::os::raw::c_longlong; +pub type GRIN_VERTEX_DATA = *mut ::std::os::raw::c_void; +pub type GRIN_VERTEX_LIST = *mut ::std::os::raw::c_void; +pub type GRIN_VERTEX_LIST_ITERATOR = *mut ::std::os::raw::c_void; +pub type GRIN_ADJACENT_LIST = *mut ::std::os::raw::c_void; +pub type GRIN_ADJACENT_LIST_ITERATOR = *mut ::std::os::raw::c_void; +pub type GRIN_EDGE_DATA = *mut ::std::os::raw::c_void; +pub type GRIN_EDGE_LIST = *mut ::std::os::raw::c_void; +pub type GRIN_EDGE_LIST_ITERATOR = *mut ::std::os::raw::c_void; +pub type GRIN_PARTITIONED_GRAPH = *mut ::std::os::raw::c_void; +pub type GRIN_PARTITION = ::std::os::raw::c_uint; +pub type GRIN_PARTITION_LIST = *mut ::std::os::raw::c_void; +pub type GRIN_PARTITION_ID = ::std::os::raw::c_uint; +pub type GRIN_VERTEX_REF = ::std::os::raw::c_longlong; +pub type GRIN_EDGE_REF = ::std::os::raw::c_longlong; +pub type GRIN_VERTEX_TYPE = ::std::os::raw::c_uint; +pub type GRIN_VERTEX_TYPE_LIST = *mut ::std::os::raw::c_void; +pub type GRIN_VERTEX_PROPERTY = ::std::os::raw::c_uint; +pub type GRIN_VERTEX_PROPERTY_LIST = *mut ::std::os::raw::c_void; +pub type GRIN_VERTEX_TYPE_ID = ::std::os::raw::c_uint; +pub type GRIN_VERTEX_PROPERTY_ID = ::std::os::raw::c_uint; +pub type GRIN_EDGE_TYPE = ::std::os::raw::c_uint; +pub type GRIN_EDGE_TYPE_LIST = *mut ::std::os::raw::c_void; +pub type GRIN_VEV_TYPE = ::std::os::raw::c_uint; +pub type GRIN_VEV_TYPE_LIST = *mut ::std::os::raw::c_void; +pub type GRIN_EDGE_PROPERTY = ::std::os::raw::c_uint; +pub type GRIN_EDGE_PROPERTY_LIST = *mut ::std::os::raw::c_void; +pub type GRIN_EDGE_TYPE_ID = ::std::os::raw::c_uint; +pub type GRIN_EDGE_PROPERTY_ID = ::std::os::raw::c_uint; +pub type GRIN_ROW = *mut ::std::os::raw::c_void; +extern "C" { + #[doc = " GRIN_FEATURES_ENABLE_DEMOSTORAGE\n RUST_KEEP pub const GRIN_NULL_DATATYPE: GrinDatatype = GRIN_DATATYPE_UNDEFINED;\n RUST_KEEP pub const GRIN_NULL_GRAPH: GrinGraph = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_VERTEX: GrinVertex = -1;\n RUST_KEEP pub const GRIN_NULL_EDGE: GrinEdge = -1;\n RUST_KEEP pub const GRIN_NULL_VERTEX_DATA: GrinVertexData = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_VERTEX_LIST: GrinVertexList = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_VERTEX_LIST_ITERATOR: GrinVertexListIterator = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_ADJACENT_LIST: GrinAdjacentList = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_ADJACENT_LIST_ITERATOR: GrinAdjacentListIterator = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_EDGE_DATA: GrinEdgeData = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_EDGE_LIST: GrinEdgeList = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_EDGE_LIST_ITERATOR: GrinEdgeListIterator = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_PARTITIONED_GRAPH: GrinPartitionedGraph = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_PARTITION: GrinPartition = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_PARTITION_LIST: GrinPartitionList = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_PARTITION_ID: GrinPartitionId = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_VERTEX_REF: GrinVertexRef = -1;\n RUST_KEEP pub const GRIN_NULL_EDGE_REF: GrinEdgeRef = -1;\n RUST_KEEP pub const GRIN_NULL_VERTEX_TYPE: GrinVertexType = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_VERTEX_TYPE_LIST: GrinVertexTypeList = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_VERTEX_PROPERTY: GrinVertexProperty = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_VERTEX_PROPERTY_LIST: GrinVertexPropertyList = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_VERTEX_TYPE_ID: GrinVertexTypeId = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_VERTEX_PROPERTY_ID: GrinVertexPropertyId = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_EDGE_TYPE: GrinEdgeType = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_EDGE_TYPE_LIST: GrinEdgeTypeList = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_VEV_TYPE: GrinVevType = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_VEV_TYPE_LIST: GrinVevTypeList = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_EDGE_PROPERTY: GrinEdgeProperty = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_EDGE_PROPERTY_LIST: GrinEdgePropertyList = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_EDGE_TYPE_ID: GrinEdgeTypeId = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_EDGE_PROPERTY_ID: GrinEdgePropertyId = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_ROW: GrinRow = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_SIZE: u32 = u32::MAX;"] + pub static mut __rust_keep_grin_null: ::std::os::raw::c_int; +} From bdaa6da5c4e6e5b9aea9e44d7e8c8732313199c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Mon, 10 Jul 2023 11:33:27 +0800 Subject: [PATCH 14/48] Implement partition/reference.h & topology.h --- demo_storage/src/partition/reference.cc | 191 ++++++++++++++++++++++++ demo_storage/src/partition/topology.cc | 154 +++++++++++++++++++ 2 files changed, 345 insertions(+) create mode 100644 demo_storage/src/partition/reference.cc create mode 100644 demo_storage/src/partition/topology.cc diff --git a/demo_storage/src/partition/reference.cc b/demo_storage/src/partition/reference.cc new file mode 100644 index 0000000..ddf92ba --- /dev/null +++ b/demo_storage/src/partition/reference.cc @@ -0,0 +1,191 @@ +/** Copyright 2020 Alibaba Group Holding Limited. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include + +#include "src/predefine.h" +// GRIN headers +#include "partition/reference.h" + +#ifdef GRIN_ENABLE_VERTEX_REF +GRIN_VERTEX_REF grin_get_vertex_ref_by_vertex(GRIN_GRAPH g, GRIN_VERTEX v) { + return v; +} + +void grin_destroy_vertex_ref(GRIN_GRAPH g, GRIN_VERTEX_REF vr) { return; } + +GRIN_VERTEX grin_get_vertex_from_vertex_ref(GRIN_GRAPH g, GRIN_VERTEX_REF vr) { + return vr; +} + +GRIN_PARTITION grin_get_master_partition_from_vertex_ref(GRIN_GRAPH g, + GRIN_VERTEX_REF vr) { + auto _g = static_cast(g); + return _g->GetMasterPartitionIdFromVertexGid(vr); +} + +const char* grin_serialize_vertex_ref(GRIN_GRAPH g, GRIN_VERTEX_REF vr) { + std::stringstream ss; + ss << vr; + int len = ss.str().length() + 1; + char* out = new char[len]; + snprintf(out, len, "%s", ss.str().c_str()); + return out; +} + +void grin_destroy_serialized_vertex_ref(GRIN_GRAPH g, const char* svr) { + delete[] svr; +} + +GRIN_VERTEX_REF grin_deserialize_to_vertex_ref(GRIN_GRAPH g, const char* svr) { + std::stringstream ss(svr); + long long int vr; // NOLINT + ss >> vr; + return vr; +} + +bool grin_is_master_vertex(GRIN_GRAPH g, GRIN_VERTEX v) { + auto _g = static_cast(g); + return _g->GetMasterPartitionIdFromVertexGid(v) == _g->GetPartitionId(); +} + +bool grin_is_mirror_vertex(GRIN_GRAPH g, GRIN_VERTEX v) { + auto _g = static_cast(g); + return _g->GetMasterPartitionIdFromVertexGid(v) != _g->GetPartitionId(); +} +#endif + +#ifdef GRIN_TRAIT_FAST_VERTEX_REF +long long int grin_serialize_vertex_ref_as_int64(GRIN_GRAPH g, // NOLINT + GRIN_VERTEX_REF vr) { + return vr; +} + +GRIN_VERTEX_REF grin_deserialize_int64_to_vertex_ref( + GRIN_GRAPH g, + long long int fvr) { // NOLINT + return fvr; +} +#endif + +#ifdef GRIN_TRAIT_MASTER_VERTEX_MIRROR_PARTITION_LIST +GRIN_PARTITION_LIST grin_get_master_vertex_mirror_partition_list( + GRIN_GRAPH g, GRIN_VERTEX v) { + auto _g = static_cast(g); + auto pid = _g->GetMasterPartitionIdFromVertexGid(v); + if (pid != _g->GetPartitionId()) + return GRIN_NULL_PARTITION_LIST; + auto pl = new GRIN_PARTITION_LIST_T(); + for (auto i = 0; i < _g->GetPartitionNum(); ++i) { + if (i != pid) + pl->push_back(i); + } + return pl; +} +#endif + +#ifdef GRIN_TRAIT_MIRROR_VERTEX_MIRROR_PARTITION_LIST +GRIN_PARTITION_LIST grin_get_mirror_vertex_mirror_partition_list( + GRIN_GRAPH g, GRIN_VERTEX v) { + auto _g = static_cast(g); + auto pid = _g->GetMasterPartitionIdFromVertexGid(v); + if (pid == _g->GetPartitionId()) + return GRIN_NULL_PARTITION_LIST; + auto pl = new GRIN_PARTITION_LIST_T(); + for (auto i = 0; i < _g->GetPartitionNum(); ++i) { + if (i != pid) + pl->push_back(i); + } + return pl; +} +#endif + +#ifdef GRIN_ENABLE_EDGE_REF +GRIN_EDGE_REF grin_get_edge_ref_by_edge(GRIN_GRAPH g, GRIN_EDGE e) { return e; } + +void grin_destroy_edge_ref(GRIN_GRAPH g, GRIN_EDGE_REF er) { return; } + +GRIN_EDGE grin_get_edge_from_edge_ref(GRIN_GRAPH g, GRIN_EDGE_REF er) { + return er; +} + +GRIN_PARTITION grin_get_master_partition_from_edge_ref(GRIN_GRAPH g, + GRIN_EDGE_REF er) { + auto _g = static_cast(g); + return _g->GetMasterPartitionIdFromEdgeGid(er); +} + +const char* grin_serialize_edge_ref(GRIN_GRAPH g, GRIN_EDGE_REF er) { + std::stringstream ss; + ss << er; + int len = ss.str().length() + 1; + char* out = new char[len]; + snprintf(out, len, "%s", ss.str().c_str()); + return out; +} + +void grin_destroy_serialized_edge_ref(GRIN_GRAPH g, const char* ser) { + delete[] ser; +} + +GRIN_EDGE_REF grin_deserialize_to_edge_ref(GRIN_GRAPH g, const char* ser) { + std::stringstream ss(ser); + long long int er; // NOLINT + ss >> er; + return er; +} + +bool grin_is_master_edge(GRIN_GRAPH g, GRIN_EDGE e) { + auto _g = static_cast(g); + return _g->GetMasterPartitionIdFromEdgeGid(e) == _g->GetPartitionId(); +} + +bool grin_is_mirror_edge(GRIN_GRAPH g, GRIN_EDGE e) { + auto _g = static_cast(g); + return _g->GetMasterPartitionIdFromEdgeGid(e) != _g->GetPartitionId(); +} +#endif + +#ifdef GRIN_TRAIT_MASTER_EDGE_MIRROR_PARTITION_LIST +GRIN_PARTITION_LIST grin_get_master_edge_mirror_partition_list(GRIN_GRAPH g, + GRIN_EDGE e) { + auto _g = static_cast(g); + auto pid = _g->GetMasterPartitionIdFromEdgeGid(e); + if (pid != _g->GetPartitionId()) + return GRIN_NULL_PARTITION_LIST; + auto pl = new GRIN_PARTITION_LIST_T(); + for (size_t i = 0; i < _g->GetPartitionNum(); ++i) { + if (i != pid) + pl->push_back(i); + } + return pl; +} +#endif + +#ifdef GRIN_TRAIT_MIRROR_EDGE_MIRROR_PARTITION_LIST +GRIN_PARTITION_LIST grin_get_mirror_edge_mirror_partition_list(GRIN_GRAPH g, + GRIN_EDGE e) { + auto _g = static_cast(g); + auto pid = _g->GetMasterPartitionIdFromEdgeGid(e); + if (pid == _g->GetPartitionId()) + return GRIN_NULL_PARTITION_LIST; + auto pl = new GRIN_PARTITION_LIST_T(); + for (size_t i = 0; i < _g->GetPartitionNum(); ++i) { + if (i != pid) + pl->push_back(i); + } + return pl; +} +#endif diff --git a/demo_storage/src/partition/topology.cc b/demo_storage/src/partition/topology.cc new file mode 100644 index 0000000..8b49f3b --- /dev/null +++ b/demo_storage/src/partition/topology.cc @@ -0,0 +1,154 @@ +/** Copyright 2020 Alibaba Group Holding Limited. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "src/predefine.h" +// GRIN headers +#include "partition/topology.h" + +#if defined(GRIN_TRAIT_SELECT_MASTER_FOR_VERTEX_LIST) && \ + !defined(GRIN_WITH_VERTEX_PROPERTY) +GRIN_VERTEX_LIST grin_get_vertex_list_select_master(GRIN_GRAPH); + +GRIN_VERTEX_LIST grin_get_vertex_list_select_mirror(GRIN_GRAPH); +#endif + +#if defined(GRIN_TRAIT_SELECT_MASTER_FOR_VERTEX_LIST) && \ + defined(GRIN_WITH_VERTEX_PROPERTY) +GRIN_VERTEX_LIST grin_get_vertex_list_by_type_select_master( + GRIN_GRAPH g, GRIN_VERTEX_TYPE vtype) { + auto _g = static_cast(g); + return new GRIN_VERTEX_LIST_T(vtype, ONE_PARTITION, _g->GetPartitionId()); +} + +GRIN_VERTEX_LIST grin_get_vertex_list_by_type_select_mirror( + GRIN_GRAPH g, GRIN_VERTEX_TYPE vtype) { + auto _g = static_cast(g); + return new GRIN_VERTEX_LIST_T(vtype, ALL_BUT_ONE_PARTITION, + _g->GetPartitionId()); +} +#endif + +#if defined(GRIN_TRAIT_SELECT_PARTITION_FOR_VERTEX_LIST) && \ + !defined(GRIN_WITH_VERTEX_PROPERTY) +GRIN_VERTEX_LIST grin_get_vertex_list_select_partition(GRIN_GRAPH, + GRIN_PARTITION); +#endif + +#if defined(GRIN_TRAIT_SELECT_PARTITION_FOR_VERTEX_LIST) && \ + defined(GRIN_WITH_VERTEX_PROPERTY) +GRIN_VERTEX_LIST grin_get_vertex_list_by_type_select_partition( + GRIN_GRAPH g, GRIN_VERTEX_TYPE vtype, GRIN_PARTITION p) { + auto _g = static_cast(g); + if (p >= _g->GetPartitionNum()) { + return GRIN_NULL_VERTEX_LIST; + } + return new GRIN_VERTEX_LIST_T(vtype, ONE_PARTITION, p); +} +#endif + +#if defined(GRIN_TRAIT_SELECT_MASTER_FOR_EDGE_LIST) && \ + !defined(GRIN_WITH_EDGE_PROPERTY) +GRIN_EDGE_LIST grin_get_edge_list_select_master(GRIN_GRAPH); + +GRIN_EDGE_LIST grin_get_edge_list_select_mirror(GRIN_GRAPH); +#endif + +#if defined(GRIN_TRAIT_SELECT_MASTER_FOR_EDGE_LIST) && \ + defined(GRIN_WITH_EDGE_PROPERTY) +GRIN_EDGE_LIST grin_get_edge_list_by_type_select_master(GRIN_GRAPH g, + GRIN_EDGE_TYPE etype) { + auto _g = static_cast(g); + return new GRIN_EDGE_LIST_T(etype, ONE_PARTITION, _g->GetPartitionId()); +} + +GRIN_EDGE_LIST grin_get_edge_list_by_type_select_mirror(GRIN_GRAPH g, + GRIN_EDGE_TYPE etype) { + auto _g = static_cast(g); + return new GRIN_EDGE_LIST_T(etype, ALL_BUT_ONE_PARTITION, + _g->GetPartitionId()); +} +#endif + +#if defined(GRIN_TRAIT_SELECT_PARTITION_FOR_EDGE_LIST) && \ + !defined(GRIN_WITH_EDGE_PROPERTY) +GRIN_EDGE_LIST grin_get_edge_list_select_partition(GRIN_GRAPH, GRIN_PARTITION); +#endif + +#if defined(GRIN_TRAIT_SELECT_PARTITION_FOR_EDGE_LIST) && \ + defined(GRIN_WITH_EDGE_PROPERTY) +GRIN_EDGE_LIST grin_get_edge_list_by_type_select_partition(GRIN_GRAPH g, + GRIN_EDGE_TYPE etype, + GRIN_PARTITION p) { + auto _g = static_cast(g); + if (p >= _g->GetPartitionNum()) { + return GRIN_NULL_EDGE_LIST; + } + return new GRIN_EDGE_LIST_T(etype, ONE_PARTITION, p); +} +#endif + +#if defined(GRIN_TRAIT_SELECT_MASTER_NEIGHBOR_FOR_ADJACENT_LIST) && \ + !defined(GRIN_WITH_VERTEX_PROPERTY) +GRIN_ADJACENT_LIST grin_get_adjacent_list_select_master_neighbor(GRIN_GRAPH, + GRIN_DIRECTION, + GRIN_VERTEX); + +GRIN_ADJACENT_LIST grin_get_adjacent_list_select_mirror_neighbor(GRIN_GRAPH, + GRIN_DIRECTION, + GRIN_VERTEX); +#endif + +#if defined(GRIN_TRAIT_SELECT_MASTER_NEIGHBOR_FOR_ADJACENT_LIST) && \ + defined(GRIN_WITH_VERTEX_PROPERTY) +GRIN_ADJACENT_LIST grin_get_adjacent_list_by_edge_type_select_master_neighbor( + GRIN_GRAPH g, GRIN_DIRECTION d, GRIN_VERTEX v, GRIN_EDGE_TYPE etype) { + auto _g = static_cast(g); + auto vtype = DEMO_STORAGE_NAMESPACE::get_type_id_from_gid(v); + auto vid = DEMO_STORAGE_NAMESPACE::get_id_from_gid(v); + return new GRIN_ADJACENT_LIST_T(vtype, vid, d, etype, ONE_PARTITION, + _g->GetPartitionId()); +} + +GRIN_ADJACENT_LIST grin_get_adjacent_list_by_edge_type_select_mirror_neighbor( + GRIN_GRAPH g, GRIN_DIRECTION d, GRIN_VERTEX v, GRIN_EDGE_TYPE etype) { + auto _g = static_cast(g); + auto vtype = DEMO_STORAGE_NAMESPACE::get_type_id_from_gid(v); + auto vid = DEMO_STORAGE_NAMESPACE::get_id_from_gid(v); + return new GRIN_ADJACENT_LIST_T(vtype, vid, d, etype, ALL_BUT_ONE_PARTITION, + _g->GetPartitionId()); +} +#endif + +#if defined(GRIN_TRAIT_SELECT_NEIGHBOR_PARTITION_FOR_ADJACENT_LIST) && \ + !defined(GRIN_WITH_VERTEX_PROPERTY) +GRIN_ADJACENT_LIST grin_get_adjacent_list_select_partition_neighbor( + GRIN_GRAPH, GRIN_DIRECTION, GRIN_VERTEX, GRIN_PARTITION); +#endif + +#if defined(GRIN_TRAIT_SELECT_NEIGHBOR_PARTITION_FOR_ADJACENT_LIST) && \ + defined(GRIN_WITH_VERTEX_PROPERTY) +GRIN_ADJACENT_LIST +grin_get_adjacent_list_by_edge_type_select_partition_neighbor( + GRIN_GRAPH g, GRIN_DIRECTION d, GRIN_VERTEX v, GRIN_EDGE_TYPE etype, + GRIN_PARTITION p) { + auto _g = static_cast(g); + if (p >= _g->GetPartitionNum()) { + return GRIN_NULL_ADJACENT_LIST; + } + auto vtype = DEMO_STORAGE_NAMESPACE::get_type_id_from_gid(v); + auto vid = DEMO_STORAGE_NAMESPACE::get_id_from_gid(v); + return new GRIN_ADJACENT_LIST_T(vtype, vid, d, etype, ONE_PARTITION, p); +} +#endif From 5dbd4ae18867887ec844522cc05e423f0dcc267e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Tue, 11 Jul 2023 11:14:12 +0800 Subject: [PATCH 15/48] Implement topology related APIs --- demo_storage/src/topology/adjacentlist.cc | 237 ++++++++++++++++++++++ demo_storage/src/topology/edgelist.cc | 185 +++++++++++++++++ demo_storage/src/topology/vertexlist.cc | 190 +++++++++++++++++ 3 files changed, 612 insertions(+) create mode 100644 demo_storage/src/topology/adjacentlist.cc create mode 100644 demo_storage/src/topology/edgelist.cc create mode 100644 demo_storage/src/topology/vertexlist.cc diff --git a/demo_storage/src/topology/adjacentlist.cc b/demo_storage/src/topology/adjacentlist.cc new file mode 100644 index 0000000..6763097 --- /dev/null +++ b/demo_storage/src/topology/adjacentlist.cc @@ -0,0 +1,237 @@ +/** Copyright 2020 Alibaba Group Holding Limited. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "src/predefine.h" +// GRIN headers +#include "topology/adjacentlist.h" + +#if defined(GRIN_ENABLE_ADJACENT_LIST) && !defined(GRIN_WITH_EDGE_PROPERTY) +GRIN_ADJACENT_LIST grin_get_adjacent_list(GRIN_GRAPH, GRIN_DIRECTION, + GRIN_VERTEX); +#endif + +#ifdef GRIN_ENABLE_ADJACENT_LIST +void grin_destroy_adjacent_list(GRIN_GRAPH g, GRIN_ADJACENT_LIST al) { + auto _al = static_cast(al); + delete _al; +} +#endif + +#ifdef GRIN_ENABLE_ADJACENT_LIST_ARRAY +size_t grin_get_adjacent_list_size(GRIN_GRAPH g, GRIN_ADJACENT_LIST al) { + auto _g = static_cast(g); + auto _al = static_cast(al); + auto vtype = _al->vtype_id; + auto vid = _al->vid; + auto etype = _al->etype_id; + auto dir = _al->dir; + auto partition_num = _g->GetPartitionNum(); + + if (_al->partition_type == ALL_PARTITION) { + auto num = 0; + for (auto i = 0; i < partition_num; i++) { + num += _g->GetAdjacentListSize(vtype, vid, etype, i, dir); + } + return num; + } + + auto partition_id = _al->partition_id; + if (_al->partition_type == ONE_PARTITION) { + return _g->GetAdjacentListSize(vtype, vid, etype, partition_id, dir); + } + + if (_al->partition_type == ALL_BUT_ONE_PARTITION) { + auto num = 0; + for (auto i = 0; i < partition_num; i++) { + if (i != partition_id) { + num += _g->GetAdjacentListSize(vtype, vid, etype, i, dir); + } + } + return num; + } + + return GRIN_NULL_SIZE; +} + +GRIN_VERTEX grin_get_neighbor_from_adjacent_list(GRIN_GRAPH g, + GRIN_ADJACENT_LIST al, + size_t idx) { + auto e = grin_get_edge_from_adjacent_list(g, al, idx); + if (e == GRIN_NULL_EDGE) { + return GRIN_NULL_VERTEX; + } + auto _g = static_cast(g); + auto _al = static_cast(al); + auto& edge = _g->GetEdge(e); + auto v = DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id( + _al->vtype_id, _al->vid); + if (edge.GetSource() == v) { + return edge.GetDest(); + } else if (edge.GetDest() == v) { + return edge.GetSource(); + } else { + return GRIN_NULL_VERTEX; + } +} + +GRIN_EDGE grin_get_edge_from_adjacent_list(GRIN_GRAPH g, GRIN_ADJACENT_LIST al, + size_t idx) { + auto _g = static_cast(g); + auto _al = static_cast(al); + auto vtype = _al->vtype_id; + auto vid = _al->vid; + auto etype = _al->etype_id; + auto dir = _al->dir; + auto partition_num = _g->GetPartitionNum(); + size_t prefix = 0; + for (auto i = 0; i < partition_num; i++) { + auto size = _g->GetAdjacentListSize(vtype, vid, etype, i, dir); + if (_al->partition_type == ONE_PARTITION && i != _al->partition_id) { + size = 0; + } + if (_al->partition_type == ALL_BUT_ONE_PARTITION && + i == _al->partition_id) { + size = 0; + } + if (idx >= prefix && idx < prefix + size) { + auto& edges = _g->GetAdjacentList(vtype, vid, etype, i, dir); + return edges[idx - prefix]; + } + prefix += size; + } + return GRIN_NULL_EDGE; +} +#endif + +#ifdef GRIN_ENABLE_ADJACENT_LIST_ITERATOR +GRIN_ADJACENT_LIST_ITERATOR grin_get_adjacent_list_begin( + GRIN_GRAPH g, GRIN_ADJACENT_LIST al) { + auto _g = static_cast(g); + auto _al = static_cast(al); + auto vtype = _al->vtype_id; + auto vid = _al->vid; + auto etype = _al->etype_id; + auto dir = _al->dir; + auto partition_id = _al->partition_id; + auto partition_num = _g->GetPartitionNum(); + + auto current_partition = 0; + while (current_partition < partition_num) { + auto size = + _g->GetAdjacentListSize(vtype, vid, etype, current_partition, dir); + if (_al->partition_type == ONE_PARTITION && + current_partition != partition_id) { + size = 0; + } + if (_al->partition_type == ALL_BUT_ONE_PARTITION && + current_partition == partition_id) { + size = 0; + } + if (size > 0) { + return new GRIN_ADJACENT_LIST_ITERATOR_T( + vtype, vid, dir, etype, _al->partition_type, partition_id, + current_partition, 0); + } + current_partition++; + } + + return new GRIN_ADJACENT_LIST_ITERATOR_T(vtype, vid, dir, etype, + _al->partition_type, partition_id, + current_partition, 0); +} + +void grin_destroy_adjacent_list_iter(GRIN_GRAPH g, + GRIN_ADJACENT_LIST_ITERATOR ali) { + auto _ali = static_cast(ali); + delete _ali; +} + +void grin_get_next_adjacent_list_iter(GRIN_GRAPH g, + GRIN_ADJACENT_LIST_ITERATOR ali) { + auto _g = static_cast(g); + auto _ali = static_cast(ali); + auto vtype = _ali->vtype_id; + auto vid = _ali->vid; + auto etype = _ali->etype_id; + auto dir = _ali->dir; + auto partition_num = _g->GetPartitionNum(); + auto partition_id = _ali->partition_id; + + _ali->current_offset++; + if (_ali->current_offset >= _g->GetAdjacentListSize(vtype, vid, etype, + _ali->current_partition, + dir)) { + _ali->current_offset = 0; + _ali->current_partition++; + while (_ali->current_partition < partition_num) { + auto size = _g->GetAdjacentListSize(vtype, vid, etype, + _ali->current_partition, dir); + if (_ali->partition_type == ONE_PARTITION && + _ali->current_partition != partition_id) { + size = 0; + } + if (_ali->partition_type == ALL_BUT_ONE_PARTITION && + _ali->current_partition == partition_id) { + size = 0; + } + if (size > 0) { + return; + } + _ali->current_partition++; + } + } +} + +bool grin_is_adjacent_list_end(GRIN_GRAPH g, GRIN_ADJACENT_LIST_ITERATOR ali) { + if (ali == GRIN_NULL_ADJACENT_LIST_ITERATOR) { + return true; + } + auto _g = static_cast(g); + auto _ali = static_cast(ali); + return _ali->current_partition >= _g->GetPartitionNum(); +} + +GRIN_VERTEX grin_get_neighbor_from_adjacent_list_iter( + GRIN_GRAPH g, GRIN_ADJACENT_LIST_ITERATOR ali) { + auto e = grin_get_edge_from_adjacent_list_iter(g, ali); + if (e == GRIN_NULL_EDGE) { + return GRIN_NULL_VERTEX; + } + auto _g = static_cast(g); + auto _ali = static_cast(ali); + auto& edge = _g->GetEdge(e); + auto v = DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id( + _ali->vtype_id, _ali->vid); + if (edge.GetSource() == v) { + return edge.GetDest(); + } else if (edge.GetDest() == v) { + return edge.GetSource(); + } else { + return GRIN_NULL_VERTEX; + } +} + +GRIN_EDGE grin_get_edge_from_adjacent_list_iter( + GRIN_GRAPH g, GRIN_ADJACENT_LIST_ITERATOR ali) { + auto _g = static_cast(g); + auto _ali = static_cast(ali); + auto& edges = _g->GetAdjacentList(_ali->vtype_id, _ali->vid, _ali->etype_id, + _ali->current_partition, _ali->dir); + if (_ali->current_offset >= edges.size()) { + return GRIN_NULL_EDGE; + } + return edges[_ali->current_offset]; +} +#endif diff --git a/demo_storage/src/topology/edgelist.cc b/demo_storage/src/topology/edgelist.cc new file mode 100644 index 0000000..5b3402c --- /dev/null +++ b/demo_storage/src/topology/edgelist.cc @@ -0,0 +1,185 @@ +/** Copyright 2020 Alibaba Group Holding Limited. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "src/predefine.h" +// GRIN headers +#include "topology/edgelist.h" + +#if defined(GRIN_ENABLE_EDGE_LIST) && !defined(GRIN_WITH_EDGE_PROPERTY) +GRIN_EDGE_LIST grin_get_edge_list(GRIN_GRAPH); +#endif + +#ifdef GRIN_ENABLE_EDGE_LIST +void grin_destroy_edge_list(GRIN_GRAPH g, GRIN_EDGE_LIST el) { + auto _el = static_cast(el); + delete _el; +} +#endif + +#ifdef GRIN_ENABLE_EDGE_LIST_ARRAY +size_t grin_get_edge_list_size(GRIN_GRAPH g, GRIN_EDGE_LIST el) { + auto _g = static_cast(g); + auto _el = static_cast(el); + auto etype = _el->type_id; + if (etype >= _g->GetEdgeTypeNum()) + return GRIN_NULL_SIZE; + + if (_el->partition_type == ALL_PARTITION) { + return _g->GetEdgeNum(etype); + } else if (_el->partition_type == ONE_PARTITION) { + return _g->GetPartitionedEdgeNum(etype, _el->partition_id); + } else if (_el->partition_type == ALL_BUT_ONE_PARTITION) { + return _g->GetEdgeNum(etype) - + _g->GetPartitionedEdgeNum(etype, _el->partition_id); + } + + return GRIN_NULL_SIZE; +} + +GRIN_EDGE grin_get_edge_from_list(GRIN_GRAPH g, GRIN_EDGE_LIST el, size_t idx) { + auto _g = static_cast(g); + auto _el = static_cast(el); + auto etype = _el->type_id; + auto num = _g->GetEdgeNum(etype); + + if (_el->partition_type == ALL_PARTITION) { + if (idx < num) { + return DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id(etype, + idx); + } else { + return GRIN_NULL_EDGE; + } + } + + auto partition_id = _el->partition_id; + auto partition_num = _g->GetPartitionNum(); + auto partitioned_num = _g->GetPartitionedEdgeNum(etype, partition_id); + + if (_el->partition_type == ONE_PARTITION) { + if (idx < partitioned_num) { + auto _idx = idx * partition_num + partition_id; + return DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id(etype, + _idx); + } else { + return GRIN_NULL_EDGE; + } + } + if (_el->partition_type == ALL_BUT_ONE_PARTITION) { + if (idx < num - partitioned_num) { + auto _idx = idx + idx / (partition_num - 1); + if (idx % (partition_num - 1) >= partition_id) + _idx++; + return DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id(etype, + _idx); + } else { + return GRIN_NULL_EDGE; + } + } + return GRIN_NULL_EDGE; +} +#endif + +#ifdef GRIN_ENABLE_EDGE_LIST_ITERATOR +GRIN_EDGE_LIST_ITERATOR grin_get_edge_list_begin(GRIN_GRAPH g, + GRIN_EDGE_LIST el) { + auto _g = static_cast(g); + auto _el = static_cast(el); + auto etype = _el->type_id; + + if (_el->partition_type == ALL_PARTITION) { + return new GRIN_EDGE_LIST_ITERATOR_T(etype, ALL_PARTITION, 0, 0); + } + + auto num = _g->GetEdgeNum(etype); + auto partition_id = _el->partition_id; + auto partition_num = _g->GetPartitionNum(); + + if (_el->partition_type == ONE_PARTITION) { + auto _offset = partition_id; + if (_offset >= num) + _offset = -1; + return new GRIN_EDGE_LIST_ITERATOR_T(etype, ONE_PARTITION, partition_id, + _offset); + } + + if (_el->partition_type == ALL_BUT_ONE_PARTITION) { + auto _offset = 0; + if (_offset % partition_num == partition_id) + _offset++; + if (_offset >= num) + _offset = -1; + return new GRIN_EDGE_LIST_ITERATOR_T(etype, ALL_BUT_ONE_PARTITION, + partition_id, _offset); + } + + return GRIN_NULL_EDGE_LIST_ITERATOR; +} + +void grin_destroy_edge_list_iter(GRIN_GRAPH g, GRIN_EDGE_LIST_ITERATOR eli) { + auto _eli = static_cast(eli); + delete _eli; +} + +void grin_get_next_edge_list_iter(GRIN_GRAPH g, GRIN_EDGE_LIST_ITERATOR eli) { + auto _g = static_cast(g); + auto _eli = static_cast(eli); + auto etype = _eli->type_id; + auto num = _g->GetEdgeNum(etype); + + if (_eli->partition_type == ALL_PARTITION) { + _eli->current_offset++; + if (_eli->current_offset >= num) { + _eli->current_offset = -1; + } + return; + } + + auto partition_id = _eli->partition_id; + auto partition_num = _g->GetPartitionNum(); + + if (_eli->partition_type == ONE_PARTITION) { + _eli->current_offset += partition_num; + if (_eli->current_offset >= num) { + _eli->current_offset = -1; + } + return; + } + + if (_eli->partition_type == ALL_BUT_ONE_PARTITION) { + _eli->current_offset++; + if (_eli->current_offset % partition_num == partition_id) { + _eli->current_offset++; + } + if (_eli->current_offset >= num) { + _eli->current_offset = -1; + } + return; + } +} + +bool grin_is_edge_list_end(GRIN_GRAPH g, GRIN_EDGE_LIST_ITERATOR eli) { + if (eli == GRIN_NULL_EDGE_LIST_ITERATOR) { + return true; + } + auto _eli = static_cast(eli); + return _eli->current_offset == -1; +} + +GRIN_EDGE grin_get_edge_from_iter(GRIN_GRAPH g, GRIN_EDGE_LIST_ITERATOR eli) { + auto _eli = static_cast(eli); + return DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id( + _eli->type_id, _eli->current_offset); +} +#endif diff --git a/demo_storage/src/topology/vertexlist.cc b/demo_storage/src/topology/vertexlist.cc new file mode 100644 index 0000000..f6d35c8 --- /dev/null +++ b/demo_storage/src/topology/vertexlist.cc @@ -0,0 +1,190 @@ +/** Copyright 2020 Alibaba Group Holding Limited. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "src/predefine.h" +// GRIN headers +#include "topology/vertexlist.h" + +#if defined(GRIN_ENABLE_VERTEX_LIST) && !defined(GRIN_WITH_VERTEX_PROPERTY) +GRIN_VERTEX_LIST grin_get_vertex_list(GRIN_GRAPH); +#endif + +#ifdef GRIN_ENABLE_VERTEX_LIST +void grin_destroy_vertex_list(GRIN_GRAPH g, GRIN_VERTEX_LIST vl) { + auto _vl = static_cast(vl); + delete _vl; +} +#endif + +#ifdef GRIN_ENABLE_VERTEX_LIST_ARRAY +size_t grin_get_vertex_list_size(GRIN_GRAPH g, GRIN_VERTEX_LIST vl) { + auto _g = static_cast(g); + auto _vl = static_cast(vl); + auto vtype = _vl->type_id; + if (vtype >= _g->GetVertexTypeNum()) + GRIN_NULL_SIZE; + + if (_vl->partition_type == ALL_PARTITION) { + return _g->GetVertexNum(vtype); + } else if (_vl->partition_type == ONE_PARTITION) { + return _g->GetPartitionedVertexNum(vtype, _vl->partition_id); + } else if (_vl->partition_type == ALL_BUT_ONE_PARTITION) { + return _g->GetVertexNum(vtype) - + _g->GetPartitionedVertexNum(vtype, _vl->partition_id); + } + + return GRIN_NULL_SIZE; +} + +GRIN_VERTEX grin_get_vertex_from_list(GRIN_GRAPH g, GRIN_VERTEX_LIST vl, + size_t idx) { + auto _g = static_cast(g); + auto _vl = static_cast(vl); + auto vtype = _vl->type_id; + auto num = _g->GetVertexNum(vtype); + + if (_vl->partition_type == ALL_PARTITION) { + if (idx < num) { + return DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id(vtype, + idx); + } else { + return GRIN_NULL_VERTEX; + } + } + + auto partition_id = _vl->partition_id; + auto partition_num = _g->GetPartitionNum(); + auto partitioned_num = _g->GetPartitionedVertexNum(vtype, partition_id); + + if (_vl->partition_type == ONE_PARTITION) { + if (idx < partitioned_num) { + auto _idx = idx * partition_num + partition_id; + return DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id(vtype, + _idx); + } else { + return GRIN_NULL_VERTEX; + } + } + + if (_vl->partition_type == ALL_BUT_ONE_PARTITION) { + if (idx < num - partitioned_num) { + auto _idx = idx + idx / (partition_num - 1); + if (idx % (partition_num - 1) >= partition_id) + _idx++; + return DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id(vtype, + _idx); + } else { + return GRIN_NULL_VERTEX; + } + } + return GRIN_NULL_VERTEX; +} +#endif + +#ifdef GRIN_ENABLE_VERTEX_LIST_ITERATOR +GRIN_VERTEX_LIST_ITERATOR grin_get_vertex_list_begin(GRIN_GRAPH g, + GRIN_VERTEX_LIST vl) { + auto _g = static_cast(g); + auto _vl = static_cast(vl); + auto vtype = _vl->type_id; + + if (_vl->partition_type == ALL_PARTITION) { + return new GRIN_VERTEX_LIST_ITERATOR_T(vtype, ALL_PARTITION, 0, 0); + } + + auto num = _g->GetVertexNum(vtype); + auto partition_id = _vl->partition_id; + auto partition_num = _g->GetPartitionNum(); + + if (_vl->partition_type == ONE_PARTITION) { + auto _offset = partition_id; + if (_offset >= num) + _offset = -1; + return new GRIN_VERTEX_LIST_ITERATOR_T(vtype, ONE_PARTITION, partition_id, + _offset); + } + + if (_vl->partition_type == ALL_BUT_ONE_PARTITION) { + auto _offset = 0; + if (_offset % partition_num == partition_id) + _offset++; + if (_offset >= num) + _offset = -1; + return new GRIN_VERTEX_LIST_ITERATOR_T(vtype, ALL_BUT_ONE_PARTITION, + partition_id, _offset); + } + + return GRIN_NULL_VERTEX_LIST_ITERATOR; +} + +void grin_destroy_vertex_list_iter(GRIN_GRAPH g, + GRIN_VERTEX_LIST_ITERATOR vli) { + auto _vli = static_cast(vli); + delete _vli; +} + +void grin_get_next_vertex_list_iter(GRIN_GRAPH g, + GRIN_VERTEX_LIST_ITERATOR vli) { + auto _g = static_cast(g); + auto _vli = static_cast(vli); + auto vtype = _vli->type_id; + auto num = _g->GetVertexNum(vtype); + + if (_vli->partition_type == ALL_PARTITION) { + _vli->current_offset++; + if (_vli->current_offset >= num) { + _vli->current_offset = -1; + } + return; + } + + auto partition_id = _vli->partition_id; + auto partition_num = _g->GetPartitionNum(); + + if (_vli->partition_type == ONE_PARTITION) { + _vli->current_offset += partition_num; + if (_vli->current_offset >= num) { + _vli->current_offset = -1; + } + return; + } + + if (_vli->partition_type == ALL_BUT_ONE_PARTITION) { + _vli->current_offset++; + if (_vli->current_offset % partition_num == partition_id) { + _vli->current_offset++; + } + if (_vli->current_offset >= num) { + _vli->current_offset = -1; + } + return; + } +} + +bool grin_is_vertex_list_end(GRIN_GRAPH g, GRIN_VERTEX_LIST_ITERATOR vli) { + if (vli == GRIN_NULL_VERTEX_LIST_ITERATOR) { + return true; + } + auto _vli = static_cast(vli); + return _vli->current_offset == -1; +} + +GRIN_VERTEX grin_get_vertex_from_iter(GRIN_GRAPH g, + GRIN_VERTEX_LIST_ITERATOR vli) { + auto _vli = static_cast(vli); + return DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id( + _vli->type_id, _vli->current_offset); +} +#endif From 42a23ff552cb7f5ade78cf911410940927d8ae47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Tue, 18 Jul 2023 10:01:39 +0800 Subject: [PATCH 16/48] Rebase on v0.1.4 --- demo_storage/predefine.h | 24 ++--------- rust/Cargo.toml | 8 ++-- rust/grin.rs | 70 ++++++++++++++++++++++++++++++++ rust/grin_demo_storage.rs | 2 - storage/demo_storage/predefine.h | 24 ++--------- 5 files changed, 83 insertions(+), 45 deletions(-) diff --git a/demo_storage/predefine.h b/demo_storage/predefine.h index 14616b8..b841b7b 100644 --- a/demo_storage/predefine.h +++ b/demo_storage/predefine.h @@ -84,15 +84,6 @@ typedef enum { #define GRIN_ENABLE_VERTEX_REF #define GRIN_TRAIT_FAST_VERTEX_REF #define GRIN_ENABLE_EDGE_REF -#define GRIN_ASSUME_ALL_REPLICATE_PARTITION -// #define GRIN_ASSUME_EDGE_CUT_PARTITION -// #define GRIN_ASSUME_EDGE_CUT_FOLLOW_SRC_PARTITION -// #define GRIN_ASSUME_EDGE_CUT_FOLLOW_DST_PARTITION -// #define GRIN_ASSUME_VERTEX_CUT_PARTITION -// #define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_VERTEX_DATA -#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_VERTEX_DATA -// #define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_EDGE_DATA -#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_EDGE_DATA #define GRIN_TRAIT_MASTER_VERTEX_MIRROR_PARTITION_LIST #define GRIN_TRAIT_MIRROR_VERTEX_MIRROR_PARTITION_LIST #define GRIN_TRAIT_MASTER_EDGE_MIRROR_PARTITION_LIST @@ -118,20 +109,17 @@ typedef enum { #define GRIN_TRAIT_NATURAL_ID_FOR_EDGE_TYPE #define GRIN_ENABLE_EDGE_PRIMARY_KEYS #define GRIN_TRAIT_NATURAL_ID_FOR_EDGE_PROPERTY -#define GRIN_TRAIT_SPECIFIC_VEV_RELATION -// #define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_VERTEX_PROPERTY -#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_VERTEX_PROPERTY -// #define GRIN_ASSUME_SPLIT_MASTER_MIRROR_PARTITION_FOR_VERTEX_PROPERTY -// #define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_EDGE_PROPERTY -#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_EDGE_PROPERTY -// #define GRIN_ASSUME_SPLIT_MASTER_MIRROR_PARTITION_FOR_EDGE_PROPERTY // Index // #define GRIN_WITH_VERTEX_LABEL // #define GRIN_WITH_EDGE_LABEL #define GRIN_ASSUME_ALL_VERTEX_LIST_SORTED #define GRIN_ENABLE_VERTEX_INTERNAL_ID_INDEX +#define GRIN_ENABLE_VERTEX_EXTERNAL_ID_OF_INT64 +#define GRIN_ENABLE_VERTEX_EXTERNAL_ID_OF_STRING #define GRIN_ENABLE_VERTEX_PK_INDEX #define GRIN_ENABLE_EDGE_PK_INDEX +// Common +#define GRIN_TRAIT_LOOSE_SCHEMA /* 3. Define the handles using typedef */ typedef void *GRIN_GRAPH; @@ -206,8 +194,6 @@ typedef unsigned GRIN_VERTEX_PROPERTY_ID; #ifdef GRIN_WITH_EDGE_PROPERTY typedef unsigned GRIN_EDGE_TYPE; typedef void* GRIN_EDGE_TYPE_LIST; -typedef unsigned GRIN_VEV_TYPE; -typedef void* GRIN_VEV_TYPE_LIST; typedef unsigned GRIN_EDGE_PROPERTY; typedef void* GRIN_EDGE_PROPERTY_LIST; #endif @@ -255,8 +241,6 @@ typedef void* GRIN_LABEL_LIST; #define GRIN_NULL_VERTEX_PROPERTY_ID (unsigned)~0 #define GRIN_NULL_EDGE_TYPE (unsigned)~0 #define GRIN_NULL_EDGE_TYPE_LIST NULL -#define GRIN_NULL_VEV_TYPE (unsigned)~0 -#define GRIN_NULL_VEV_TYPE_LIST NULL #define GRIN_NULL_EDGE_PROPERTY (unsigned)~0 #define GRIN_NULL_EDGE_PROPERTY_LIST NULL #define GRIN_NULL_EDGE_TYPE_ID (unsigned)~0 diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 49c48b4..d806a78 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -56,6 +56,8 @@ grin_enable_vertex_external_id_of_int64 = [] grin_enable_vertex_external_id_of_string = [] grin_enable_vertex_pk_index = [] grin_enable_edge_pk_index = [] -grin_features_enable_v6d = ['grin_assume_has_directed_graph', 'grin_assume_has_undirected_graph', 'grin_assume_has_multi_edge_graph', 'grin_enable_vertex_list', 'grin_enable_vertex_list_array', 'grin_enable_vertex_list_iterator', 'grin_enable_adjacent_list', 'grin_enable_adjacent_list_array', 'grin_enable_adjacent_list_iterator', 'grin_enable_graph_partition', 'grin_assume_edge_cut_partition', 'grin_trait_natural_id_for_partition', 'grin_enable_vertex_ref', 'grin_trait_fast_vertex_ref', 'grin_trait_select_master_for_vertex_list', 'grin_enable_row', 'grin_enable_schema', 'grin_trait_property_value_of_float_array', 'grin_with_vertex_property', 'grin_enable_vertex_primary_keys', 'grin_with_edge_property', 'grin_enable_vertex_internal_id_index', 'grin_enable_vertex_external_id_of_int64', 'grin_enable_vertex_pk_index'] -grin_features_enable_gart = ['grin_assume_has_undirected_graph', 'grin_assume_has_multi_edge_graph', 'grin_enable_vertex_list', 'grin_enable_vertex_list_iterator', 'grin_enable_adjacent_list', 'grin_enable_adjacent_list_iterator', 'grin_enable_graph_partition', 'grin_assume_edge_cut_partition', 'grin_trait_natural_id_for_partition', 'grin_enable_vertex_ref', 'grin_trait_fast_vertex_ref', 'grin_trait_select_master_for_vertex_list', 'grin_enable_row', 'grin_trait_const_value_ptr', 'grin_enable_schema', 'grin_trait_property_value_of_float_array', 'grin_with_vertex_property', 'grin_with_edge_property', 'grin_enable_vertex_internal_id_index', 'grin_enable_vertex_external_id_of_int64'] -grin_features_enable_graphar = ['grin_assume_has_multi_edge_graph', 'grin_enable_vertex_list', 'grin_enable_vertex_list_array', 'grin_enable_vertex_list_iterator', 'grin_enable_edge_list', 'grin_enable_edge_list_iterator', 'grin_enable_adjacent_list', 'grin_enable_adjacent_list_iterator', 'grin_enable_graph_partition', 'grin_trait_natural_id_for_partition', 'grin_enable_vertex_ref', 'grin_trait_fast_vertex_ref', 'grin_trait_master_vertex_mirror_partition_list', 'grin_trait_mirror_vertex_mirror_partition_list', 'grin_trait_select_master_for_vertex_list', 'grin_trait_select_partition_for_vertex_list', 'grin_enable_row', 'grin_enable_schema', 'grin_with_vertex_property', 'grin_enable_vertex_primary_keys', 'grin_with_edge_property', 'grin_trait_property_value_of_float_array', 'grin_assume_all_vertex_list_sorted', 'grin_enable_vertex_internal_id_index', 'grin_enable_vertex_external_id_of_int64'] +grin_trait_loose_schema = [] +grin_features_enable_v6d = ['grin_assume_has_directed_graph', 'grin_assume_has_undirected_graph', 'grin_assume_has_multi_edge_graph', 'grin_enable_vertex_list', 'grin_enable_vertex_list_array', 'grin_enable_vertex_list_iterator', 'grin_enable_adjacent_list', 'grin_enable_adjacent_list_array', 'grin_enable_adjacent_list_iterator', 'grin_enable_graph_partition', 'grin_trait_natural_id_for_partition', 'grin_enable_vertex_ref', 'grin_trait_fast_vertex_ref', 'grin_trait_select_master_for_vertex_list', 'grin_enable_row', 'grin_with_vertex_property', 'grin_with_vertex_property_name', 'grin_with_vertex_type_name', 'grin_trait_natural_id_for_vertex_type', 'grin_trait_natural_id_for_vertex_property', 'grin_with_edge_property', 'grin_with_edge_property_name', 'grin_with_edge_type_name', 'grin_trait_natural_id_for_edge_type', 'grin_trait_natural_id_for_edge_property', 'grin_enable_vertex_primary_keys', 'grin_enable_vertex_internal_id_index', 'grin_enable_vertex_pk_index', 'grin_enable_vertex_external_id_of_int64'] +grin_features_enable_gart = ['grin_assume_has_directed_graph', 'grin_assume_has_undirected_graph', 'grin_assume_has_multi_edge_graph', 'grin_enable_vertex_list', 'grin_enable_vertex_list_iterator', 'grin_enable_adjacent_list', 'grin_enable_adjacent_list_iterator', 'grin_enable_graph_partition', 'grin_trait_natural_id_for_partition', 'grin_enable_vertex_ref', 'grin_trait_fast_vertex_ref', 'grin_trait_select_master_for_vertex_list', 'grin_enable_row', 'grin_with_vertex_property', 'grin_with_vertex_property_name', 'grin_with_vertex_type_name', 'grin_trait_natural_id_for_vertex_type', 'grin_trait_natural_id_for_vertex_property', 'grin_with_edge_property', 'grin_with_edge_property_name', 'grin_with_edge_type_name', 'grin_trait_natural_id_for_edge_type', 'grin_trait_natural_id_for_edge_property', 'grin_enable_vertex_internal_id_index'] +grin_features_enable_GraphAr = ['grin_assume_has_directed_graph', 'grin_assume_has_multi_edge_graph', 'grin_enable_vertex_list', 'grin_enable_vertex_list_array', 'grin_enable_vertex_list_iterator', 'grin_enable_edge_list', 'grin_enable_edge_list_iterator', 'grin_enable_adjacent_list', 'grin_enable_adjacent_list_iterator', 'grin_enable_graph_partition', 'grin_trait_natural_id_for_partition', 'grin_enable_vertex_ref', 'grin_trait_fast_vertex_ref', 'grin_assume_all_replicate_partition', 'grin_assume_replicate_master_mirror_partition_for_vertex_data', 'grin_assume_replicate_master_mirror_partition_for_edge_data', 'grin_trait_master_vertex_mirror_partition_list', 'grin_trait_mirror_vertex_mirror_partition_list', 'grin_trait_select_master_for_vertex_list', 'grin_trait_select_partition_for_vertex_list', 'grin_enable_row', 'grin_with_vertex_property', 'grin_with_vertex_property_name', 'grin_with_vertex_type_name', 'grin_trait_natural_id_for_vertex_type', 'grin_enable_vertex_primary_keys', 'grin_trait_natural_id_for_vertex_property', 'grin_with_edge_property', 'grin_with_edge_property_name', 'grin_with_edge_type_name', 'grin_trait_natural_id_for_edge_type', 'grin_trait_natural_id_for_edge_property', 'grin_assume_replicate_master_mirror_partition_for_vertex_property', 'grin_assume_replicate_master_mirror_partition_for_edge_property', 'grin_assume_all_vertex_list_sorted', 'grin_enable_vertex_internal_id_index'] +grin_features_enable_demo_storage = ['grin_assume_has_directed_graph', 'grin_assume_has_undirected_graph', 'grin_assume_has_multi_edge_graph', 'grin_with_vertex_data', 'grin_with_edge_data', 'grin_enable_vertex_list', 'grin_enable_vertex_list_array', 'grin_enable_vertex_list_iterator', 'grin_enable_edge_list', 'grin_enable_edge_list_array', 'grin_enable_edge_list_iterator', 'grin_enable_adjacent_list', 'grin_enable_adjacent_list_array', 'grin_enable_adjacent_list_iterator', 'grin_enable_graph_partition', 'grin_trait_natural_id_for_partition', 'grin_enable_vertex_ref', 'grin_trait_fast_vertex_ref', 'grin_enable_edge_ref', 'grin_trait_master_vertex_mirror_partition_list', 'grin_trait_mirror_vertex_mirror_partition_list', 'grin_trait_master_edge_mirror_partition_list', 'grin_trait_mirror_edge_mirror_partition_list', 'grin_trait_select_master_for_vertex_list', 'grin_trait_select_partition_for_vertex_list', 'grin_trait_select_master_for_edge_list', 'grin_trait_select_partition_for_edge_list', 'grin_trait_select_master_neighbor_for_adjacent_list', 'grin_trait_select_neighbor_partition_for_adjacent_list', 'grin_enable_row', 'grin_trait_const_value_ptr', 'grin_with_vertex_property', 'grin_with_vertex_property_name', 'grin_with_vertex_type_name', 'grin_trait_natural_id_for_vertex_type', 'grin_enable_vertex_primary_keys', 'grin_trait_natural_id_for_vertex_property', 'grin_with_edge_property', 'grin_with_edge_property_name', 'grin_with_edge_type_name', 'grin_trait_natural_id_for_edge_type', 'grin_enable_edge_primary_keys', 'grin_trait_natural_id_for_edge_property', 'grin_assume_all_vertex_list_sorted', 'grin_enable_vertex_internal_id_index', 'grin_enable_vertex_external_id_of_int64', 'grin_enable_vertex_external_id_of_string', 'grin_enable_vertex_pk_index', 'grin_enable_edge_pk_index', 'grin_trait_loose_schema'] diff --git a/rust/grin.rs b/rust/grin.rs index 07fd4e1..3504365 100644 --- a/rust/grin.rs +++ b/rust/grin.rs @@ -230,6 +230,71 @@ cfg_if::cfg_if! { pub const GRIN_NULL_EDGE_PROPERTY_ID: GrinEdgePropertyId = u32::MAX; pub const GRIN_NULL_ROW: GrinRow = std::ptr::null_mut(); pub const GRIN_NULL_SIZE: u32 = u32::MAX; + } elif #[cfg(feature = "grin_features_enable_demo_storage")]{ + pub type GrinGraph = *mut ::std::os::raw::c_void; + pub type GrinVertex = i64; + pub type GrinEdge = i64; + pub type GrinVertexData = *mut ::std::os::raw::c_void; + pub type GrinVertexList = *mut ::std::os::raw::c_void; + pub type GrinVertexListIterator = *mut ::std::os::raw::c_void; + pub type GrinAdjacentList = *mut ::std::os::raw::c_void; + pub type GrinAdjacentListIterator = *mut ::std::os::raw::c_void; + pub type GrinEdgeData = *mut ::std::os::raw::c_void; + pub type GrinEdgeList = *mut ::std::os::raw::c_void; + pub type GrinEdgeListIterator = *mut ::std::os::raw::c_void; + pub type GrinPartitionedGraph = *mut ::std::os::raw::c_void; + pub type GrinPartition = u32; + pub type GrinPartitionList = *mut ::std::os::raw::c_void; + pub type GrinPartitionId = u32; + pub type GrinVertexRef = i64; + pub type GrinEdgeRef = i64; + pub type GrinVertexType = u32; + pub type GrinVertexTypeList = *mut ::std::os::raw::c_void; + pub type GrinVertexProperty = u32; + pub type GrinVertexPropertyList = *mut ::std::os::raw::c_void; + pub type GrinVertexTypeId = u32; + pub type GrinVertexPropertyId = u32; + pub type GrinEdgeType = u32; + pub type GrinEdgeTypeList = *mut ::std::os::raw::c_void; + pub type GrinEdgeProperty = u32; + pub type GrinEdgePropertyList = *mut ::std::os::raw::c_void; + pub type GrinEdgeTypeId = u32; + pub type GrinEdgePropertyId = u32; + pub type GrinRow = *mut ::std::os::raw::c_void; + pub const GRIN_NULL_DATATYPE: GrinDatatype = GRIN_DATATYPE_UNDEFINED; + pub const GRIN_NULL_GRAPH: GrinGraph = std::ptr::null_mut(); + pub const GRIN_NULL_VERTEX: GrinVertex = -1; + pub const GRIN_NULL_EDGE: GrinEdge = -1; + pub const GRIN_NULL_VERTEX_DATA: GrinVertexData = std::ptr::null_mut(); + pub const GRIN_NULL_VERTEX_LIST: GrinVertexList = std::ptr::null_mut(); + pub const GRIN_NULL_VERTEX_LIST_ITERATOR: GrinVertexListIterator = std::ptr::null_mut(); + pub const GRIN_NULL_ADJACENT_LIST: GrinAdjacentList = std::ptr::null_mut(); + pub const GRIN_NULL_ADJACENT_LIST_ITERATOR: GrinAdjacentListIterator = std::ptr::null_mut(); + pub const GRIN_NULL_EDGE_DATA: GrinEdgeData = std::ptr::null_mut(); + pub const GRIN_NULL_EDGE_LIST: GrinEdgeList = std::ptr::null_mut(); + pub const GRIN_NULL_EDGE_LIST_ITERATOR: GrinEdgeListIterator = std::ptr::null_mut(); + pub const GRIN_NULL_PARTITIONED_GRAPH: GrinPartitionedGraph = std::ptr::null_mut(); + pub const GRIN_NULL_PARTITION: GrinPartition = u32::MAX; + pub const GRIN_NULL_PARTITION_LIST: GrinPartitionList = std::ptr::null_mut(); + pub const GRIN_NULL_PARTITION_ID: GrinPartitionId = u32::MAX; + pub const GRIN_NULL_VERTEX_REF: GrinVertexRef = -1; + pub const GRIN_NULL_EDGE_REF: GrinEdgeRef = -1; + pub const GRIN_NULL_VERTEX_TYPE: GrinVertexType = u32::MAX; + pub const GRIN_NULL_VERTEX_TYPE_LIST: GrinVertexTypeList = std::ptr::null_mut(); + pub const GRIN_NULL_VERTEX_PROPERTY: GrinVertexProperty = u32::MAX; + pub const GRIN_NULL_VERTEX_PROPERTY_LIST: GrinVertexPropertyList = std::ptr::null_mut(); + pub const GRIN_NULL_VERTEX_TYPE_ID: GrinVertexTypeId = u32::MAX; + pub const GRIN_NULL_VERTEX_PROPERTY_ID: GrinVertexPropertyId = u32::MAX; + pub const GRIN_NULL_EDGE_TYPE: GrinEdgeType = u32::MAX; + pub const GRIN_NULL_EDGE_TYPE_LIST: GrinEdgeTypeList = std::ptr::null_mut(); + pub const GRIN_NULL_VEV_TYPE: GrinVevType = u32::MAX; + pub const GRIN_NULL_VEV_TYPE_LIST: GrinVevTypeList = std::ptr::null_mut(); + pub const GRIN_NULL_EDGE_PROPERTY: GrinEdgeProperty = u32::MAX; + pub const GRIN_NULL_EDGE_PROPERTY_LIST: GrinEdgePropertyList = std::ptr::null_mut(); + pub const GRIN_NULL_EDGE_TYPE_ID: GrinEdgeTypeId = u32::MAX; + pub const GRIN_NULL_EDGE_PROPERTY_ID: GrinEdgePropertyId = u32::MAX; + pub const GRIN_NULL_ROW: GrinRow = std::ptr::null_mut(); + pub const GRIN_NULL_SIZE: u32 = u32::MAX; } else { pub type GrinGraph = *mut ::std::os::raw::c_void; pub type GrinVertex = *mut ::std::os::raw::c_void; @@ -1824,6 +1889,11 @@ extern "C" { arg3: GrinLabel, ) -> GrinEdgeList; + #[doc = " @brief get all the edge types that might have the label\n @param GrinGraph the graph\n @param GrinLabel the label\n @return the edge type list"] + #[cfg(all(feature = "grin_with_edge_label", feature = "grin_with_edge_property"))] + #[allow(unused)] + pub fn grin_get_edge_types_by_label(arg1: GrinGraph, arg2: GrinLabel) -> GrinEdgeTypeList; + #[cfg(feature = "grin_assume_all_vertex_list_sorted")] #[allow(unused)] pub fn grin_smaller_vertex(arg1: GrinGraph, arg2: GrinVertex, arg3: GrinVertex) -> bool; diff --git a/rust/grin_demo_storage.rs b/rust/grin_demo_storage.rs index 236bad9..c14573d 100644 --- a/rust/grin_demo_storage.rs +++ b/rust/grin_demo_storage.rs @@ -76,8 +76,6 @@ pub type GRIN_VERTEX_TYPE_ID = ::std::os::raw::c_uint; pub type GRIN_VERTEX_PROPERTY_ID = ::std::os::raw::c_uint; pub type GRIN_EDGE_TYPE = ::std::os::raw::c_uint; pub type GRIN_EDGE_TYPE_LIST = *mut ::std::os::raw::c_void; -pub type GRIN_VEV_TYPE = ::std::os::raw::c_uint; -pub type GRIN_VEV_TYPE_LIST = *mut ::std::os::raw::c_void; pub type GRIN_EDGE_PROPERTY = ::std::os::raw::c_uint; pub type GRIN_EDGE_PROPERTY_LIST = *mut ::std::os::raw::c_void; pub type GRIN_EDGE_TYPE_ID = ::std::os::raw::c_uint; diff --git a/storage/demo_storage/predefine.h b/storage/demo_storage/predefine.h index 14616b8..b841b7b 100644 --- a/storage/demo_storage/predefine.h +++ b/storage/demo_storage/predefine.h @@ -84,15 +84,6 @@ typedef enum { #define GRIN_ENABLE_VERTEX_REF #define GRIN_TRAIT_FAST_VERTEX_REF #define GRIN_ENABLE_EDGE_REF -#define GRIN_ASSUME_ALL_REPLICATE_PARTITION -// #define GRIN_ASSUME_EDGE_CUT_PARTITION -// #define GRIN_ASSUME_EDGE_CUT_FOLLOW_SRC_PARTITION -// #define GRIN_ASSUME_EDGE_CUT_FOLLOW_DST_PARTITION -// #define GRIN_ASSUME_VERTEX_CUT_PARTITION -// #define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_VERTEX_DATA -#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_VERTEX_DATA -// #define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_EDGE_DATA -#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_EDGE_DATA #define GRIN_TRAIT_MASTER_VERTEX_MIRROR_PARTITION_LIST #define GRIN_TRAIT_MIRROR_VERTEX_MIRROR_PARTITION_LIST #define GRIN_TRAIT_MASTER_EDGE_MIRROR_PARTITION_LIST @@ -118,20 +109,17 @@ typedef enum { #define GRIN_TRAIT_NATURAL_ID_FOR_EDGE_TYPE #define GRIN_ENABLE_EDGE_PRIMARY_KEYS #define GRIN_TRAIT_NATURAL_ID_FOR_EDGE_PROPERTY -#define GRIN_TRAIT_SPECIFIC_VEV_RELATION -// #define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_VERTEX_PROPERTY -#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_VERTEX_PROPERTY -// #define GRIN_ASSUME_SPLIT_MASTER_MIRROR_PARTITION_FOR_VERTEX_PROPERTY -// #define GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_EDGE_PROPERTY -#define GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_EDGE_PROPERTY -// #define GRIN_ASSUME_SPLIT_MASTER_MIRROR_PARTITION_FOR_EDGE_PROPERTY // Index // #define GRIN_WITH_VERTEX_LABEL // #define GRIN_WITH_EDGE_LABEL #define GRIN_ASSUME_ALL_VERTEX_LIST_SORTED #define GRIN_ENABLE_VERTEX_INTERNAL_ID_INDEX +#define GRIN_ENABLE_VERTEX_EXTERNAL_ID_OF_INT64 +#define GRIN_ENABLE_VERTEX_EXTERNAL_ID_OF_STRING #define GRIN_ENABLE_VERTEX_PK_INDEX #define GRIN_ENABLE_EDGE_PK_INDEX +// Common +#define GRIN_TRAIT_LOOSE_SCHEMA /* 3. Define the handles using typedef */ typedef void *GRIN_GRAPH; @@ -206,8 +194,6 @@ typedef unsigned GRIN_VERTEX_PROPERTY_ID; #ifdef GRIN_WITH_EDGE_PROPERTY typedef unsigned GRIN_EDGE_TYPE; typedef void* GRIN_EDGE_TYPE_LIST; -typedef unsigned GRIN_VEV_TYPE; -typedef void* GRIN_VEV_TYPE_LIST; typedef unsigned GRIN_EDGE_PROPERTY; typedef void* GRIN_EDGE_PROPERTY_LIST; #endif @@ -255,8 +241,6 @@ typedef void* GRIN_LABEL_LIST; #define GRIN_NULL_VERTEX_PROPERTY_ID (unsigned)~0 #define GRIN_NULL_EDGE_TYPE (unsigned)~0 #define GRIN_NULL_EDGE_TYPE_LIST NULL -#define GRIN_NULL_VEV_TYPE (unsigned)~0 -#define GRIN_NULL_VEV_TYPE_LIST NULL #define GRIN_NULL_EDGE_PROPERTY (unsigned)~0 #define GRIN_NULL_EDGE_PROPERTY_LIST NULL #define GRIN_NULL_EDGE_TYPE_ID (unsigned)~0 From 0e250bc948d5bbee15ff640902322adea92c18be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Tue, 18 Jul 2023 10:28:04 +0800 Subject: [PATCH 17/48] Update test --- demo_storage/test/test.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/demo_storage/test/test.c b/demo_storage/test/test.c index c272df5..6c66c2b 100644 --- a/demo_storage/test/test.c +++ b/demo_storage/test/test.c @@ -8,6 +8,7 @@ #include "storage/loadmoderngraph.h" // GRIN headers #include "common/error.h" +#include "index/external_id.h" #include "index/internal_id.h" #include "index/label.h" #include "index/order.h" @@ -15,7 +16,6 @@ #include "partition/partition.h" #include "partition/reference.h" #include "partition/topology.h" -#include "property/partition.h" #include "property/primarykey.h" #include "property/property.h" #include "property/propertylist.h" @@ -1013,6 +1013,23 @@ FOR_VERTEX_LIST_END(g, vl) } +void test_index_external_id_of_int64(int argc, char** argv) { + printf("+++++++++++++++++++++ Test index external id +++++++++++++++++++++\n"); + GRIN_GRAPH g = get_graph(argc, argv, 0); + +FOR_VERTEX_LIST_BEGIN(g, vl) + FOR_VERTEX_BEGIN(g, vl, v) + long long int ext_id = grin_get_vertex_external_id_of_int64(g, v); + GRIN_VERTEX v1 = grin_get_vertex_by_external_id_of_int64(g, ext_id); + assert(grin_equal_vertex(g, v, v1)); + grin_destroy_vertex(g, v1); + FOR_VERTEX_END(g, vl, v) +FOR_VERTEX_LIST_END(g, vl) + + grin_destroy_graph(g); +} + + void test_index(int argc, char** argv) { #if defined(GRIN_ASSUME_ALL_VERTEX_LIST_SORTED) && defined(GRIN_ENABLE_VERTEX_LIST_ARRAY) test_index_order(argc, argv); @@ -1020,6 +1037,9 @@ void test_index(int argc, char** argv) { #ifdef GRIN_ENABLE_VERTEX_INTERNAL_ID_INDEX test_index_internal_id(argc, argv); #endif +#ifdef GRIN_ENABLE_VERTEX_EXTERNAL_ID_OF_INT64 + test_index_external_id_of_int64(argc, argv); +#endif } void test_vertex_property_value(int argc, char** argv) { From a419bdc685e124194c9115b4041333f8a8c0a660 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Tue, 18 Jul 2023 11:23:46 +0800 Subject: [PATCH 18/48] Implement external id --- demo_storage/src/index/external_id.cc | 41 +++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 demo_storage/src/index/external_id.cc diff --git a/demo_storage/src/index/external_id.cc b/demo_storage/src/index/external_id.cc new file mode 100644 index 0000000..08906f6 --- /dev/null +++ b/demo_storage/src/index/external_id.cc @@ -0,0 +1,41 @@ +/** Copyright 2020 Alibaba Group Holding Limited. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "src/predefine.h" +// GRIN headers +#include "index/external_id.h" + +#ifdef GRIN_ENABLE_VERTEX_EXTERNAL_ID_OF_INT64 +GRIN_VERTEX grin_get_vertex_by_external_id_of_int64( + GRIN_GRAPH g, long long int id) { // NOLINT + return id; +} + +long long int grin_get_vertex_external_id_of_int64(GRIN_GRAPH g, // NOLINT + GRIN_VERTEX v) { + return v; +} +#endif + +#ifdef GRIN_ENABLE_VERTEX_EXTERNAL_ID_OF_STRING +GRIN_VERTEX grin_get_vertex_by_external_id_of_string(GRIN_GRAPH g, + const char* id) { + return std::stoi(std::string(id)); +} + +const char* grin_get_vertex_external_id_of_string(GRIN_GRAPH g, GRIN_VERTEX v) { + std::string std = std::to_string(v); + char* id = new char[std.length() + 1]; + snprintf(id, std.length() + 1, "%s", std.c_str()); + return id; +} +#endif From 6978343cd68bc348ff43b3b69027b7db914cfa71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Tue, 18 Jul 2023 11:55:15 +0800 Subject: [PATCH 19/48] Disable loose_schema --- demo_storage/predefine.h | 2 +- storage/demo_storage/predefine.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/demo_storage/predefine.h b/demo_storage/predefine.h index b841b7b..6732714 100644 --- a/demo_storage/predefine.h +++ b/demo_storage/predefine.h @@ -119,7 +119,7 @@ typedef enum { #define GRIN_ENABLE_VERTEX_PK_INDEX #define GRIN_ENABLE_EDGE_PK_INDEX // Common -#define GRIN_TRAIT_LOOSE_SCHEMA +// #define GRIN_TRAIT_LOOSE_SCHEMA /* 3. Define the handles using typedef */ typedef void *GRIN_GRAPH; diff --git a/storage/demo_storage/predefine.h b/storage/demo_storage/predefine.h index b841b7b..6732714 100644 --- a/storage/demo_storage/predefine.h +++ b/storage/demo_storage/predefine.h @@ -119,7 +119,7 @@ typedef enum { #define GRIN_ENABLE_VERTEX_PK_INDEX #define GRIN_ENABLE_EDGE_PK_INDEX // Common -#define GRIN_TRAIT_LOOSE_SCHEMA +// #define GRIN_TRAIT_LOOSE_SCHEMA /* 3. Define the handles using typedef */ typedef void *GRIN_GRAPH; From a65501811d6d870f3674b6f39420c05006c45102 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Tue, 18 Jul 2023 15:04:09 +0800 Subject: [PATCH 20/48] Implement part of label --- demo_storage/predefine.h | 8 ++-- demo_storage/src/predefine.h | 11 +++++- demo_storage/storage/storage.cc | 18 +++++++++ demo_storage/storage/storage.h | 68 +++++++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+), 6 deletions(-) diff --git a/demo_storage/predefine.h b/demo_storage/predefine.h index 6732714..eeb90cb 100644 --- a/demo_storage/predefine.h +++ b/demo_storage/predefine.h @@ -110,8 +110,8 @@ typedef enum { #define GRIN_ENABLE_EDGE_PRIMARY_KEYS #define GRIN_TRAIT_NATURAL_ID_FOR_EDGE_PROPERTY // Index -// #define GRIN_WITH_VERTEX_LABEL -// #define GRIN_WITH_EDGE_LABEL +#define GRIN_WITH_VERTEX_LABEL +#define GRIN_WITH_EDGE_LABEL #define GRIN_ASSUME_ALL_VERTEX_LIST_SORTED #define GRIN_ENABLE_VERTEX_INTERNAL_ID_INDEX #define GRIN_ENABLE_VERTEX_EXTERNAL_ID_OF_INT64 @@ -211,7 +211,7 @@ typedef void* GRIN_ROW; #endif #if defined(GRIN_WITH_VERTEX_LABEL) || defined(GRIN_WITH_EDGE_LABEL) -typedef void* GRIN_LABEL; +typedef unsigned GRIN_LABEL; typedef void* GRIN_LABEL_LIST; #endif @@ -246,7 +246,7 @@ typedef void* GRIN_LABEL_LIST; #define GRIN_NULL_EDGE_TYPE_ID (unsigned)~0 #define GRIN_NULL_EDGE_PROPERTY_ID (unsigned)~0 #define GRIN_NULL_ROW NULL -#define GRIN_NULL_LABEL NULL +#define GRIN_NULL_LABEL (unsigned)~0 #define GRIN_NULL_LABEL_LIST NULL #define GRIN_NULL_SIZE (unsigned)~0 #define GRIN_NULL_NAME NULL diff --git a/demo_storage/src/predefine.h b/demo_storage/src/predefine.h index 42109c8..96eb553 100644 --- a/demo_storage/src/predefine.h +++ b/demo_storage/src/predefine.h @@ -34,6 +34,7 @@ typedef std::vector GRIN_EDGE_TYPE_LIST_T; typedef std::vector GRIN_EDGE_PROPERTY_LIST_T; typedef std::vector GRIN_VEV_TYPE_LIST_T; typedef std::vector GRIN_PARTITION_LIST_T; +typedef std::vector GRIN_LABEL_LIST_T; typedef std::vector GRIN_ROW_T; @@ -56,9 +57,11 @@ struct GRIN_VERTEX_LIST_T { PARTITION_TYPE_IN_LIST partition_type; // only used when partition_type is ONE_PARTITION/ALL_BUT_ONE_PARTITION unsigned partition_id; + unsigned label_id; GRIN_VERTEX_LIST_T(unsigned _type_id, PARTITION_TYPE_IN_LIST _partition_type = ALL_PARTITION, - unsigned _partition_id = 0) + unsigned _partition_id = 0, + unsigned _label_id = GRIN_NULL_LABEL) : type_id(_type_id), partition_type(_partition_type), partition_id(_partition_id) {} @@ -69,6 +72,7 @@ struct GRIN_VERTEX_LIST_ITERATOR_T { PARTITION_TYPE_IN_LIST partition_type; // only used when partition_type is ONE_PARTITION/ALL_BUT_ONE_PARTITION unsigned partition_id; + unsigned label_id; int64_t current_offset; GRIN_VERTEX_LIST_ITERATOR_T(unsigned _type_id, PARTITION_TYPE_IN_LIST _partition_type, @@ -84,9 +88,11 @@ struct GRIN_EDGE_LIST_T { PARTITION_TYPE_IN_LIST partition_type; // only used when partition_type is ONE_PARTITION/ALL_BUT_ONE_PARTITION unsigned partition_id; + unsigned label_id; GRIN_EDGE_LIST_T(unsigned _type_id, PARTITION_TYPE_IN_LIST _partition_type = ALL_PARTITION, - unsigned _partition_id = 0) + unsigned _partition_id = 0, + unsigned _label_id = GRIN_NULL_LABEL) : type_id(_type_id), partition_type(_partition_type), partition_id(_partition_id) {} @@ -97,6 +103,7 @@ struct GRIN_EDGE_LIST_ITERATOR_T { PARTITION_TYPE_IN_LIST partition_type; // only used when partition_type is ONE_PARTITION/ALL_BUT_ONE_PARTITION unsigned partition_id; + unsigned label_id; int64_t current_offset; GRIN_EDGE_LIST_ITERATOR_T(unsigned _type_id, PARTITION_TYPE_IN_LIST _partition_type, diff --git a/demo_storage/storage/storage.cc b/demo_storage/storage/storage.cc index f8de662..d8ec5b9 100644 --- a/demo_storage/storage/storage.cc +++ b/demo_storage/storage/storage.cc @@ -51,6 +51,15 @@ void Graph::AddVertex(Vertex& vertex) noexcept { // NOLINT std::string oid = vertex.GetOid(); oid_string_2_gid_[oid] = gid; } + + // labels + auto& labels = vertex.GetLabels(); + for (auto& label : labels) { + AddVertexLabel(label); + vertex_label_2_type_id_[vertex_label_2_id_[label]].insert(type_id); + label_vertex_ids_[std::make_pair(type_id, vertex_label_2_id_[label])] + .push_back(gid); + } } void Graph::AddEdge(Edge& edge) noexcept { // NOLINT @@ -88,6 +97,15 @@ void Graph::AddEdge(Edge& edge) noexcept { // NOLINT dest_partition_id)] .push_back(edge.GetGid()); } + + // labels + auto& labels = edge.GetLabels(); + for (auto& label : labels) { + AddEdgeLabel(label); + edge_label_2_type_id_[edge_label_2_id_[label]].insert(type_id); + label_edge_ids_[std::make_pair(type_id, edge_label_2_id_[label])].push_back( + edge.GetGid()); + } } Graph* DemoStorage::load_modern_graph(const std::string& name, diff --git a/demo_storage/storage/storage.h b/demo_storage/storage/storage.h index 7f49d55..ee04b23 100644 --- a/demo_storage/storage/storage.h +++ b/demo_storage/storage/storage.h @@ -312,6 +312,45 @@ class Graph { return edge_property_2_id_[etype].at(name); } + // get labels + size_t GetVertexLabelNum() const noexcept { return vertex_labels_.size(); } + size_t GetEdgeLabelNum() const noexcept { return edge_labels_.size(); } + const std::string& GetVertexLabelName(uint32_t label_id) const noexcept { + return vertex_labels_[label_id]; + } + const std::string& GetEdgeLabelName(uint32_t label_id) const noexcept { + return edge_labels_[label_id]; + } + int32_t GetVertexLabelId(std::string label) const noexcept { + if (vertex_label_2_id_.find(label) == vertex_label_2_id_.end()) { + return -1; + } + return vertex_label_2_id_.at(label); + } + int32_t GetEdgeLabelId(std::string label) const noexcept { + if (edge_label_2_id_.find(label) == edge_label_2_id_.end()) { + return -1; + } + return edge_label_2_id_.at(label); + } + int32_t GetLabelId(std::string label) const noexcept { + if (vertex_label_2_id_.find(label) != vertex_label_2_id_.end()) { + return vertex_label_2_id_.at(label); + } + if (edge_label_2_id_.find(label) != edge_label_2_id_.end()) { + return edge_label_2_id_.at(label) + vertex_labels_.size(); + } + return -1; + } + const std::set& GetVertexTypesByLabel(uint32_t label_id) const + noexcept { + return vertex_label_2_type_id_[label_id]; + } + const std::set& GetEdgeTypesByLabel(uint32_t label_id) const + noexcept { + return edge_label_2_type_id_[label_id]; + } + // get vertex & edge number size_t GetVertexNum(uint32_t type_id) const noexcept { if (type_id >= vertices_.size()) { @@ -509,6 +548,24 @@ class Graph { } } + // add labels + void AddVertexLabel(const std::string& label) noexcept { + if (vertex_label_2_id_.find(label) == vertex_label_2_id_.end()) { + vertex_label_2_id_[label] = vertex_labels_.size(); + vertex_labels_.push_back(label); + std::set tmp; + vertex_label_2_type_id_.push_back(tmp); + } + } + void AddEdgeLabel(const std::string& label) noexcept { + if (edge_label_2_id_.find(label) == edge_label_2_id_.end()) { + edge_label_2_id_[label] = edge_labels_.size(); + edge_labels_.push_back(label); + std::set tmp; + edge_label_2_type_id_.push_back(tmp); + } + } + // add vertices and edges void AddVertex(Vertex& vertex) noexcept; // NOLINT void AddEdge(Edge& edge) noexcept; // NOLINT @@ -530,6 +587,17 @@ class Graph { // vertices and edges std::vector> vertices_; std::vector> edges_; + // labels + std::vector vertex_labels_, edge_labels_; + std::map vertex_label_2_id_, edge_label_2_id_; + std::vector> vertex_label_2_type_id_, + edge_label_2_type_id_; + // label indices: label_vertex_ids_[label][partition_id] = vector of global + // vid label_edge_ids_[label][partition_id] = vector of global eid + std::map, std::vector> + label_vertex_ids_; + std::map, std::vector> + label_edge_ids_; // adj_list_[(vtype, vid, partition_id)] = vector of global eid for edges std::map, std::vector> From f667a1ab3136866079eeb1366d4502b67e2eef73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Tue, 18 Jul 2023 17:04:25 +0800 Subject: [PATCH 21/48] Implement vertexlist & edgelist (array-like) to support label --- demo_storage/src/predefine.h | 14 ++++++--- demo_storage/src/topology/edgelist.cc | 24 +++++++++++++--- demo_storage/src/topology/vertexlist.cc | 24 +++++++++++++--- demo_storage/storage/storage.cc | 32 ++++++++++++++++----- demo_storage/storage/storage.h | 38 +++++++++++++++++++++++-- 5 files changed, 110 insertions(+), 22 deletions(-) diff --git a/demo_storage/src/predefine.h b/demo_storage/src/predefine.h index 96eb553..796003b 100644 --- a/demo_storage/src/predefine.h +++ b/demo_storage/src/predefine.h @@ -64,7 +64,8 @@ struct GRIN_VERTEX_LIST_T { unsigned _label_id = GRIN_NULL_LABEL) : type_id(_type_id), partition_type(_partition_type), - partition_id(_partition_id) {} + partition_id(_partition_id), + label_id(_label_id) {} }; struct GRIN_VERTEX_LIST_ITERATOR_T { @@ -76,10 +77,12 @@ struct GRIN_VERTEX_LIST_ITERATOR_T { int64_t current_offset; GRIN_VERTEX_LIST_ITERATOR_T(unsigned _type_id, PARTITION_TYPE_IN_LIST _partition_type, - unsigned _partition_id, int64_t _current_offset) + unsigned _partition_id, unsigned _label_id, + int64_t _current_offset) : type_id(_type_id), partition_type(_partition_type), partition_id(_partition_id), + label_id(_label_id), current_offset(_current_offset) {} }; @@ -95,7 +98,8 @@ struct GRIN_EDGE_LIST_T { unsigned _label_id = GRIN_NULL_LABEL) : type_id(_type_id), partition_type(_partition_type), - partition_id(_partition_id) {} + partition_id(_partition_id), + label_id(_label_id) {} }; struct GRIN_EDGE_LIST_ITERATOR_T { @@ -107,10 +111,12 @@ struct GRIN_EDGE_LIST_ITERATOR_T { int64_t current_offset; GRIN_EDGE_LIST_ITERATOR_T(unsigned _type_id, PARTITION_TYPE_IN_LIST _partition_type, - unsigned _partition_id, int64_t _current_offset) + unsigned _partition_id, unsigned _label_id, + int64_t _current_offset) : type_id(_type_id), partition_type(_partition_type), partition_id(_partition_id), + label_id(_label_id), current_offset(_current_offset) {} }; diff --git a/demo_storage/src/topology/edgelist.cc b/demo_storage/src/topology/edgelist.cc index 5b3402c..677cb72 100644 --- a/demo_storage/src/topology/edgelist.cc +++ b/demo_storage/src/topology/edgelist.cc @@ -33,9 +33,14 @@ size_t grin_get_edge_list_size(GRIN_GRAPH g, GRIN_EDGE_LIST el) { auto _g = static_cast(g); auto _el = static_cast(el); auto etype = _el->type_id; + auto label = _el->label_id; if (etype >= _g->GetEdgeTypeNum()) return GRIN_NULL_SIZE; + if (label != GRIN_NULL_LABEL) { + return _g->GetEdgeNumByLabel(etype, label); + } + if (_el->partition_type == ALL_PARTITION) { return _g->GetEdgeNum(etype); } else if (_el->partition_type == ONE_PARTITION) { @@ -52,8 +57,18 @@ GRIN_EDGE grin_get_edge_from_list(GRIN_GRAPH g, GRIN_EDGE_LIST el, size_t idx) { auto _g = static_cast(g); auto _el = static_cast(el); auto etype = _el->type_id; + auto label = _el->label_id; auto num = _g->GetEdgeNum(etype); + if (label != GRIN_NULL_LABEL) { + auto& edges = _g->GetEdgeIdsByLabel(etype, label); + if (idx < edges.size()) { + return edges[idx]; + } else { + return GRIN_NULL_EDGE; + } + } + if (_el->partition_type == ALL_PARTITION) { if (idx < num) { return DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id(etype, @@ -99,7 +114,8 @@ GRIN_EDGE_LIST_ITERATOR grin_get_edge_list_begin(GRIN_GRAPH g, auto etype = _el->type_id; if (_el->partition_type == ALL_PARTITION) { - return new GRIN_EDGE_LIST_ITERATOR_T(etype, ALL_PARTITION, 0, 0); + return new GRIN_EDGE_LIST_ITERATOR_T(etype, ALL_PARTITION, 0, + GRIN_NULL_LABEL, 0); } auto num = _g->GetEdgeNum(etype); @@ -111,7 +127,7 @@ GRIN_EDGE_LIST_ITERATOR grin_get_edge_list_begin(GRIN_GRAPH g, if (_offset >= num) _offset = -1; return new GRIN_EDGE_LIST_ITERATOR_T(etype, ONE_PARTITION, partition_id, - _offset); + GRIN_NULL_LABEL, _offset); } if (_el->partition_type == ALL_BUT_ONE_PARTITION) { @@ -120,8 +136,8 @@ GRIN_EDGE_LIST_ITERATOR grin_get_edge_list_begin(GRIN_GRAPH g, _offset++; if (_offset >= num) _offset = -1; - return new GRIN_EDGE_LIST_ITERATOR_T(etype, ALL_BUT_ONE_PARTITION, - partition_id, _offset); + return new GRIN_EDGE_LIST_ITERATOR_T( + etype, ALL_BUT_ONE_PARTITION, partition_id, GRIN_NULL_LABEL, _offset); } return GRIN_NULL_EDGE_LIST_ITERATOR; diff --git a/demo_storage/src/topology/vertexlist.cc b/demo_storage/src/topology/vertexlist.cc index f6d35c8..94e711f 100644 --- a/demo_storage/src/topology/vertexlist.cc +++ b/demo_storage/src/topology/vertexlist.cc @@ -33,9 +33,14 @@ size_t grin_get_vertex_list_size(GRIN_GRAPH g, GRIN_VERTEX_LIST vl) { auto _g = static_cast(g); auto _vl = static_cast(vl); auto vtype = _vl->type_id; + auto label = _vl->label_id; if (vtype >= _g->GetVertexTypeNum()) GRIN_NULL_SIZE; + if (label != GRIN_NULL_LABEL) { + return _g->GetVertexNumByLabel(vtype, label); + } + if (_vl->partition_type == ALL_PARTITION) { return _g->GetVertexNum(vtype); } else if (_vl->partition_type == ONE_PARTITION) { @@ -53,8 +58,18 @@ GRIN_VERTEX grin_get_vertex_from_list(GRIN_GRAPH g, GRIN_VERTEX_LIST vl, auto _g = static_cast(g); auto _vl = static_cast(vl); auto vtype = _vl->type_id; + auto label = _vl->label_id; auto num = _g->GetVertexNum(vtype); + if (label != GRIN_NULL_LABEL) { + auto& vertices = _g->GetVertexIdsByLabel(vtype, label); + if (idx < vertices.size()) { + return vertices[idx]; + } else { + return GRIN_NULL_VERTEX; + } + } + if (_vl->partition_type == ALL_PARTITION) { if (idx < num) { return DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id(vtype, @@ -101,7 +116,8 @@ GRIN_VERTEX_LIST_ITERATOR grin_get_vertex_list_begin(GRIN_GRAPH g, auto vtype = _vl->type_id; if (_vl->partition_type == ALL_PARTITION) { - return new GRIN_VERTEX_LIST_ITERATOR_T(vtype, ALL_PARTITION, 0, 0); + return new GRIN_VERTEX_LIST_ITERATOR_T(vtype, ALL_PARTITION, 0, + GRIN_NULL_LABEL, 0); } auto num = _g->GetVertexNum(vtype); @@ -113,7 +129,7 @@ GRIN_VERTEX_LIST_ITERATOR grin_get_vertex_list_begin(GRIN_GRAPH g, if (_offset >= num) _offset = -1; return new GRIN_VERTEX_LIST_ITERATOR_T(vtype, ONE_PARTITION, partition_id, - _offset); + GRIN_NULL_LABEL, _offset); } if (_vl->partition_type == ALL_BUT_ONE_PARTITION) { @@ -122,8 +138,8 @@ GRIN_VERTEX_LIST_ITERATOR grin_get_vertex_list_begin(GRIN_GRAPH g, _offset++; if (_offset >= num) _offset = -1; - return new GRIN_VERTEX_LIST_ITERATOR_T(vtype, ALL_BUT_ONE_PARTITION, - partition_id, _offset); + return new GRIN_VERTEX_LIST_ITERATOR_T( + vtype, ALL_BUT_ONE_PARTITION, partition_id, GRIN_NULL_LABEL, _offset); } return GRIN_NULL_VERTEX_LIST_ITERATOR; diff --git a/demo_storage/storage/storage.cc b/demo_storage/storage/storage.cc index d8ec5b9..ee8e67d 100644 --- a/demo_storage/storage/storage.cc +++ b/demo_storage/storage/storage.cc @@ -56,9 +56,11 @@ void Graph::AddVertex(Vertex& vertex) noexcept { // NOLINT auto& labels = vertex.GetLabels(); for (auto& label : labels) { AddVertexLabel(label); - vertex_label_2_type_id_[vertex_label_2_id_[label]].insert(type_id); - label_vertex_ids_[std::make_pair(type_id, vertex_label_2_id_[label])] - .push_back(gid); + auto label_id = vertex_label_2_id_[label]; + vertex_label_2_type_id_[label_id].insert(type_id); + vertex_pos_in_type_and_label_[std::make_tuple(type_id, label_id, gid)] = + label_vertex_ids_[std::make_pair(type_id, label_id)].size(); + label_vertex_ids_[std::make_pair(type_id, label_id)].push_back(gid); } } @@ -155,7 +157,11 @@ Graph* DemoStorage::load_modern_graph(const std::string& name, v.AddProperty("id", v_0_id[i]); v.AddProperty("name", v_0_name[i]); v.AddProperty("age", v_0_age[i]); - v.AddLabel("person"); + v.AddLabel("person_label"); + if (i % 2 == 0) + v.AddLabel("v_label_0"); + else + v.AddLabel("v_label_1"); graph->AddVertex(v); } for (int64_t i = 0; i < 2; i++) { @@ -164,7 +170,11 @@ Graph* DemoStorage::load_modern_graph(const std::string& name, v.AddProperty("id", v_1_id[i]); v.AddProperty("name", v_1_name[i]); v.AddProperty("lang", v_1_lang[i]); - v.AddLabel("software"); + v.AddLabel("software_label"); + if (i % 2 == 0) + v.AddLabel("v_label_0"); + else + v.AddLabel("v_label_1"); graph->AddVertex(v); } @@ -179,14 +189,22 @@ Graph* DemoStorage::load_modern_graph(const std::string& name, Edge e = graph->ConstructEdgeFromVertexOid(0, e_0_src[i], e_0_dst[i], i); e.SetEData(GRIN_DATATYPE::Double, e_0_weight[i]); e.AddProperty("weight", e_0_weight[i]); - e.AddLabel("knows"); + e.AddLabel("knows_label"); + if (i % 2 == 0) + e.AddLabel("e_label_0"); + else + e.AddLabel("e_label_1"); graph->AddEdge(e); } for (int64_t i = 0; i < 4; i++) { Edge e = graph->ConstructEdgeFromVertexOid(1, e_1_src[i], e_1_dst[i], i); e.SetEData(GRIN_DATATYPE::Double, e_1_weight[i]); e.AddProperty("weight", e_1_weight[i]); - e.AddLabel("created"); + e.AddLabel("created_label"); + if (i % 2 == 0) + e.AddLabel("e_label_0"); + else + e.AddLabel("e_label_1"); graph->AddEdge(e); } diff --git a/demo_storage/storage/storage.h b/demo_storage/storage/storage.h index ee04b23..2e3d09a 100644 --- a/demo_storage/storage/storage.h +++ b/demo_storage/storage/storage.h @@ -17,7 +17,6 @@ limitations under the License. #define STORAGE_STORAGE_H_ #include -#include #include #include #include @@ -382,6 +381,20 @@ class Graph { } return res; } + size_t GetVertexNumByLabel(uint32_t type_id, uint32_t label_id) { + std::pair tmp = std::make_pair(type_id, label_id); + if (label_vertex_ids_.find(tmp) == label_vertex_ids_.end()) { + return 0; + } + return label_vertex_ids_[tmp].size(); + } + size_t GetEdgeNumByLabel(uint32_t type_id, uint32_t label_id) { + std::pair tmp = std::make_pair(type_id, label_id); + if (label_edge_ids_.find(tmp) == label_edge_ids_.end()) { + return 0; + } + return label_edge_ids_[tmp].size(); + } // get vertices, edges, and adjacent lists const Vertex& GetVertex(int64_t gid) const { @@ -400,6 +413,21 @@ class Graph { const std::vector& GetEdges(uint32_t type_id) const { return edges_[type_id]; } + const std::vector& GetVertexIdsByLabel(uint32_t type_id, + uint32_t label_id) { + std::pair tmp = std::make_pair(type_id, label_id); + return label_vertex_ids_[tmp]; + } + const std::vector& GetEdgeIdsByLabel(uint32_t type_id, + uint32_t label_id) { + std::pair tmp = std::make_pair(type_id, label_id); + return label_edge_ids_[tmp]; + } + size_t GetVertexPositionInTypeAndLabel(uint32_t type_id, uint32_t label_id, + int64_t gid) { + std::tuple tmp = std::make_tuple(type_id, label_id, gid); + return vertex_pos_in_type_and_label_[tmp]; + } size_t GetAdjacentListSize(uint32_t vtype_id, int64_t vid, uint32_t etype_id, uint32_t partition_id, GRIN_DIRECTION dir) { size_t size = 0; @@ -592,12 +620,16 @@ class Graph { std::map vertex_label_2_id_, edge_label_2_id_; std::vector> vertex_label_2_type_id_, edge_label_2_type_id_; - // label indices: label_vertex_ids_[label][partition_id] = vector of global - // vid label_edge_ids_[label][partition_id] = vector of global eid + // label indices: + // label_vertex_ids_[label][partition_id] = vector of global vid std::map, std::vector> label_vertex_ids_; + // label_edge_ids_[label][partition_id] = vector of global eid std::map, std::vector> label_edge_ids_; + // vertex_pos_in_type_and_label_[(vtype, label, gid)] = position + std::map, size_t> + vertex_pos_in_type_and_label_; // adj_list_[(vtype, vid, partition_id)] = vector of global eid for edges std::map, std::vector> From a6c8ef7fae940e7e98b7cd3040bde90059772634 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Wed, 19 Jul 2023 14:17:37 +0800 Subject: [PATCH 22/48] Implement vertexlist & edgelist (iter-like) to support label --- demo_storage/src/topology/edgelist.cc | 18 +++++++++++++----- demo_storage/src/topology/vertexlist.cc | 18 +++++++++++++----- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/demo_storage/src/topology/edgelist.cc b/demo_storage/src/topology/edgelist.cc index 677cb72..9495ed4 100644 --- a/demo_storage/src/topology/edgelist.cc +++ b/demo_storage/src/topology/edgelist.cc @@ -112,10 +112,10 @@ GRIN_EDGE_LIST_ITERATOR grin_get_edge_list_begin(GRIN_GRAPH g, auto _g = static_cast(g); auto _el = static_cast(el); auto etype = _el->type_id; + auto label = _el->label_id; if (_el->partition_type == ALL_PARTITION) { - return new GRIN_EDGE_LIST_ITERATOR_T(etype, ALL_PARTITION, 0, - GRIN_NULL_LABEL, 0); + return new GRIN_EDGE_LIST_ITERATOR_T(etype, ALL_PARTITION, 0, label, 0); } auto num = _g->GetEdgeNum(etype); @@ -152,7 +152,9 @@ void grin_get_next_edge_list_iter(GRIN_GRAPH g, GRIN_EDGE_LIST_ITERATOR eli) { auto _g = static_cast(g); auto _eli = static_cast(eli); auto etype = _eli->type_id; - auto num = _g->GetEdgeNum(etype); + auto label = _eli->label_id; + auto num = label == GRIN_NULL_LABEL ? _g->GetEdgeNum(etype) + : _g->GetEdgeNumByLabel(etype, label); if (_eli->partition_type == ALL_PARTITION) { _eli->current_offset++; @@ -194,8 +196,14 @@ bool grin_is_edge_list_end(GRIN_GRAPH g, GRIN_EDGE_LIST_ITERATOR eli) { } GRIN_EDGE grin_get_edge_from_iter(GRIN_GRAPH g, GRIN_EDGE_LIST_ITERATOR eli) { + auto _g = static_cast(g); auto _eli = static_cast(eli); - return DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id( - _eli->type_id, _eli->current_offset); + if (_eli->label_id != GRIN_NULL_LABEL) { + return _g->GetEdgeIdsByLabel(_eli->type_id, + _eli->label_id)[_eli->current_offset]; + } else { + return DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id( + _eli->type_id, _eli->current_offset); + } } #endif diff --git a/demo_storage/src/topology/vertexlist.cc b/demo_storage/src/topology/vertexlist.cc index 94e711f..ddd8935 100644 --- a/demo_storage/src/topology/vertexlist.cc +++ b/demo_storage/src/topology/vertexlist.cc @@ -114,10 +114,10 @@ GRIN_VERTEX_LIST_ITERATOR grin_get_vertex_list_begin(GRIN_GRAPH g, auto _g = static_cast(g); auto _vl = static_cast(vl); auto vtype = _vl->type_id; + auto label = _vl->label_id; if (_vl->partition_type == ALL_PARTITION) { - return new GRIN_VERTEX_LIST_ITERATOR_T(vtype, ALL_PARTITION, 0, - GRIN_NULL_LABEL, 0); + return new GRIN_VERTEX_LIST_ITERATOR_T(vtype, ALL_PARTITION, 0, label, 0); } auto num = _g->GetVertexNum(vtype); @@ -156,7 +156,9 @@ void grin_get_next_vertex_list_iter(GRIN_GRAPH g, auto _g = static_cast(g); auto _vli = static_cast(vli); auto vtype = _vli->type_id; - auto num = _g->GetVertexNum(vtype); + auto label = _vli->label_id; + auto num = label == GRIN_NULL_LABEL ? _g->GetVertexNum(vtype) + : _g->GetVertexNumByLabel(vtype, label); if (_vli->partition_type == ALL_PARTITION) { _vli->current_offset++; @@ -199,8 +201,14 @@ bool grin_is_vertex_list_end(GRIN_GRAPH g, GRIN_VERTEX_LIST_ITERATOR vli) { GRIN_VERTEX grin_get_vertex_from_iter(GRIN_GRAPH g, GRIN_VERTEX_LIST_ITERATOR vli) { + auto _g = static_cast(g); auto _vli = static_cast(vli); - return DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id( - _vli->type_id, _vli->current_offset); + if (_vli->label_id != GRIN_NULL_LABEL) { + return _g->GetVertexIdsByLabel(_vli->type_id, + _vli->label_id)[_vli->current_offset]; + } else { + return DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id( + _vli->type_id, _vli->current_offset); + } } #endif From d5c88b3fdbb3e6ded4296d1f858577509b7ed818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Tue, 25 Jul 2023 09:38:36 +0800 Subject: [PATCH 23/48] Implement label related API --- demo_storage/src/index/label.cc | 157 ++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 demo_storage/src/index/label.cc diff --git a/demo_storage/src/index/label.cc b/demo_storage/src/index/label.cc new file mode 100644 index 0000000..47a4eaf --- /dev/null +++ b/demo_storage/src/index/label.cc @@ -0,0 +1,157 @@ +/** Copyright 2020 Alibaba Group Holding Limited. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "src/predefine.h" +// GRIN headers +#include "index/label.h" + +#if defined(GRIN_WITH_VERTEX_LABEL) || defined(GRIN_WITH_EDGE_LABEL) +size_t grin_get_label_list_size(GRIN_GRAPH g, GRIN_LABEL_LIST ll) { + auto _ll = static_cast(ll); + return _ll->size(); +} + +GRIN_LABEL grin_get_label_from_list(GRIN_GRAPH g, GRIN_LABEL_LIST ll, + size_t idx) { + auto _ll = static_cast(ll); + if (idx >= _ll->size()) { + return GRIN_NULL_LABEL; + } + return _ll->at(idx); +} + +GRIN_LABEL grin_get_label_by_name(GRIN_GRAPH g, const char* name) { + auto _g = static_cast(g); + auto idx = _g->GetLabelId(std::string(name)); + if (idx == -1) { + return GRIN_NULL_LABEL; + } + return idx; +} + +const char* grin_get_label_name(GRIN_GRAPH g, GRIN_LABEL label) { + auto _g = static_cast(g); + if (label < _g->GetVertexLabelNum()) { + return _g->GetVertexLabelName(label).c_str(); + } else if (label < _g->GetVertexLabelNum() + _g->GetEdgeLabelNum()) { + return _g->GetEdgeLabelName(label - _g->GetVertexLabelNum()).c_str(); + } else { + return nullptr; + } +} + +void grin_destroy_label(GRIN_GRAPH g, GRIN_LABEL label) { return; } + +void grin_destroy_label_list(GRIN_GRAPH g, GRIN_LABEL_LIST ll) { + auto _ll = static_cast(ll); + delete _ll; +} +#endif + +#ifdef GRIN_WITH_VERTEX_LABEL +GRIN_LABEL_LIST grin_get_vertex_label_list(GRIN_GRAPH g) { + auto _g = static_cast(g); + auto ll = new GRIN_LABEL_LIST_T(); + for (auto i = 0; i < _g->GetVertexLabelNum(); ++i) { + ll->push_back(i); + } + return ll; +} + +GRIN_LABEL_LIST grin_get_label_list_by_vertex(GRIN_GRAPH g, GRIN_VERTEX v) { + auto _g = static_cast(g); + auto& _v = _g->GetVertex(v); + auto ll = new GRIN_LABEL_LIST_T(); + auto& labels = _v.GetLabels(); + for (auto& label : labels) { + ll->push_back(_g->GetVertexLabelId(label)); + } + return ll; +} +#endif + +#if defined(GRIN_WITH_VERTEX_LABEL) && !defined(GRIN_WITH_VERTEX_PROPERTY) +GRIN_VERTEX_LIST grin_get_vertex_list_by_label(GRIN_GRAPH, GRIN_LABEL); +#endif + +#if defined(GRIN_WITH_VERTEX_LABEL) && defined(GRIN_WITH_VERTEX_PROPERTY) +GRIN_VERTEX_LIST grin_get_vertex_list_by_type_by_label(GRIN_GRAPH g, + GRIN_VERTEX_TYPE vtype, + GRIN_LABEL label) { + auto _g = static_cast(g); + if (vtype >= _g->GetVertexTypeNum()) + return GRIN_NULL_VERTEX_LIST; + auto vl = new GRIN_VERTEX_LIST_T(vtype, ALL_PARTITION, 0, label); + return vl; +} + +GRIN_VERTEX_TYPE_LIST grin_get_vertex_type_list_by_label(GRIN_GRAPH g, + GRIN_LABEL label) { + auto _g = static_cast(g); + auto vtl = new GRIN_VERTEX_TYPE_LIST_T(); + auto& vtypes = _g->GetVertexTypesByLabel(label); + for (auto& vtype : vtypes) { + vtl->push_back(vtype); + } + return vtl; +} +#endif + +#ifdef GRIN_WITH_EDGE_LABEL +GRIN_LABEL_LIST grin_get_edge_label_list(GRIN_GRAPH g) { + auto _g = static_cast(g); + auto ll = new GRIN_LABEL_LIST_T(); + for (auto i = 0; i < _g->GetEdgeLabelNum(); ++i) { + ll->push_back(i + _g->GetVertexLabelNum()); + } + return ll; +} + +GRIN_LABEL_LIST grin_get_label_list_by_edge(GRIN_GRAPH g, GRIN_EDGE e) { + auto _g = static_cast(g); + auto& _e = _g->GetEdge(e); + auto ll = new GRIN_LABEL_LIST_T(); + auto& labels = _e.GetLabels(); + for (auto& label : labels) { + ll->push_back(_g->GetEdgeLabelId(label) + _g->GetVertexLabelNum()); + } + return ll; +} +#endif + +#if defined(GRIN_WITH_EDGE_LABEL) && !defined(GRIN_WITH_EDGE_PROPERTY) +GRIN_EDGE_LIST grin_get_edge_list_by_label(GRIN_GRAPH, GRIN_LABEL); +#endif + +#if defined(GRIN_WITH_EDGE_LABEL) && defined(GRIN_WITH_EDGE_PROPERTY) +GRIN_EDGE_LIST grin_get_edge_list_by_type_by_label(GRIN_GRAPH g, + GRIN_EDGE_TYPE etype, + GRIN_LABEL label) { + auto _g = static_cast(g); + if (etype >= _g->GetEdgeTypeNum()) + return GRIN_NULL_EDGE_LIST; + auto el = new GRIN_EDGE_LIST_T(etype, ALL_PARTITION, 0, + label - _g->GetVertexLabelNum()); + return el; +} + +GRIN_EDGE_TYPE_LIST grin_get_edge_type_list_by_label(GRIN_GRAPH g, + GRIN_LABEL label) { + auto _g = static_cast(g); + auto etl = new GRIN_EDGE_TYPE_LIST_T(); + auto& etypes = _g->GetEdgeTypesByLabel(label - _g->GetVertexLabelNum()); + for (auto& etype : etypes) { + etl->push_back(etype); + } + return etl; +} +#endif From a0fd6a01a29c94bc5b6bc5bc1fa62ba7b1d14206 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Tue, 26 Sep 2023 14:18:42 +0800 Subject: [PATCH 24/48] Implement index --- demo_storage/src/index/internal_id.cc | 58 +++++++ demo_storage/src/index/order.cc | 62 +++++++ demo_storage/src/index/pk.cc | 234 ++++++++++++++++++++++++++ 3 files changed, 354 insertions(+) create mode 100644 demo_storage/src/index/internal_id.cc create mode 100644 demo_storage/src/index/order.cc create mode 100644 demo_storage/src/index/pk.cc diff --git a/demo_storage/src/index/internal_id.cc b/demo_storage/src/index/internal_id.cc new file mode 100644 index 0000000..cabc198 --- /dev/null +++ b/demo_storage/src/index/internal_id.cc @@ -0,0 +1,58 @@ +/** Copyright 2020 Alibaba Group Holding Limited. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "src/predefine.h" +// GRIN headers +#include "index/internal_id.h" + +#if defined(GRIN_ENABLE_VERTEX_INTERNAL_ID_INDEX) && \ + !defined(GRIN_WITH_VERTEX_PROPERTY) +long long int grin_get_vertex_internal_id(GRIN_GRAPH, GRIN_VERTEX); // NOLINT + +GRIN_VERTEX grin_get_vertex_by_internal_id(GRIN_GRAPH, + long long int id); // NOLINT + +long long int grin_get_vertex_internal_id_upper_bound(GRIN_GRAPH); // NOLINT + +long long int grin_get_vertex_internal_id_lower_bound(GRIN_GRAPH); // NOLINT +#endif + +#if defined(GRIN_ENABLE_VERTEX_INTERNAL_ID_INDEX) && \ + defined(GRIN_WITH_VERTEX_PROPERTY) + +long long int grin_get_vertex_internal_id_by_type(GRIN_GRAPH g, // NOLINT + GRIN_VERTEX_TYPE vtype, + GRIN_VERTEX v) { + return DEMO_STORAGE_NAMESPACE::get_id_from_gid(v); +} + +GRIN_VERTEX grin_get_vertex_by_internal_id_by_type( + GRIN_GRAPH g, GRIN_VERTEX_TYPE vtype, + long long int id) { // NOLINT + auto _g = static_cast(g); + if (vtype >= _g->GetVertexTypeNum() || id >= _g->GetVertexNum(vtype)) { + return GRIN_NULL_VERTEX; + } + return DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id(vtype, id); +} + +long long int grin_get_vertex_internal_id_upper_bound_by_type( // NOLINT + GRIN_GRAPH g, GRIN_VERTEX_TYPE vtype) { + auto _g = static_cast(g); + return _g->GetVertexNum(vtype); +} + +long long int grin_get_vertex_internal_id_lower_bound_by_type( // NOLINT + GRIN_GRAPH g, GRIN_VERTEX_TYPE vtype) { + return 0; +} +#endif diff --git a/demo_storage/src/index/order.cc b/demo_storage/src/index/order.cc new file mode 100644 index 0000000..497e817 --- /dev/null +++ b/demo_storage/src/index/order.cc @@ -0,0 +1,62 @@ +/** Copyright 2020 Alibaba Group Holding Limited. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "src/predefine.h" +// GRIN headers +#include "index/order.h" + +#ifdef GRIN_ASSUME_ALL_VERTEX_LIST_SORTED +bool grin_smaller_vertex(GRIN_GRAPH g, GRIN_VERTEX v1, GRIN_VERTEX v2) { + return v1 < v2; +} +#endif + +#if defined(GRIN_ASSUME_ALL_VERTEX_LIST_SORTED) && \ + defined(GRIN_ENABLE_VERTEX_LIST_ARRAY) +size_t grin_get_position_of_vertex_from_sorted_list(GRIN_GRAPH g, + GRIN_VERTEX_LIST vl, + GRIN_VERTEX v) { + auto _g = static_cast(g); + auto _vl = static_cast(vl); + auto vtype = DEMO_STORAGE_NAMESPACE::get_type_id_from_gid(v); + auto vid = DEMO_STORAGE_NAMESPACE::get_id_from_gid(v); + if (vtype != _vl->type_id) { + return -1; + } + if (_vl->label_id != GRIN_NULL_LABEL) { + return _g->GetVertexPositionInTypeAndLabel(vtype, _vl->label_id, v); + } + if (_vl->partition_type == ALL_PARTITION) { + return vid; + } else if (_vl->partition_type == ONE_PARTITION) { + auto partition_id = _g->GetMasterPartitionIdFromVertexGid(v); + auto partition_num = _g->GetPartitionNum(); + if (partition_id != _vl->partition_id) { + return -1; + } + return vid / partition_num; + } else if (_vl->partition_type == ALL_BUT_ONE_PARTITION) { + auto partition_id = _g->GetMasterPartitionIdFromVertexGid(v); + auto partition_num = _g->GetPartitionNum(); + if (partition_id == _vl->partition_id) { + return -1; + } + size_t pos = + (vid / partition_num) * (partition_num - 1) + vid % partition_num; + if (partition_id > _vl->partition_id) { + pos -= 1; + } + return pos; + } + return -1; +} +#endif diff --git a/demo_storage/src/index/pk.cc b/demo_storage/src/index/pk.cc new file mode 100644 index 0000000..0881653 --- /dev/null +++ b/demo_storage/src/index/pk.cc @@ -0,0 +1,234 @@ +/** Copyright 2020 Alibaba Group Holding Limited. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "src/predefine.h" +// GRIN headers +#include "index/pk.h" +#include "property/primarykey.h" +#include "property/property.h" +#include "property/propertylist.h" +#include "property/row.h" + +#if defined(GRIN_ENABLE_VERTEX_PK_INDEX) && \ + defined(GRIN_ENABLE_VERTEX_PRIMARY_KEYS) + +GRIN_VERTEX grin_get_vertex_by_primary_keys_row(GRIN_GRAPH g, + GRIN_VERTEX_TYPE vtype, + GRIN_ROW r) { + auto _g = static_cast(g); + auto _r = static_cast(r); + auto property_list = grin_get_primary_keys_by_vertex_type(g, vtype); + if (property_list == GRIN_NULL_VERTEX_PROPERTY_LIST || + grin_get_vertex_property_list_size(g, property_list) != _r->size()) { + return GRIN_NULL_VERTEX; + } + auto vertex_num = _g->GetVertexNum(vtype); + for (auto i = 0; i < vertex_num; ++i) { + auto v = DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id(vtype, i); + auto row = grin_get_vertex_primary_keys_row(g, v); + if (row == GRIN_NULL_ROW) { + continue; + } + auto _row = static_cast(row); + if (_row->size() != _r->size()) { + grin_destroy_row(g, row); + continue; + } + bool is_same = true; + for (auto j = 0; j < _row->size(); ++j) { + auto property = grin_get_vertex_property_from_list(g, property_list, j); + auto type = grin_get_vertex_property_datatype(g, property); + auto value1 = grin_get_value_from_row(g, r, type, j); + auto value2 = grin_get_value_from_row(g, row, type, j); + if (value1 == NULL || value2 == NULL) { + is_same = false; + break; + } + switch (type) { + case GRIN_DATATYPE::Int32: + if (*static_cast(value1) != + *static_cast(value2)) { + is_same = false; + } + break; + case GRIN_DATATYPE::UInt32: + if (*static_cast(value1) != + *static_cast(value2)) { + is_same = false; + } + break; + case GRIN_DATATYPE::Int64: + if (*static_cast(value1) != + *static_cast(value2)) { + is_same = false; + } + break; + case GRIN_DATATYPE::UInt64: + if (*static_cast(value1) != + *static_cast(value2)) { + is_same = false; + } + break; + case GRIN_DATATYPE::Float: + if (*static_cast(value1) != + *static_cast(value2)) { + is_same = false; + } + break; + case GRIN_DATATYPE::Double: + if (*static_cast(value1) != + *static_cast(value2)) { + is_same = false; + } + break; + case GRIN_DATATYPE::String: + if (strcmp(static_cast(value1), + static_cast(value2)) != 0) { + is_same = false; + } + break; + case GRIN_DATATYPE::Date32: + if (*static_cast(value1) != + *static_cast(value2)) { + is_same = false; + } + break; + case GRIN_DATATYPE::Time32: + if (*static_cast(value1) != + *static_cast(value2)) { + is_same = false; + } + break; + case GRIN_DATATYPE::Timestamp64: + if (*static_cast(value1) != + *static_cast(value2)) { + is_same = false; + } + break; + default: + is_same = false; + } + } + grin_destroy_row(g, row); + if (is_same) { + return v; + } + } + return GRIN_NULL_VERTEX; +} +#endif + +#if defined(GRIN_ENABLE_EDGE_PK_INDEX) && defined(GRIN_ENABLE_EDGE_PRIMARY_KEYS) +GRIN_EDGE grin_get_edge_by_primary_keys_row(GRIN_GRAPH g, GRIN_EDGE_TYPE etype, + GRIN_ROW r) { + auto _g = static_cast(g); + auto _r = static_cast(r); + auto property_list = grin_get_primary_keys_by_edge_type(g, etype); + if (property_list == GRIN_NULL_EDGE_PROPERTY_LIST || + grin_get_edge_property_list_size(g, property_list) != _r->size()) { + return GRIN_NULL_EDGE; + } + auto edge_num = _g->GetEdgeNum(etype); + for (auto i = 0; i < edge_num; i++) { + auto e = DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id(etype, i); + auto row = grin_get_edge_primary_keys_row(g, e); + if (row == GRIN_NULL_ROW) { + continue; + } + auto _row = static_cast(row); + if (_row->size() != _r->size()) { + grin_destroy_row(g, row); + continue; + } + bool is_same = true; + for (auto j = 0; j < _row->size(); ++j) { + auto property = grin_get_edge_property_from_list(g, property_list, j); + auto type = grin_get_edge_property_datatype(g, property); + auto value1 = grin_get_value_from_row(g, r, type, j); + auto value2 = grin_get_value_from_row(g, row, type, j); + if (value1 == NULL || value2 == NULL) { + is_same = false; + break; + } + switch (type) { + case GRIN_DATATYPE::Int32: + if (*static_cast(value1) != + *static_cast(value2)) { + is_same = false; + } + break; + case GRIN_DATATYPE::UInt32: + if (*static_cast(value1) != + *static_cast(value2)) { + is_same = false; + } + break; + case GRIN_DATATYPE::Int64: + if (*static_cast(value1) != + *static_cast(value2)) { + is_same = false; + } + break; + case GRIN_DATATYPE::UInt64: + if (*static_cast(value1) != + *static_cast(value2)) { + is_same = false; + } + break; + case GRIN_DATATYPE::Float: + if (*static_cast(value1) != + *static_cast(value2)) { + is_same = false; + } + break; + case GRIN_DATATYPE::Double: + if (*static_cast(value1) != + *static_cast(value2)) { + is_same = false; + } + break; + case GRIN_DATATYPE::String: + if (strcmp(static_cast(value1), + static_cast(value2)) != 0) { + is_same = false; + } + break; + case GRIN_DATATYPE::Date32: + if (*static_cast(value1) != + *static_cast(value2)) { + is_same = false; + } + break; + case GRIN_DATATYPE::Time32: + if (*static_cast(value1) != + *static_cast(value2)) { + is_same = false; + } + break; + case GRIN_DATATYPE::Timestamp64: + if (*static_cast(value1) != + *static_cast(value2)) { + is_same = false; + } + break; + default: + is_same = false; + } + } + grin_destroy_row(g, row); + if (is_same) { + return e; + } + } + return GRIN_NULL_EDGE; +} +#endif From cdff94d6bf3f4523a72c38e73e74b3a7748de534 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Tue, 26 Sep 2023 14:19:29 +0800 Subject: [PATCH 25/48] Implement error & message --- demo_storage/src/common/error.cc | 19 ++ demo_storage/src/common/message.cc | 329 +++++++++++++++++++++++++++++ 2 files changed, 348 insertions(+) create mode 100644 demo_storage/src/common/error.cc create mode 100644 demo_storage/src/common/message.cc diff --git a/demo_storage/src/common/error.cc b/demo_storage/src/common/error.cc new file mode 100644 index 0000000..705714e --- /dev/null +++ b/demo_storage/src/common/error.cc @@ -0,0 +1,19 @@ +/** Copyright 2020 Alibaba Group Holding Limited. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "src/predefine.h" +// GRIN headers +#include "common/error.h" + +__thread GRIN_ERROR_CODE grin_error_code = NO_ERROR; + +GRIN_ERROR_CODE grin_get_last_error_code() { return grin_error_code; } diff --git a/demo_storage/src/common/message.cc b/demo_storage/src/common/message.cc new file mode 100644 index 0000000..464ad20 --- /dev/null +++ b/demo_storage/src/common/message.cc @@ -0,0 +1,329 @@ +/** Copyright 2020 Alibaba Group Holding Limited. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include +#include + +#include "../predefine.h" +#include "./graph.pb.h" + +// GRIN headers +#include "common/message.h" + +const char* grin_get_static_storage_feature_msg() { + grin::Graph g; + g.set_uri("demo_storage"); + g.set_grin_version("0.1.0"); + + { + auto storage_feature = g.add_features(); + // topology + auto feature = storage_feature->mutable_topology_feature(); + +#ifdef GRIN_ASSUME_HAS_DIRECTED_GRAPH + feature->set_grin_assume_has_directed_graph(true); +#endif + +#ifdef GRIN_ASSUME_HAS_UNDIRECTED_GRAPH + feature->set_grin_assume_has_undirected_graph(true); +#endif + +#ifdef GRIN_ASSUME_HAS_MULTI_EDGE_GRAPH + feature->set_grin_assume_has_multi_edge_graph(true); +#endif + +#ifdef GRIN_WITH_VERTEX_DATA + feature->set_grin_with_vertex_data(true); +#endif + +#ifdef GRIN_WITH_EDGE_DATA + feature->set_grin_with_edge_data(true); +#endif + +#ifdef GRIN_ENABLE_VERTEX_LIST_ARRAY +#ifndef GRIN_ENABLE_VERTEX_LIST + LOG(ERROR) + << "GRIN_ENABLE_VERTEX_LIST_ARRAY requires GRIN_ENABLE_VERTEX_LIST" +#endif + feature->add_vertex_list_retrievals( + grin::ListRetrieval::LR_ARRAY_LIKE); +#endif + +#ifdef GRIN_ENABLE_VERTEX_LIST_ITERATOR +#ifndef GRIN_ENABLE_VERTEX_LIST + LOG(ERROR) + << "GRIN_ENABLE_VERTEX_LIST_ITERATOR requires GRIN_ENABLE_VERTEX_LIST" +#endif + feature->add_vertex_list_retrievals( + grin::ListRetrieval::LR_ITERATOR); +#endif + +#ifdef GRIN_ENABLE_EDGE_LIST_ARRAY +#ifndef GRIN_ENABLE_EDGE_LIST + LOG(ERROR) << "GRIN_ENABLE_EDGE_LIST_ARRAY requires GRIN_ENABLE_EDGE_LIST" +#endif + feature->add_edge_list_retrievals( + grin::ListRetrieval::LR_ARRAY_LIKE); +#endif + +#ifdef GRIN_ENABLE_EDGE_LIST_ITERATOR +#ifndef GRIN_ENABLE_EDGE_LIST + LOG(ERROR) + << "GRIN_ENABLE_EDGE_LIST_ITERATOR requires GRIN_ENABLE_EDGE_LIST" +#endif + feature->add_edge_list_retrievals(grin::ListRetrieval::LR_ITERATOR); +#endif + +#ifdef GRIN_ENABLE_ADJACENT_LIST_ARRAY +#ifndef GRIN_ENABLE_ADJACENT_LIST + LOG(ERROR) + << "GRIN_ENABLE_ADJACENT_LIST_ARRAY requires GRIN_ENABLE_ADJACENT_LIST" +#endif + feature->add_adjacent_list_retrievals( + grin::ListRetrieval::LR_ARRAY_LIKE); +#endif + +#ifdef GRIN_ENABLE_ADJACENT_LIST_ITERATOR +#ifndef GRIN_ENABLE_ADJACENT_LIST + LOG(ERROR) << "GRIN_ENABLE_ADJACENT_LIST_ITERATOR requires " + "GRIN_ENABLE_ADJACENT_LIST" +#endif + feature->add_adjacent_list_retrievals( + grin::ListRetrieval::LR_ITERATOR); +#endif + } + + { + auto storage_feature = g.add_features(); + auto feature = storage_feature->mutable_partition_feature(); + auto cnt = 0; +#ifndef GRIN_ENABLE_GRAPH_PARTITION + feature->set_graph_partition_strategy(grin::GraphPartitionStrategy::GPS_NA); +#else +#ifdef GRIN_ASSUME_ALL_REPLICATE_PARTITION + feature->set_graph_partition_strategy( + grin::GraphPartitionStrategy::GPS_ALL_REPLICATE); + cnt++; +#endif + +#ifdef GRIN_ASSUME_EDGE_CUT_PARTITION + feature->set_graph_partition_strategy( + grin::GraphPartitionStrategy::GPS_EDGE_CUT); + cnt++; +#endif + +#ifdef GRIN_ASSUME_VERTEX_CUT_PARTITION + feature->set_graph_partition_strategy( + grin::GraphPartitionStrategy::GPS_VERTEX_CUT); + cnt++; +#endif + if (cnt > 1) { + LOG(ERROR) << "More than one partition strategy is enabled"; + } +#endif + +#ifdef GRIN_TRAIT_NATURAL_ID_FOR_PARTITION + feature->set_grin_trait_natural_id_for_partition(true); +#endif + +#ifdef GRIN_ENABLE_VERTEX_REF + feature->set_grin_enable_vertex_ref(true); +#endif + +#ifdef GRIN_TRAIT_FAST_VERTEX_REF + feature->set_grin_trait_fast_vertex_ref(true); +#endif + +#ifdef GRIN_ENABLE_EDGE_REF + feature->set_grin_enable_edge_ref(true); +#endif + +#ifdef GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_VERTEX_DATA +#ifdef GRIN_WITH_VERTEX_DATA + feature->set_vertex_data( + grin::PropertyDataPartitionStrategy::PDPS_MASTER_ONLY); +#else + feature->set_vertex_data(grin::PropertyDataPartitionStrategy::PDPS_NA); +#endif +#endif + +#ifdef GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_VERTEX_DATA +#ifdef GRIN_WITH_VERTEX_DATA + feature->set_vertex_data( + grin::PropertyDataPartitionStrategy::PDPS_REPLICATE_MASTER_MIRROR); +#else + feature->set_vertex_data(grin::PropertyDataPartitionStrategy::PDPS_NA); +#endif +#endif + +#ifdef GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_EDGE_DATA +#ifdef GRIN_WITH_EDGE_DATA + feature->set_edge_data( + grin::PropertyDataPartitionStrategy::PDPS_MASTER_ONLY); +#else + feature->set_edge_data(grin::PropertyDataPartitionStrategy::PDPS_NA); +#endif +#endif + +#ifdef GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_EDGE_DATA +#ifdef GRIN_WITH_EDGE_DATA + feature->set_edge_data( + grin::PropertyDataPartitionStrategy::PDPS_REPLICATE_MASTER_MIRROR); +#else + feature->set_edge_data(grin::PropertyDataPartitionStrategy::PDPS_NA); +#endif +#endif + + auto mpl_feature = feature->mutable_mirror_partition_list_feature(); +#ifdef GRIN_TRAIT_MASTER_VERTEX_MIRROR_PARTITION_LIST + mpl_feature->set_grin_trait_master_vertex_mirror_partition_list(true); +#endif + +#ifdef GRIN_TRAIT_MIRROR_VERTEX_MIRROR_PARTITION_LIST + mpl_feature->set_grin_trait_mirror_vertex_mirror_partition_list(true); +#endif + +#ifdef GRIN_TRAIT_MASTER_EDGE_MIRROR_PARTITION_LIST + mpl_feature->set_grin_trait_master_edge_mirror_partition_list(true); +#endif + +#ifdef GRIN_TRAIT_MIRROR_EDGE_MIRROR_PARTITION_LIST + mpl_feature->set_grin_trait_mirror_edge_mirror_partition_list(true); +#endif + +#ifdef GRIN_TRAIT_SELECT_MASTER_FOR_VERTEX_LIST + feature->set_grin_trait_select_master_for_vertex_list(true); +#endif + +#ifdef GRIN_TRAIT_SELECT_PARTITION_FOR_VERTEX_LIST + feature->set_grin_trait_select_partition_for_vertex_list(true); +#endif + +#ifdef GRIN_TRAIT_SELECT_MASTER_FOR_EDGE_LIST + feature->set_grin_trait_select_master_for_edge_list(true); +#endif + +#ifdef GRIN_TRAIT_SELECT_PARTITION_FOR_EDGE_LIST + feature->set_grin_trait_select_partition_for_edge_list(true); +#endif + +#ifdef GRIN_TRAIT_SELECT_MASTER_NEIGHBOR_FOR_ADJACENT_LIST + feature->set_grin_trait_select_master_neighbor_for_adjacent_list(true); +#endif + +#ifdef GRIN_TRAIT_SELECT_NEIGHBOR_PARTITION_FOR_ADJACENT_LIST + feature->set_grin_trait_select_neighbor_partition_for_adjacent_list(true); +#endif + } + + { + auto storage_feature = g.add_features(); + auto feature = storage_feature->mutable_property_feature(); +#ifdef GRIN_ENABLE_ROW + feature->set_grin_enable_row(true); +#endif + + auto vfeature = feature->mutable_vertex_property_feature(); +#ifdef GRIN_WITH_VERTEX_PROPERTY + vfeature->set_grin_with_vertex_property(true); +#endif + +#ifdef GRIN_WITH_VERTEX_PROPERTY_NAME + vfeature->set_grin_with_vertex_property_name(true); +#endif + +#ifdef GRIN_WITH_VERTEX_TYPE_NAME + vfeature->set_grin_with_vertex_type_name(true); +#endif + +#ifdef GRIN_ENABLE_VERTEX_PRIMARY_KEYS + vfeature->set_grin_enable_vertex_primary_keys(true); +#endif + +#ifdef GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_TYPE + vfeature->set_grin_trait_natural_id_for_vertex_type(true); +#endif + +#ifdef GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_PROPERTY + vfeature->set_grin_trait_natural_id_for_vertex_property(true); +#endif + + auto efeature = feature->mutable_edge_property_feature(); +#ifdef GRIN_WITH_EDGE_PROPERTY + efeature->set_grin_with_edge_property(true); +#endif + +#ifdef GRIN_WITH_EDGE_PROPERTY_NAME + efeature->set_grin_with_edge_property_name(true); +#endif + +#ifdef GRIN_WITH_EDGE_TYPE_NAME + efeature->set_grin_with_edge_type_name(true); +#endif + +#ifdef GRIN_ENABLE_EDGE_PRIMARY_KEYS + efeature->set_grin_enable_edge_primary_keys(true); +#endif + +#ifdef GRIN_TRAIT_NATURAL_ID_FOR_EDGE_TYPE + efeature->set_grin_trait_natural_id_for_edge_type(true); +#endif + +#ifdef GRIN_TRAIT_NATURAL_ID_FOR_EDGE_PROPERTY + efeature->set_grin_trait_natural_id_for_edge_property(true); +#endif + +#ifdef GRIN_TRAIT_SPECIFIC_VEV_RELATION + feature->set_grin_trait_specific_vev_relation(true); +#endif + +#ifdef GRIN_TRAIT_CONST_VALUE_PTR + feature->set_grin_trait_const_value_ptr(true); +#endif + } + + { + auto storage_feature = g.add_features(); + auto feature = storage_feature->mutable_index_feature(); +#ifdef GRIN_WITH_VERTEX_LABEL + feature->set_grin_with_vertex_label(true); +#endif + +#ifdef GRIN_WITH_EDGE_LABEL + feature->set_grin_with_edge_label(true); +#endif + +#ifdef GRIN_ASSUME_ALL_VERTEX_LIST_SORTED + feature->set_grin_assume_all_vertex_list_sorted(true); +#endif + +#ifdef GRIN_ENABLE_VERTEX_INTERNAL_ID_INDEX + feature->set_grin_enable_vertex_internal_id_index(true); +#endif + +#ifdef GRIN_ENABLE_VERTEX_PK_INDEX + feature->set_grin_enable_vertex_pk_index(true); +#endif + +#ifdef GRIN_ENABLE_EDGE_PK_INDEX + feature->set_grin_enable_edge_pk_index(true); +#endif + } + + std::string graph_def; + google::protobuf::util::MessageToJsonString(g, &graph_def); + + int len = graph_def.length() + 1; + char* out = new char[len]; + snprintf(out, len, "%s", graph_def.c_str()); + return out; +} From c928080a1eaca1fc120510481262cdb8c5777e75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Tue, 26 Sep 2023 14:20:06 +0800 Subject: [PATCH 26/48] Implement property-related APIs --- demo_storage/src/property/primarykey.cc | 111 ++++++ demo_storage/src/property/property.cc | 419 ++++++++++++++++++++++ demo_storage/src/property/propertylist.cc | 153 ++++++++ demo_storage/src/property/row.cc | 222 ++++++++++++ demo_storage/src/property/topology.cc | 65 ++++ demo_storage/src/property/type.cc | 223 ++++++++++++ 6 files changed, 1193 insertions(+) create mode 100644 demo_storage/src/property/primarykey.cc create mode 100644 demo_storage/src/property/property.cc create mode 100644 demo_storage/src/property/propertylist.cc create mode 100644 demo_storage/src/property/row.cc create mode 100644 demo_storage/src/property/topology.cc create mode 100644 demo_storage/src/property/type.cc diff --git a/demo_storage/src/property/primarykey.cc b/demo_storage/src/property/primarykey.cc new file mode 100644 index 0000000..7ffe608 --- /dev/null +++ b/demo_storage/src/property/primarykey.cc @@ -0,0 +1,111 @@ +/** Copyright 2020 Alibaba Group Holding Limited. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "src/predefine.h" +// GRIN headers +#include "property/primarykey.h" + +#ifdef GRIN_ENABLE_VERTEX_PRIMARY_KEYS +GRIN_VERTEX_TYPE_LIST grin_get_vertex_types_with_primary_keys(GRIN_GRAPH g) { + auto _g = static_cast(g); + auto vtl = new GRIN_VERTEX_TYPE_LIST_T(); + auto vtype_num = _g->GetVertexTypeNum(); + for (auto i = 0; i < vtype_num; i++) { + auto& properties = _g->GetVertexProperties(i); + for (auto& property : properties) { + if (property.is_primary_) { + vtl->push_back(i); + break; + } + } + } + return vtl; +} + +GRIN_VERTEX_PROPERTY_LIST grin_get_primary_keys_by_vertex_type( + GRIN_GRAPH g, GRIN_VERTEX_TYPE vtype) { + auto _g = static_cast(g); + auto vpl = new GRIN_VERTEX_PROPERTY_LIST_T(); + auto& properties = _g->GetVertexProperties(vtype); + for (auto i = 0; i < properties.size(); i++) { + auto& property = properties[i]; + if (property.is_primary_) { + vpl->push_back( + DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id(vtype, i)); + } + } + return vpl; +} + +GRIN_ROW grin_get_vertex_primary_keys_row(GRIN_GRAPH g, GRIN_VERTEX v) { + auto _g = static_cast(g); + auto& _v = _g->GetVertex(v); + auto vtype = DEMO_STORAGE_NAMESPACE::get_type_id_from_gid(v); + auto& properties = _g->GetVertexProperties(vtype); + auto row = new GRIN_ROW_T(); + for (auto i = 0; i < properties.size(); i++) { + auto& property = properties[i]; + if (property.is_primary_) { + row->push_back(_v.GetPropertyAny(property.name_)); + } + } + return row; +} +#endif + +#ifdef GRIN_ENABLE_EDGE_PRIMARY_KEYS +GRIN_EDGE_TYPE_LIST grin_get_edge_types_with_primary_keys(GRIN_GRAPH g) { + auto _g = static_cast(g); + auto etl = new GRIN_EDGE_TYPE_LIST_T(); + auto etype_num = _g->GetEdgeTypeNum(); + for (auto i = 0; i < etype_num; i++) { + auto& properties = _g->GetEdgeProperties(i); + for (auto& property : properties) { + if (property.is_primary_) { + etl->push_back(i); + break; + } + } + } + return etl; +} + +GRIN_EDGE_PROPERTY_LIST grin_get_primary_keys_by_edge_type( + GRIN_GRAPH g, GRIN_EDGE_TYPE etype) { + auto _g = static_cast(g); + auto epl = new GRIN_EDGE_PROPERTY_LIST_T(); + auto& properties = _g->GetEdgeProperties(etype); + for (auto i = 0; i < properties.size(); i++) { + auto& property = properties[i]; + if (property.is_primary_) { + epl->push_back( + DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id(etype, i)); + } + } + return epl; +} + +GRIN_ROW grin_get_edge_primary_keys_row(GRIN_GRAPH g, GRIN_EDGE e) { + auto _g = static_cast(g); + auto& _e = _g->GetEdge(e); + auto etype = DEMO_STORAGE_NAMESPACE::get_type_id_from_gid(e); + auto& properties = _g->GetEdgeProperties(etype); + auto row = new GRIN_ROW_T(); + for (auto i = 0; i < properties.size(); i++) { + auto& property = properties[i]; + if (property.is_primary_) { + row->push_back(_e.GetPropertyAny(property.name_)); + } + } + return row; +} +#endif diff --git a/demo_storage/src/property/property.cc b/demo_storage/src/property/property.cc new file mode 100644 index 0000000..22d9e75 --- /dev/null +++ b/demo_storage/src/property/property.cc @@ -0,0 +1,419 @@ +/** Copyright 2020 Alibaba Group Holding Limited. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "src/predefine.h" +// GRIN headers +#include "common/error.h" +#include "property/property.h" + +#define __grin_check_vertex_property(v, vp, x) \ + grin_error_code = NO_ERROR; \ + auto vtype0 = DEMO_STORAGE_NAMESPACE::get_type_id_from_gid(v); \ + auto vtype1 = DEMO_STORAGE_NAMESPACE::get_type_id_from_gid(vp); \ + if (vtype0 != vtype1) { \ + grin_error_code = INVALID_VALUE; \ + return x; \ + } + +#define __grin_check_edge_property(e, ep, x) \ + grin_error_code = NO_ERROR; \ + auto etype0 = DEMO_STORAGE_NAMESPACE::get_type_id_from_gid(e); \ + auto etype1 = DEMO_STORAGE_NAMESPACE::get_type_id_from_gid(ep); \ + if (etype0 != etype1) { \ + grin_error_code = INVALID_VALUE; \ + return x; \ + } + +void grin_destroy_string_value(GRIN_GRAPH g, const char* value) { return; } + +#ifdef GRIN_WITH_VERTEX_PROPERTY_NAME +const char* grin_get_vertex_property_name(GRIN_GRAPH g, GRIN_VERTEX_TYPE vtype, + GRIN_VERTEX_PROPERTY vp) { + auto _g = static_cast(g); + if (vtype >= _g->GetVertexTypeNum()) + return nullptr; + auto vp_id = DEMO_STORAGE_NAMESPACE::get_id_from_gid(vp); + return _g->GetVertexPropertyName(vtype, vp_id).c_str(); +} + +GRIN_VERTEX_PROPERTY grin_get_vertex_property_by_name(GRIN_GRAPH g, + GRIN_VERTEX_TYPE vtype, + const char* name) { + auto _g = static_cast(g); + if (vtype >= _g->GetVertexTypeNum()) + return GRIN_NULL_VERTEX_PROPERTY; + auto vp_id = _g->GetVertexPropertyId(vtype, name); + if (vp_id == -1) + return GRIN_NULL_VERTEX_PROPERTY; + return DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id(vtype, vp_id); +} + +GRIN_VERTEX_PROPERTY_LIST grin_get_vertex_properties_by_name(GRIN_GRAPH g, + const char* name) { + auto vpl = new GRIN_VERTEX_PROPERTY_LIST_T(); + auto _g = static_cast(g); + for (unsigned i = 0; i < _g->GetVertexTypeNum(); ++i) { + auto vp_id = _g->GetVertexPropertyId(i, name); + if (vp_id != -1) + vpl->push_back( + DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id(i, vp_id)); + } + if (vpl->size() == 0) { + delete vpl; + return GRIN_NULL_VERTEX_PROPERTY_LIST; + } + return vpl; +} +#endif + +#ifdef GRIN_WITH_EDGE_PROPERTY_NAME +const char* grin_get_edge_property_name(GRIN_GRAPH g, GRIN_EDGE_TYPE etype, + GRIN_EDGE_PROPERTY ep) { + auto _g = static_cast(g); + if (etype >= _g->GetEdgeTypeNum()) + return nullptr; + auto ep_id = DEMO_STORAGE_NAMESPACE::get_id_from_gid(ep); + return _g->GetEdgePropertyName(etype, ep_id).c_str(); +} + +GRIN_EDGE_PROPERTY grin_get_edge_property_by_name(GRIN_GRAPH g, + GRIN_EDGE_TYPE etype, + const char* name) { + auto _g = static_cast(g); + if (etype >= _g->GetEdgeTypeNum()) + return GRIN_NULL_EDGE_PROPERTY; + auto ep_id = _g->GetEdgePropertyId(etype, name); + if (ep_id == -1) + return GRIN_NULL_EDGE_PROPERTY; + return DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id(etype, ep_id); +} + +GRIN_EDGE_PROPERTY_LIST grin_get_edge_properties_by_name(GRIN_GRAPH g, + const char* name) { + auto epl = new GRIN_EDGE_PROPERTY_LIST_T(); + auto _g = static_cast(g); + for (unsigned i = 0; i < _g->GetEdgeTypeNum(); ++i) { + auto ep_id = _g->GetEdgePropertyId(i, name); + if (ep_id != -1) + epl->push_back( + DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id(i, ep_id)); + } + if (epl->size() == 0) { + delete epl; + return GRIN_NULL_EDGE_PROPERTY_LIST; + } + return epl; +} +#endif + +#ifdef GRIN_WITH_VERTEX_PROPERTY +bool grin_equal_vertex_property(GRIN_GRAPH g, GRIN_VERTEX_PROPERTY vp1, + GRIN_VERTEX_PROPERTY vp2) { + return vp1 == vp2; +} + +void grin_destroy_vertex_property(GRIN_GRAPH g, GRIN_VERTEX_PROPERTY vp) { + return; +} + +GRIN_DATATYPE grin_get_vertex_property_datatype(GRIN_GRAPH g, + GRIN_VERTEX_PROPERTY vp) { + auto _g = static_cast(g); + auto& property = _g->GetVertexProperty(vp); + return property.datatype_; +} + +int grin_get_vertex_property_value_of_int32(GRIN_GRAPH g, GRIN_VERTEX v, + GRIN_VERTEX_PROPERTY vp) { + __grin_check_vertex_property(v, vp, 0); + auto _g = static_cast(g); + auto& property = _g->GetVertexProperty(vp); + auto& _v = _g->GetVertex(v); + return _v.GetProperty(property.name_); +} + +unsigned int grin_get_vertex_property_value_of_uint32(GRIN_GRAPH g, // NOLINT + GRIN_VERTEX v, + GRIN_VERTEX_PROPERTY vp) { + __grin_check_vertex_property(v, vp, 0); + auto _g = static_cast(g); + auto& property = _g->GetVertexProperty(vp); + auto& _v = _g->GetVertex(v); + return _v.GetProperty(property.name_); +} + +long long int grin_get_vertex_property_value_of_int64(GRIN_GRAPH g, // NOLINT + GRIN_VERTEX v, + GRIN_VERTEX_PROPERTY vp) { + __grin_check_vertex_property(v, vp, 0); + auto _g = static_cast(g); + auto& property = _g->GetVertexProperty(vp); + auto& _v = _g->GetVertex(v); + return _v.GetProperty(property.name_); +} + +unsigned long long int grin_get_vertex_property_value_of_uint64( // NOLINT + GRIN_GRAPH g, GRIN_VERTEX v, GRIN_VERTEX_PROPERTY vp) { + __grin_check_vertex_property(v, vp, 0); + auto _g = static_cast(g); + auto& property = _g->GetVertexProperty(vp); + auto& _v = _g->GetVertex(v); + return _v.GetProperty(property.name_); +} + +float grin_get_vertex_property_value_of_float(GRIN_GRAPH g, GRIN_VERTEX v, + GRIN_VERTEX_PROPERTY vp) { + __grin_check_vertex_property(v, vp, 0); + auto _g = static_cast(g); + auto& property = _g->GetVertexProperty(vp); + auto& _v = _g->GetVertex(v); + return _v.GetProperty(property.name_); +} + +double grin_get_vertex_property_value_of_double(GRIN_GRAPH g, GRIN_VERTEX v, + GRIN_VERTEX_PROPERTY vp) { + __grin_check_vertex_property(v, vp, 0); + auto _g = static_cast(g); + auto& property = _g->GetVertexProperty(vp); + auto& _v = _g->GetVertex(v); + return _v.GetProperty(property.name_); +} + +const char* grin_get_vertex_property_value_of_string(GRIN_GRAPH g, + GRIN_VERTEX v, + GRIN_VERTEX_PROPERTY vp) { + __grin_check_vertex_property(v, vp, NULL); + auto _g = static_cast(g); + auto& property = _g->GetVertexProperty(vp); + auto& _v = _g->GetVertex(v); + return _v.GetProperty(property.name_).c_str(); +} + +int grin_get_vertex_property_value_of_date32(GRIN_GRAPH g, GRIN_VERTEX v, + GRIN_VERTEX_PROPERTY vp) { + __grin_check_vertex_property(v, vp, 0); + auto _g = static_cast(g); + auto& property = _g->GetVertexProperty(vp); + auto& _v = _g->GetVertex(v); + return _v.GetProperty(property.name_); +} + +int grin_get_vertex_property_value_of_time32(GRIN_GRAPH g, GRIN_VERTEX v, + GRIN_VERTEX_PROPERTY vp) { + __grin_check_vertex_property(v, vp, 0); + auto _g = static_cast(g); + auto& property = _g->GetVertexProperty(vp); + auto& _v = _g->GetVertex(v); + return _v.GetProperty(property.name_); +} + +long long int grin_get_vertex_property_value_of_timestamp64( // NOLINT + GRIN_GRAPH g, GRIN_VERTEX v, GRIN_VERTEX_PROPERTY vp) { + __grin_check_vertex_property(v, vp, 0); + auto _g = static_cast(g); + auto& property = _g->GetVertexProperty(vp); + auto& _v = _g->GetVertex(v); + return _v.GetProperty(property.name_); +} + +GRIN_VERTEX_TYPE grin_get_vertex_type_from_property(GRIN_GRAPH g, + GRIN_VERTEX_PROPERTY vp) { + return DEMO_STORAGE_NAMESPACE::get_type_id_from_gid(vp); +} +#endif + +#if defined(GRIN_WITH_VERTEX_PROPERTY) && defined(GRIN_TRAIT_CONST_VALUE_PTR) +const void* grin_get_vertex_property_value(GRIN_GRAPH g, GRIN_VERTEX v, + GRIN_VERTEX_PROPERTY vp) { + auto _g = static_cast(g); + __grin_check_vertex_property(v, vp, NULL); + auto& _v = _g->GetVertex(v); + auto& property = _g->GetVertexProperty(vp); + auto& name = property.name_; + auto& type = property.datatype_; + switch (type) { + case GRIN_DATATYPE::Int32: + return &_v.GetProperty(name); + case GRIN_DATATYPE::UInt32: + return &_v.GetProperty(name); + case GRIN_DATATYPE::Int64: + return &_v.GetProperty(name); + case GRIN_DATATYPE::UInt64: + return &_v.GetProperty(name); + case GRIN_DATATYPE::Float: + return &_v.GetProperty(name); + case GRIN_DATATYPE::Double: + return &_v.GetProperty(name); + case GRIN_DATATYPE::String: + return _v.GetProperty(name).c_str(); + case GRIN_DATATYPE::Date32: + return &_v.GetProperty(name); + case GRIN_DATATYPE::Time32: + return &_v.GetProperty(name); + case GRIN_DATATYPE::Timestamp64: + return &_v.GetProperty(name); + default: + return NULL; + } + return NULL; +} +#endif + +#ifdef GRIN_WITH_EDGE_PROPERTY +bool grin_equal_edge_property(GRIN_GRAPH g, GRIN_EDGE_PROPERTY ep1, + GRIN_EDGE_PROPERTY ep2) { + return ep1 == ep2; +} + +void grin_destroy_edge_property(GRIN_GRAPH g, GRIN_EDGE_PROPERTY ep) { return; } + +GRIN_DATATYPE grin_get_edge_property_datatype(GRIN_GRAPH g, + GRIN_EDGE_PROPERTY ep) { + auto _g = static_cast(g); + auto& property = _g->GetEdgeProperty(ep); + return property.datatype_; +} + +int grin_get_edge_property_value_of_int32(GRIN_GRAPH g, GRIN_EDGE e, + GRIN_EDGE_PROPERTY ep) { + __grin_check_edge_property(e, ep, 0); + auto _g = static_cast(g); + auto& property = _g->GetEdgeProperty(ep); + auto& _e = _g->GetEdge(e); + return _e.GetProperty(property.name_); +} + +unsigned int grin_get_edge_property_value_of_uint32(GRIN_GRAPH g, // NOLINT + GRIN_EDGE e, + GRIN_EDGE_PROPERTY ep) { + __grin_check_edge_property(e, ep, 0); + auto _g = static_cast(g); + auto& property = _g->GetEdgeProperty(ep); + auto& _e = _g->GetEdge(e); + return _e.GetProperty(property.name_); +} + +long long int grin_get_edge_property_value_of_int64(GRIN_GRAPH g, // NOLINT + GRIN_EDGE e, + GRIN_EDGE_PROPERTY ep) { + __grin_check_edge_property(e, ep, 0); + auto _g = static_cast(g); + auto& property = _g->GetEdgeProperty(ep); + auto& _e = _g->GetEdge(e); + return _e.GetProperty(property.name_); +} + +unsigned long long int grin_get_edge_property_value_of_uint64( // NOLINT + GRIN_GRAPH g, GRIN_EDGE e, GRIN_EDGE_PROPERTY ep) { + __grin_check_edge_property(e, ep, 0); + auto _g = static_cast(g); + auto& property = _g->GetEdgeProperty(ep); + auto& _e = _g->GetEdge(e); + return _e.GetProperty(property.name_); +} + +float grin_get_edge_property_value_of_float(GRIN_GRAPH g, GRIN_EDGE e, + GRIN_EDGE_PROPERTY ep) { + __grin_check_edge_property(e, ep, 0); + auto _g = static_cast(g); + auto& property = _g->GetEdgeProperty(ep); + auto& _e = _g->GetEdge(e); + return _e.GetProperty(property.name_); +} + +double grin_get_edge_property_value_of_double(GRIN_GRAPH g, GRIN_EDGE e, + GRIN_EDGE_PROPERTY ep) { + __grin_check_edge_property(e, ep, 0); + auto _g = static_cast(g); + auto& property = _g->GetEdgeProperty(ep); + auto& _e = _g->GetEdge(e); + return _e.GetProperty(property.name_); +} + +const char* grin_get_edge_property_value_of_string(GRIN_GRAPH g, GRIN_EDGE e, + GRIN_EDGE_PROPERTY ep) { + __grin_check_edge_property(e, ep, 0); + auto _g = static_cast(g); + auto& property = _g->GetEdgeProperty(ep); + auto& _e = _g->GetEdge(e); + return _e.GetProperty(property.name_).c_str(); +} + +int grin_get_edge_property_value_of_date32(GRIN_GRAPH g, GRIN_EDGE e, + GRIN_EDGE_PROPERTY ep) { + __grin_check_edge_property(e, ep, 0); + auto _g = static_cast(g); + auto& property = _g->GetEdgeProperty(ep); + auto& _e = _g->GetEdge(e); + return _e.GetProperty(property.name_); +} + +int grin_get_edge_property_value_of_time32(GRIN_GRAPH g, GRIN_EDGE e, + GRIN_EDGE_PROPERTY ep) { + __grin_check_edge_property(e, ep, 0); + auto _g = static_cast(g); + auto& property = _g->GetEdgeProperty(ep); + auto& _e = _g->GetEdge(e); + return _e.GetProperty(property.name_); +} + +long long int grin_get_edge_property_value_of_timestamp64( // NOLINT + GRIN_GRAPH g, GRIN_EDGE e, GRIN_EDGE_PROPERTY ep) { + __grin_check_edge_property(e, ep, 0); + auto _g = static_cast(g); + auto& property = _g->GetEdgeProperty(ep); + auto& _e = _g->GetEdge(e); + return _e.GetProperty(property.name_); +} + +GRIN_EDGE_TYPE grin_get_edge_type_from_property(GRIN_GRAPH g, + GRIN_EDGE_PROPERTY ep) { + return DEMO_STORAGE_NAMESPACE::get_type_id_from_gid(ep); +} +#endif + +#if defined(GRIN_WITH_EDGE_PROPERTY) && defined(GRIN_TRAIT_CONST_VALUE_PTR) +const void* grin_get_edge_property_value(GRIN_GRAPH g, GRIN_EDGE e, + GRIN_EDGE_PROPERTY ep) { + auto _g = static_cast(g); + __grin_check_edge_property(e, ep, NULL); + auto& _e = _g->GetEdge(e); + auto& property = _g->GetEdgeProperty(ep); + auto& name = property.name_; + auto& type = property.datatype_; + switch (type) { + case GRIN_DATATYPE::Int32: + return &_e.GetProperty(name); + case GRIN_DATATYPE::UInt32: + return &_e.GetProperty(name); + case GRIN_DATATYPE::Int64: + return &_e.GetProperty(name); + case GRIN_DATATYPE::UInt64: + return &_e.GetProperty(name); + case GRIN_DATATYPE::Float: + return &_e.GetProperty(name); + case GRIN_DATATYPE::Double: + return &_e.GetProperty(name); + case GRIN_DATATYPE::String: + return _e.GetProperty(name).c_str(); + case GRIN_DATATYPE::Date32: + return &_e.GetProperty(name); + case GRIN_DATATYPE::Time32: + return &_e.GetProperty(name); + case GRIN_DATATYPE::Timestamp64: + return &_e.GetProperty(name); + default: + return NULL; + } + return NULL; +} +#endif diff --git a/demo_storage/src/property/propertylist.cc b/demo_storage/src/property/propertylist.cc new file mode 100644 index 0000000..bc76e4a --- /dev/null +++ b/demo_storage/src/property/propertylist.cc @@ -0,0 +1,153 @@ +/** Copyright 2020 Alibaba Group Holding Limited. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "src/predefine.h" +// GRIN headers +#include "property/propertylist.h" + +#ifdef GRIN_WITH_VERTEX_PROPERTY +GRIN_VERTEX_PROPERTY_LIST grin_get_vertex_property_list_by_type( + GRIN_GRAPH g, GRIN_VERTEX_TYPE vtype) { + auto _g = static_cast(g); + if (vtype >= _g->GetVertexTypeNum()) + return GRIN_NULL_VERTEX_PROPERTY_LIST; + auto vpl = new GRIN_VERTEX_PROPERTY_LIST_T(); + auto n = _g->GetVertexPropertyNum(vtype); + for (auto i = 0; i < n; ++i) { + auto vp = + DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id(vtype, i); + vpl->push_back(vp); + } + return vpl; +} + +size_t grin_get_vertex_property_list_size(GRIN_GRAPH g, + GRIN_VERTEX_PROPERTY_LIST vpl) { + auto _vpl = static_cast(vpl); + return _vpl->size(); +} + +GRIN_VERTEX_PROPERTY grin_get_vertex_property_from_list( + GRIN_GRAPH g, GRIN_VERTEX_PROPERTY_LIST vpl, size_t idx) { + auto _vpl = static_cast(vpl); + if (idx >= _vpl->size()) + return GRIN_NULL_VERTEX_PROPERTY; + return (*_vpl)[idx]; +} + +GRIN_VERTEX_PROPERTY_LIST grin_create_vertex_property_list(GRIN_GRAPH g) { + return new GRIN_VERTEX_PROPERTY_LIST_T(); +} + +void grin_destroy_vertex_property_list(GRIN_GRAPH g, + GRIN_VERTEX_PROPERTY_LIST vpl) { + auto _vpl = static_cast(vpl); + delete _vpl; +} + +bool grin_insert_vertex_property_to_list(GRIN_GRAPH g, + GRIN_VERTEX_PROPERTY_LIST vpl, + GRIN_VERTEX_PROPERTY vp) { + auto _vpl = static_cast(vpl); + _vpl->push_back(vp); + return true; +} +#endif + +#ifdef GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_PROPERTY +GRIN_VERTEX_PROPERTY grin_get_vertex_property_by_id( + GRIN_GRAPH g, GRIN_VERTEX_TYPE vtype, GRIN_VERTEX_PROPERTY_ID id) { + auto _g = static_cast(g); + if (vtype >= 0 & vtype < _g->GetVertexTypeNum() && id >= 0 && + id < _g->GetVertexPropertyNum(vtype)) { + return DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id(vtype, id); + } else { + return GRIN_NULL_VERTEX_PROPERTY; + } +} + +GRIN_VERTEX_PROPERTY_ID grin_get_vertex_property_id(GRIN_GRAPH g, + GRIN_VERTEX_TYPE vtype, + GRIN_VERTEX_PROPERTY vp) { + return DEMO_STORAGE_NAMESPACE::get_id_from_gid(vp); +} +#endif + +#ifdef GRIN_WITH_EDGE_PROPERTY +GRIN_EDGE_PROPERTY_LIST grin_get_edge_property_list_by_type( + GRIN_GRAPH g, GRIN_EDGE_TYPE etype) { + auto _g = static_cast(g); + if (etype >= _g->GetEdgeTypeNum()) + return GRIN_NULL_VERTEX_PROPERTY_LIST; + auto epl = new GRIN_EDGE_PROPERTY_LIST_T(); + auto n = _g->GetEdgePropertyNum(etype); + for (auto i = 0; i < n; ++i) { + auto ep = + DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id(etype, i); + epl->push_back(ep); + } + return epl; +} + +size_t grin_get_edge_property_list_size(GRIN_GRAPH g, + GRIN_EDGE_PROPERTY_LIST epl) { + auto _epl = static_cast(epl); + return _epl->size(); +} + +GRIN_EDGE_PROPERTY grin_get_edge_property_from_list(GRIN_GRAPH g, + GRIN_EDGE_PROPERTY_LIST epl, + size_t idx) { + auto _epl = static_cast(epl); + if (idx >= _epl->size()) + return GRIN_NULL_EDGE_PROPERTY; + return (*_epl)[idx]; +} + +GRIN_EDGE_PROPERTY_LIST grin_create_edge_property_list(GRIN_GRAPH g) { + return new GRIN_EDGE_PROPERTY_LIST_T(); +} + +void grin_destroy_edge_property_list(GRIN_GRAPH g, + GRIN_EDGE_PROPERTY_LIST epl) { + auto _epl = static_cast(epl); + delete _epl; +} + +bool grin_insert_edge_property_to_list(GRIN_GRAPH g, + GRIN_EDGE_PROPERTY_LIST epl, + GRIN_EDGE_PROPERTY ep) { + auto _epl = static_cast(epl); + _epl->push_back(ep); + return true; +} +#endif + +#ifdef GRIN_TRAIT_NATURAL_ID_FOR_EDGE_PROPERTY +GRIN_EDGE_PROPERTY grin_get_edge_property_by_id(GRIN_GRAPH g, + GRIN_EDGE_TYPE etype, + GRIN_EDGE_PROPERTY_ID id) { + auto _g = static_cast(g); + if (etype >= 0 && etype < _g->GetEdgeTypeNum() && id >= 0 && + id < _g->GetEdgePropertyNum(etype)) { + return DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id(etype, id); + } else { + return GRIN_NULL_EDGE_PROPERTY; + } +} + +GRIN_EDGE_PROPERTY_ID grin_get_edge_property_id(GRIN_GRAPH g, + GRIN_EDGE_TYPE etype, + GRIN_EDGE_PROPERTY ep) { + return DEMO_STORAGE_NAMESPACE::get_id_from_gid(ep); +} +#endif diff --git a/demo_storage/src/property/row.cc b/demo_storage/src/property/row.cc new file mode 100644 index 0000000..0ba60fd --- /dev/null +++ b/demo_storage/src/property/row.cc @@ -0,0 +1,222 @@ +/** Copyright 2020 Alibaba Group Holding Limited. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "src/predefine.h" +// GRIN headers +#include "common/error.h" +#include "property/row.h" + +#define __grin_check_row(_r, x) \ + grin_error_code = NO_ERROR; \ + if (idx >= _r->size()) { \ + grin_error_code = INVALID_VALUE; \ + return x; \ + } + +#ifdef GRIN_ENABLE_ROW +void grin_destroy_row(GRIN_GRAPH g, GRIN_ROW r) { + auto _r = static_cast(r); + delete _r; +} + +int grin_get_int32_from_row(GRIN_GRAPH g, GRIN_ROW r, size_t idx) { + auto _r = static_cast(r); + __grin_check_row(_r, 0); + return std::any_cast((*_r)[idx]); +} + +unsigned int grin_get_uint32_from_row(GRIN_GRAPH g, GRIN_ROW r, size_t idx) { + auto _r = static_cast(r); + __grin_check_row(_r, 0); + return std::any_cast((*_r)[idx]); +} + +long long int grin_get_int64_from_row(GRIN_GRAPH g, // NOLINT + GRIN_ROW r, size_t idx) { + auto _r = static_cast(r); + __grin_check_row(_r, 0); + return std::any_cast((*_r)[idx]); +} + +unsigned long long int grin_get_uint64_from_row(GRIN_GRAPH g, // NOLINT + GRIN_ROW r, size_t idx) { + auto _r = static_cast(r); + __grin_check_row(_r, 0); + return std::any_cast((*_r)[idx]); +} + +float grin_get_float_from_row(GRIN_GRAPH g, GRIN_ROW r, size_t idx) { + auto _r = static_cast(r); + __grin_check_row(_r, 0); + return std::any_cast((*_r)[idx]); +} + +double grin_get_double_from_row(GRIN_GRAPH g, GRIN_ROW r, size_t idx) { + auto _r = static_cast(r); + __grin_check_row(_r, 0); + return std::any_cast((*_r)[idx]); +} + +const char* grin_get_string_from_row(GRIN_GRAPH g, GRIN_ROW r, size_t idx) { + auto _r = static_cast(r); + __grin_check_row(_r, NULL); + return std::any_cast((*_r)[idx]).c_str(); +} + +int grin_get_date32_from_row(GRIN_GRAPH g, GRIN_ROW r, size_t idx) { + auto _r = static_cast(r); + __grin_check_row(_r, 0); + return std::any_cast((*_r)[idx]); +} + +int grin_get_time32_from_row(GRIN_GRAPH g, GRIN_ROW r, size_t idx) { + auto _r = static_cast(r); + __grin_check_row(_r, 0); + return std::any_cast((*_r)[idx]); +} + +long long int grin_get_timestamp64_from_row(GRIN_GRAPH g, GRIN_ROW r, // NOLINT + size_t idx) { + auto _r = static_cast(r); + __grin_check_row(_r, 0); + return std::any_cast((*_r)[idx]); +} + +GRIN_ROW grin_create_row(GRIN_GRAPH g) { + auto r = new GRIN_ROW_T(); + return r; +} + +bool grin_insert_int32_to_row(GRIN_GRAPH g, GRIN_ROW r, int value) { + auto _r = static_cast(r); + _r->push_back(value); + return true; +} + +bool grin_insert_uint32_to_row(GRIN_GRAPH g, GRIN_ROW r, unsigned int value) { + auto _r = static_cast(r); + _r->push_back(value); + return true; +} + +bool grin_insert_int64_to_row(GRIN_GRAPH g, GRIN_ROW r, + long long int value) { // NOLINT + auto _r = static_cast(r); + _r->push_back(value); + return true; +} + +bool grin_insert_uint64_to_row(GRIN_GRAPH g, GRIN_ROW r, + unsigned long long int value) { // NOLINT + auto _r = static_cast(r); + _r->push_back(value); + return true; +} + +bool grin_insert_float_to_row(GRIN_GRAPH g, GRIN_ROW r, float value) { + auto _r = static_cast(r); + _r->push_back(value); + return true; +} + +bool grin_insert_double_to_row(GRIN_GRAPH g, GRIN_ROW r, double value) { + auto _r = static_cast(r); + _r->push_back(value); + return true; +} + +bool grin_insert_string_to_row(GRIN_GRAPH g, GRIN_ROW r, const char* value) { + auto _r = static_cast(r); + _r->push_back(std::string(value)); + return true; +} + +bool grin_insert_date32_to_row(GRIN_GRAPH g, GRIN_ROW r, int value) { + auto _r = static_cast(r); + _r->push_back(value); + return true; +} + +bool grin_insert_time32_to_row(GRIN_GRAPH g, GRIN_ROW r, int value) { + auto _r = static_cast(r); + _r->push_back(value); + return true; +} + +bool grin_insert_timestamp64_to_row(GRIN_GRAPH g, GRIN_ROW r, + long long int value) { // NOLINT + auto _r = static_cast(r); + _r->push_back(value); + return true; +} +#endif + +#if defined(GRIN_ENABLE_ROW) && defined(GRIN_TRAIT_CONST_VALUE_PTR) +const void* grin_get_value_from_row(GRIN_GRAPH g, GRIN_ROW r, + GRIN_DATATYPE type, size_t idx) { + auto _r = static_cast(r); + __grin_check_row(_r, NULL); + switch (type) { + case GRIN_DATATYPE::Int32: + return &std::any_cast((*_r)[idx]); + case GRIN_DATATYPE::UInt32: + return &std::any_cast((*_r)[idx]); + case GRIN_DATATYPE::Int64: + return &std::any_cast((*_r)[idx]); + case GRIN_DATATYPE::UInt64: + return &std::any_cast((*_r)[idx]); + case GRIN_DATATYPE::Float: + return &std::any_cast((*_r)[idx]); + case GRIN_DATATYPE::Double: + return &std::any_cast((*_r)[idx]); + case GRIN_DATATYPE::String: + return std::any_cast((*_r)[idx]).c_str(); + case GRIN_DATATYPE::Date32: + return &std::any_cast((*_r)[idx]); + case GRIN_DATATYPE::Time32: + return &std::any_cast((*_r)[idx]); + case GRIN_DATATYPE::Timestamp64: + return &std::any_cast((*_r)[idx]); + default: + return NULL; + } + return NULL; +} +#endif + +#if defined(GRIN_WITH_VERTEX_PROPERTY) && defined(GRIN_ENABLE_ROW) +GRIN_ROW grin_get_vertex_row(GRIN_GRAPH g, GRIN_VERTEX v) { + auto _g = static_cast(g); + auto r = new GRIN_ROW_T(); + auto vtype = DEMO_STORAGE_NAMESPACE::get_type_id_from_gid(v); + auto _v = _g->GetVertex(v); + auto& properties = _g->GetVertexProperties(vtype); + for (auto& property : properties) { + r->push_back(_v.GetPropertyAny(property.name_)); + } + return r; +} +#endif + +#if defined(GRIN_WITH_EDGE_PROPERTY) && defined(GRIN_ENABLE_ROW) +GRIN_ROW grin_get_edge_row(GRIN_GRAPH g, GRIN_EDGE e) { + auto _g = static_cast(g); + auto r = new GRIN_ROW_T(); + auto etype = DEMO_STORAGE_NAMESPACE::get_type_id_from_gid(e); + auto _e = _g->GetEdge(e); + auto& properties = _g->GetEdgeProperties(etype); + for (auto& property : properties) { + r->push_back(_e.GetPropertyAny(property.name_)); + } + return r; +} +#endif diff --git a/demo_storage/src/property/topology.cc b/demo_storage/src/property/topology.cc new file mode 100644 index 0000000..ffff9ac --- /dev/null +++ b/demo_storage/src/property/topology.cc @@ -0,0 +1,65 @@ +/** Copyright 2020 Alibaba Group Holding Limited. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "src/predefine.h" +// GRIN headers +#include "property/topology.h" + +#ifdef GRIN_WITH_VERTEX_PROPERTY +size_t grin_get_vertex_num_by_type(GRIN_GRAPH g, GRIN_VERTEX_TYPE vtype) { + auto _g = static_cast(g); + return _g->GetVertexNum(vtype); +} +#endif + +#ifdef GRIN_WITH_EDGE_PROPERTY +size_t grin_get_edge_num_by_type(GRIN_GRAPH g, GRIN_EDGE_TYPE etype) { + auto _g = static_cast(g); + return _g->GetEdgeNum(etype); +} +#endif + +#if defined(GRIN_ENABLE_VERTEX_LIST) && defined(GRIN_WITH_VERTEX_PROPERTY) +GRIN_VERTEX_LIST grin_get_vertex_list_by_type(GRIN_GRAPH g, + GRIN_VERTEX_TYPE vtype) { + auto _g = static_cast(g); + if (vtype >= _g->GetVertexTypeNum()) + return GRIN_NULL_VERTEX_LIST; + auto vl = new GRIN_VERTEX_LIST_T(vtype); + return vl; +} +#endif + +#if defined(GRIN_ENABLE_EDGE_LIST) && defined(GRIN_WITH_EDGE_PROPERTY) +GRIN_EDGE_LIST grin_get_edge_list_by_type(GRIN_GRAPH g, GRIN_EDGE_TYPE etype) { + auto _g = static_cast(g); + if (etype >= _g->GetEdgeTypeNum()) + return GRIN_NULL_EDGE_LIST; + auto el = new GRIN_EDGE_LIST_T(etype); + return el; +} +#endif + +#if defined(GRIN_ENABLE_ADJACENT_LIST) && defined(GRIN_WITH_EDGE_PROPERTY) +GRIN_ADJACENT_LIST grin_get_adjacent_list_by_edge_type(GRIN_GRAPH g, + GRIN_DIRECTION d, + GRIN_VERTEX v, + GRIN_EDGE_TYPE etype) { + auto _g = static_cast(g); + if (etype >= _g->GetEdgeTypeNum()) + return GRIN_NULL_ADJACENT_LIST; + auto al = new GRIN_ADJACENT_LIST_T( + DEMO_STORAGE_NAMESPACE::get_type_id_from_gid(v), + DEMO_STORAGE_NAMESPACE::get_id_from_gid(v), d, etype); + return al; +} +#endif diff --git a/demo_storage/src/property/type.cc b/demo_storage/src/property/type.cc new file mode 100644 index 0000000..234a86c --- /dev/null +++ b/demo_storage/src/property/type.cc @@ -0,0 +1,223 @@ +/** Copyright 2020 Alibaba Group Holding Limited. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "src/predefine.h" +// GRIN headers +#include "property/type.h" + +#ifdef GRIN_WITH_VERTEX_PROPERTY +// Vertex type +bool grin_equal_vertex_type(GRIN_GRAPH g, GRIN_VERTEX_TYPE vtype1, + GRIN_VERTEX_TYPE vtype2) { + return vtype1 == vtype2; +} + +GRIN_VERTEX_TYPE grin_get_vertex_type(GRIN_GRAPH g, GRIN_VERTEX v) { + return DEMO_STORAGE_NAMESPACE::get_type_id_from_gid(v); +} + +void grin_destroy_vertex_type(GRIN_GRAPH g, GRIN_VERTEX_TYPE vtype) { return; } + +// Vertex type list +GRIN_VERTEX_TYPE_LIST grin_get_vertex_type_list(GRIN_GRAPH g) { + auto _g = static_cast(g); + auto vtl = new GRIN_VERTEX_TYPE_LIST_T(); + auto num = _g->GetVertexTypeNum(); + for (auto i = 0; i < num; i++) + vtl->push_back(i); + return vtl; +} + +void grin_destroy_vertex_type_list(GRIN_GRAPH g, GRIN_VERTEX_TYPE_LIST vtl) { + auto _vtl = static_cast(vtl); + delete _vtl; +} + +GRIN_VERTEX_TYPE_LIST grin_create_vertex_type_list(GRIN_GRAPH g) { + auto vtl = new GRIN_VERTEX_TYPE_LIST_T(); + return vtl; +} + +bool grin_insert_vertex_type_to_list(GRIN_GRAPH g, GRIN_VERTEX_TYPE_LIST vtl, + GRIN_VERTEX_TYPE vtype) { + auto _vtl = static_cast(vtl); + _vtl->push_back(vtype); + return true; +} + +size_t grin_get_vertex_type_list_size(GRIN_GRAPH g, GRIN_VERTEX_TYPE_LIST vtl) { + auto _vtl = static_cast(vtl); + return _vtl->size(); +} + +GRIN_VERTEX_TYPE grin_get_vertex_type_from_list(GRIN_GRAPH g, + GRIN_VERTEX_TYPE_LIST vtl, + size_t idx) { + auto _vtl = static_cast(vtl); + if (idx >= _vtl->size()) + return GRIN_NULL_VERTEX_TYPE; + return (*_vtl)[idx]; +} +#endif + +#ifdef GRIN_WITH_VERTEX_TYPE_NAME +const char* grin_get_vertex_type_name(GRIN_GRAPH g, GRIN_VERTEX_TYPE vtype) { + auto _g = static_cast(g); + if (vtype >= _g->GetVertexTypeNum()) + return NULL; + return _g->GetVertexTypeName(vtype).c_str(); +} + +GRIN_VERTEX_TYPE grin_get_vertex_type_by_name(GRIN_GRAPH g, const char* name) { + auto _g = static_cast(g); + auto type_id = _g->GetVertexTypeId(std::string(name)); + if (type_id == -1) + return GRIN_NULL_VERTEX_TYPE; + return type_id; +} +#endif + +#ifdef GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_TYPE +GRIN_VERTEX_TYPE_ID grin_get_vertex_type_id(GRIN_GRAPH g, + GRIN_VERTEX_TYPE vtype) { + return vtype; +} + +GRIN_VERTEX_TYPE grin_get_vertex_type_by_id(GRIN_GRAPH g, + GRIN_VERTEX_TYPE_ID vti) { + return vti; +} +#endif + +#ifdef GRIN_WITH_EDGE_PROPERTY +// Edge type +bool grin_equal_edge_type(GRIN_GRAPH g, GRIN_EDGE_TYPE etype1, + GRIN_EDGE_TYPE etype2) { + return etype1 == etype2; +} + +GRIN_EDGE_TYPE grin_get_edge_type(GRIN_GRAPH g, GRIN_EDGE e) { + return DEMO_STORAGE_NAMESPACE::get_type_id_from_gid(e); +} + +void grin_destroy_edge_type(GRIN_GRAPH g, GRIN_EDGE_TYPE etype) { return; } + +// Edge type list +GRIN_EDGE_TYPE_LIST grin_get_edge_type_list(GRIN_GRAPH g) { + auto _g = static_cast(g); + auto etl = new GRIN_EDGE_TYPE_LIST_T(); + auto num = _g->GetEdgeTypeNum(); + for (auto i = 0; i < num; i++) + etl->push_back(i); + return etl; +} + +void grin_destroy_edge_type_list(GRIN_GRAPH g, GRIN_EDGE_TYPE_LIST etl) { + auto _etl = static_cast(etl); + delete _etl; +} + +GRIN_EDGE_TYPE_LIST grin_create_edge_type_list(GRIN_GRAPH g) { + auto etl = new GRIN_EDGE_TYPE_LIST_T(); + return etl; +} + +bool grin_insert_edge_type_to_list(GRIN_GRAPH g, GRIN_EDGE_TYPE_LIST etl, + GRIN_EDGE_TYPE etype) { + auto _etl = static_cast(etl); + _etl->push_back(etype); + return true; +} + +size_t grin_get_edge_type_list_size(GRIN_GRAPH g, GRIN_EDGE_TYPE_LIST etl) { + auto _etl = static_cast(etl); + return _etl->size(); +} + +GRIN_EDGE_TYPE grin_get_edge_type_from_list(GRIN_GRAPH g, + GRIN_EDGE_TYPE_LIST etl, + size_t idx) { + auto _etl = static_cast(etl); + if (idx >= _etl->size()) + return GRIN_NULL_EDGE_TYPE; + return (*_etl)[idx]; +} +#endif + +#ifdef GRIN_WITH_EDGE_TYPE_NAME +const char* grin_get_edge_type_name(GRIN_GRAPH g, GRIN_EDGE_TYPE etype) { + auto _g = static_cast(g); + if (etype >= _g->GetEdgeTypeNum()) + return NULL; + return _g->GetEdgeTypeName(etype).c_str(); +} + +GRIN_EDGE_TYPE grin_get_edge_type_by_name(GRIN_GRAPH g, const char* name) { + auto _g = static_cast(g); + auto type_id = _g->GetEdgeTypeId(std::string(name)); + if (type_id == -1) + return GRIN_NULL_EDGE_TYPE; + return type_id; +} +#endif + +#ifdef GRIN_TRAIT_NATURAL_ID_FOR_EDGE_TYPE +GRIN_EDGE_TYPE_ID grin_get_edge_type_id(GRIN_GRAPH g, GRIN_EDGE_TYPE etype) { + return etype; +} + +GRIN_EDGE_TYPE grin_get_edge_type_by_id(GRIN_GRAPH g, GRIN_EDGE_TYPE_ID eti) { + return eti; +} +#endif + +#if defined(GRIN_WITH_VERTEX_PROPERTY) && defined(GRIN_WITH_EDGE_PROPERTY) +GRIN_VERTEX_TYPE_LIST grin_get_src_types_by_edge_type(GRIN_GRAPH g, + GRIN_EDGE_TYPE etype) { + auto _g = static_cast(g); + auto vtl = new GRIN_VERTEX_TYPE_LIST_T(); + auto& vev_types = _g->GetVertexEdgeVertexTypes(); + for (auto& [vev_type, relation_type] : vev_types) { + if (std::get<1>(vev_type) == etype) { + vtl->push_back(std::get<0>(vev_type)); + } + } + return vtl; +} + +GRIN_VERTEX_TYPE_LIST grin_get_dst_types_by_edge_type(GRIN_GRAPH g, + GRIN_EDGE_TYPE etype) { + auto _g = static_cast(g); + auto vtl = new GRIN_VERTEX_TYPE_LIST_T(); + auto& vev_types = _g->GetVertexEdgeVertexTypes(); + for (auto& [vev_type, relation_type] : vev_types) { + if (std::get<1>(vev_type) == etype) { + vtl->push_back(std::get<2>(vev_type)); + } + } + return vtl; +} + +GRIN_EDGE_TYPE_LIST +grin_get_edge_types_by_vertex_type_pair(GRIN_GRAPH g, GRIN_VERTEX_TYPE vtype1, + GRIN_VERTEX_TYPE vtype2) { + auto _g = static_cast(g); + auto etl = new GRIN_EDGE_TYPE_LIST_T(); + auto& vev_types = _g->GetVertexEdgeVertexTypes(); + for (auto& [vev_type, relation_type] : vev_types) { + if (std::get<0>(vev_type) == vtype1 && std::get<2>(vev_type) == vtype2) { + etl->push_back(std::get<1>(vev_type)); + } + } + return etl; +} +#endif From dee26583df043474b3336893c03a1cbd221bdc69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Tue, 26 Sep 2023 14:23:42 +0800 Subject: [PATCH 27/48] Add test files --- demo_storage/test/config.h | 46 +++ demo_storage/test/test_index.cc | 201 ++++++++++ demo_storage/test/test_index_label.cc | 224 +++++++++++ demo_storage/test/test_partition.cc | 120 ++++++ demo_storage/test/test_partition_reference.cc | 276 +++++++++++++ demo_storage/test/test_partition_topology.cc | 364 ++++++++++++++++++ demo_storage/test/test_property_list.cc | 226 +++++++++++ demo_storage/test/test_property_primarykey.cc | 180 +++++++++ demo_storage/test/test_property_topology.cc | 196 ++++++++++ demo_storage/test/test_property_type.cc | 244 ++++++++++++ demo_storage/test/test_property_value.cc | 327 ++++++++++++++++ demo_storage/test/test_topology.cc | 257 +++++++++++++ 12 files changed, 2661 insertions(+) create mode 100644 demo_storage/test/config.h create mode 100644 demo_storage/test/test_index.cc create mode 100644 demo_storage/test/test_index_label.cc create mode 100644 demo_storage/test/test_partition.cc create mode 100644 demo_storage/test/test_partition_reference.cc create mode 100644 demo_storage/test/test_partition_topology.cc create mode 100644 demo_storage/test/test_property_list.cc create mode 100644 demo_storage/test/test_property_primarykey.cc create mode 100644 demo_storage/test/test_property_topology.cc create mode 100644 demo_storage/test/test_property_type.cc create mode 100644 demo_storage/test/test_property_value.cc create mode 100644 demo_storage/test/test_topology.cc diff --git a/demo_storage/test/config.h b/demo_storage/test/config.h new file mode 100644 index 0000000..db2f6fd --- /dev/null +++ b/demo_storage/test/config.h @@ -0,0 +1,46 @@ +/** Copyright 2020 Alibaba Group Holding Limited. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef TEST_CONFIG_H_ +#define TEST_CONFIG_H_ + +// Define a new macro that is just like the standard C assert macro, +// except that it works even in optimized builds (where NDEBUG is +// defined) and it prints the failed assertion to stderr. +#ifndef ASSERT +#define ASSERT(x) \ + if (!(x)) { \ + char buf[2048]; \ + snprintf(buf, sizeof(buf), \ + "Assertion failed in \"%s\", line %d\n" \ + "\tProbable bug in software.\n", \ + __FILE__, __LINE__); \ + ABORT(buf); \ + } else // NOLINT +// The 'else' exists to catch the user's following semicolon +#endif + +// Define a new macro that is just like the standard C abort macro, +// except that it prints the failed assertion to stderr. +#ifndef ABORT +#define ABORT(msg) \ + do { \ + fprintf(stderr, "%s", msg); \ + fflush(stderr); \ + abort(); \ + } while (0) +#endif + +#endif // TEST_CONFIG_H_ diff --git a/demo_storage/test/test_index.cc b/demo_storage/test/test_index.cc new file mode 100644 index 0000000..07ea542 --- /dev/null +++ b/demo_storage/test/test_index.cc @@ -0,0 +1,201 @@ +/** Copyright 2020 Alibaba Group Holding Limited. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include + +// predefine for GRIN +#include "../predefine.h" +// storage headers +#include "storage/loadmoderngraph.h" +// test config headers +#include "test/config.h" +// GRIN headers +#include "index/external_id.h" +#include "index/internal_id.h" +#include "index/order.h" +#include "index/pk.h" +#include "property/primarykey.h" +#include "property/topology.h" +#include "property/type.h" +#include "topology/structure.h" +#include "topology/vertexlist.h" + +void test_index_order(GRIN_GRAPH graph) { + std::cout << "\n++++ test index: order ++++" << std::endl; + + std::cout << "test vertex order" << std::endl; + auto vtype = grin_get_vertex_type_by_id(graph, 0); + auto vertex_list = grin_get_vertex_list_by_type(graph, vtype); + size_t idx0 = 0, idx1 = 1; + auto v0 = grin_get_vertex_from_list(graph, vertex_list, idx0); + auto v1 = grin_get_vertex_from_list(graph, vertex_list, idx1); + ASSERT(grin_smaller_vertex(graph, v0, v1) == true); + ASSERT(grin_smaller_vertex(graph, v1, v0) == false); + + std::cout << "test get position of vertex from sorted list" << std::endl; + size_t pos0 = + grin_get_position_of_vertex_from_sorted_list(graph, vertex_list, v0); + size_t pos1 = + grin_get_position_of_vertex_from_sorted_list(graph, vertex_list, v1); + ASSERT(pos0 == idx0); + ASSERT(pos1 == idx1); + + // destroy + grin_destroy_vertex(graph, v0); + grin_destroy_vertex(graph, v1); + grin_destroy_vertex_list(graph, vertex_list); + grin_destroy_vertex_type(graph, vtype); + + std::cout << "---- test index: order completed ----" << std::endl; +} + +void test_internal_id(GRIN_GRAPH graph) { + std::cout << "\n++++ test index: internal id ++++" << std::endl; + + std::cout << "test vertex internal id" << std::endl; + auto vtype = grin_get_vertex_type_by_id(graph, 0); + auto vertex_list = grin_get_vertex_list_by_type(graph, vtype); + size_t idx0 = 0, idx1 = 1; + auto v0 = grin_get_vertex_from_list(graph, vertex_list, idx0); + auto v1 = grin_get_vertex_from_list(graph, vertex_list, idx1); + + // get internal id of vertex + auto id0 = grin_get_vertex_internal_id_by_type(graph, vtype, v0); + auto id1 = grin_get_vertex_internal_id_by_type(graph, vtype, v1); + std::cout << "internal id of v0 = " << id0 << std::endl; + std::cout << "internal id of v1 = " << id1 << std::endl; + + // get vertex by internal id + auto v0_from_id = grin_get_vertex_by_internal_id_by_type(graph, vtype, id0); + auto v1_from_id = grin_get_vertex_by_internal_id_by_type(graph, vtype, id1); + ASSERT(grin_equal_vertex(graph, v0, v0_from_id) == true); + ASSERT(grin_equal_vertex(graph, v1, v1_from_id) == true); + + auto lower_bound = + grin_get_vertex_internal_id_lower_bound_by_type(graph, vtype); + std::cout << "lower bound of internal id = " << lower_bound << std::endl; + auto upper_bound = + grin_get_vertex_internal_id_upper_bound_by_type(graph, vtype); + std::cout << "upper bound of internal id = " << upper_bound << std::endl; + + // destroy + grin_destroy_vertex(graph, v0); + grin_destroy_vertex(graph, v1); + grin_destroy_vertex(graph, v0_from_id); + grin_destroy_vertex(graph, v1_from_id); + grin_destroy_vertex_list(graph, vertex_list); + grin_destroy_vertex_type(graph, vtype); + + std::cout << "---- test index: internal id completed ----" << std::endl; +} + +void test_external_id(GRIN_GRAPH graph) { + std::cout << "\n++++ test index: external id ++++" << std::endl; + + std::cout << "test vertex external id: int64" << std::endl; + auto vtype = grin_get_vertex_type_by_id(graph, 0); + auto vertex_list = grin_get_vertex_list_by_type(graph, vtype); + size_t idx0 = 0, idx1 = 1; + auto v0 = grin_get_vertex_from_list(graph, vertex_list, idx0); + auto v1 = grin_get_vertex_from_list(graph, vertex_list, idx1); + + // get external id of int64 + auto id0 = grin_get_vertex_external_id_of_int64(graph, v0); + auto id1 = grin_get_vertex_external_id_of_int64(graph, v1); + std::cout << "external id of v0 = " << id0 << std::endl; + std::cout << "external id of v1 = " << id1 << std::endl; + + // get vertex by external id + auto v0_from_id = grin_get_vertex_by_external_id_of_int64(graph, id0); + auto v1_from_id = grin_get_vertex_by_external_id_of_int64(graph, id1); + ASSERT(grin_equal_vertex(graph, v0, v0_from_id) == true); + ASSERT(grin_equal_vertex(graph, v1, v1_from_id) == true); + + std::cout << "test vertex external id: string" << std::endl; + // get external id of string + auto id0_str = grin_get_vertex_external_id_of_string(graph, v0); + auto id1_str = grin_get_vertex_external_id_of_string(graph, v1); + std::cout << "external id of v0 = " << id0_str << std::endl; + std::cout << "external id of v1 = " << id1_str << std::endl; + + // get vertex by external id + auto v0_from_id_str = + grin_get_vertex_by_external_id_of_string(graph, id0_str); + auto v1_from_id_str = + grin_get_vertex_by_external_id_of_string(graph, id1_str); + ASSERT(grin_equal_vertex(graph, v0, v0_from_id_str) == true); + ASSERT(grin_equal_vertex(graph, v1, v1_from_id_str) == true); + + // destroy + grin_destroy_vertex(graph, v0); + grin_destroy_vertex(graph, v1); + grin_destroy_vertex(graph, v0_from_id); + grin_destroy_vertex(graph, v1_from_id); + grin_destroy_vertex(graph, v0_from_id_str); + grin_destroy_vertex(graph, v1_from_id_str); + grin_destroy_vertex_list(graph, vertex_list); + grin_destroy_vertex_type(graph, vtype); + + std::cout << "---- test index: internal id completed ----" << std::endl; +} + +void test_pk(GRIN_GRAPH graph) { + std::cout << "\n++++ test index: pk ++++" << std::endl; + + auto vertex_type = grin_get_vertex_type_by_id(graph, 0); + auto vertex_list = grin_get_vertex_list_by_type(graph, vertex_type); + auto v0 = grin_get_vertex_from_list(graph, vertex_list, 0); + auto row = grin_get_vertex_primary_keys_row(graph, v0); + auto v1 = grin_get_vertex_by_primary_keys_row(graph, vertex_type, row); + ASSERT(grin_equal_vertex(graph, v0, v1) == true); + std::cout << "vertex from pk is equal to the original vertex" << std::endl; + + std::cout << "---- test index: pk completed ----" << std::endl; +} + +int main() { + // load graph + std::cout << "load modern graph" << std::endl; + std::string graph_name = "modern_graph"; + char* graph_name_str = new char[graph_name.size() + 1]; + snprintf(graph_name_str, graph_name.size() + 1, "%s", graph_name.c_str()); + demo_storage_load_modern_graph(graph_name_str, 1, 0); + delete[] graph_name_str; + + // get grin graph + std::string uri = "demo_storage://" + graph_name; + std::cout << "get grin graph from uri: " << uri << std::endl; + char* uri_str = new char[uri.size() + 1]; + snprintf(uri_str, uri.size() + 1, "%s", uri.c_str()); + GRIN_GRAPH graph = grin_get_graph_from_storage(uri_str); + delete[] uri_str; + + // test index order + test_index_order(graph); + + // test internal id + test_internal_id(graph); + + // test external id + test_external_id(graph); + + // test pk + test_pk(graph); + + // destroy graph + grin_destroy_graph(graph); + + return 0; +} diff --git a/demo_storage/test/test_index_label.cc b/demo_storage/test/test_index_label.cc new file mode 100644 index 0000000..1f7836b --- /dev/null +++ b/demo_storage/test/test_index_label.cc @@ -0,0 +1,224 @@ +/** Copyright 2020 Alibaba Group Holding Limited. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include + +// predefine for GRIN +#include "../predefine.h" +// storage headers +#include "storage/loadmoderngraph.h" +// test config headers +#include "test/config.h" +// GRIN headers +#include "index/internal_id.h" +#include "index/label.h" +#include "index/order.h" +#include "property/topology.h" +#include "property/type.h" +#include "topology/edgelist.h" +#include "topology/structure.h" +#include "topology/vertexlist.h" + +void test_vertex_label(GRIN_GRAPH graph) { + std::cout << "\n++++ test index: vertex label ++++" << std::endl; + auto vertex_label_list = grin_get_vertex_label_list(graph); + auto vertex_label_list_size = + grin_get_label_list_size(graph, vertex_label_list); + std::cout << "vertex label list size: " << vertex_label_list_size + << std::endl; + + for (size_t i = 0; i < vertex_label_list_size; ++i) { + auto vertex_label = grin_get_label_from_list(graph, vertex_label_list, i); + auto vertex_label_name = grin_get_label_name(graph, vertex_label); + std::cout << "vertex label name: " << vertex_label_name << std::endl; + auto vertex_label_2 = grin_get_label_by_name(graph, vertex_label_name); + ASSERT(vertex_label == vertex_label_2); + + // get vertex types by label + auto vertex_type_list = + grin_get_vertex_type_list_by_label(graph, vertex_label); + auto vertex_type_list_size = + grin_get_label_list_size(graph, vertex_type_list); + std::cout << "vertex type list size for this label: " + << vertex_type_list_size << std::endl; + + // destroy + grin_destroy_label(graph, vertex_label); + grin_destroy_label(graph, vertex_label_2); + grin_destroy_vertex_type_list(graph, vertex_type_list); + } + + // destroy vertex label list + grin_destroy_label_list(graph, vertex_label_list); + + auto vertex_type = grin_get_vertex_type_by_name(graph, "person"); + auto vertex_list = grin_get_vertex_list_by_type(graph, vertex_type); + auto vertex = grin_get_vertex_from_list(graph, vertex_list, 0); + auto label_list = grin_get_label_list_by_vertex(graph, vertex); + auto label_list_size = grin_get_label_list_size(graph, label_list); + std::cout << "label list size for vertex person #0: " << label_list_size + << std::endl; + + for (size_t i = 0; i < label_list_size; ++i) { + auto label = grin_get_label_from_list(graph, label_list, i); + auto label_name = grin_get_label_name(graph, label); + std::cout << "label name: " << label_name << std::endl; + grin_destroy_label(graph, label); + } + + // get vertex list by label + auto label = grin_get_label_by_name(graph, "v_label_0"); + auto vertex_list_2 = + grin_get_vertex_list_by_type_by_label(graph, vertex_type, label); + auto vertex_list_size = grin_get_vertex_list_size(graph, vertex_list_2); + std::cout << "vertex list size for v_label_0 of type #0: " << vertex_list_size + << std::endl; + + // check array & iterator + auto iter = grin_get_vertex_list_begin(graph, vertex_list_2); + for (size_t i = 0; i < vertex_list_size; ++i) { + ASSERT(!grin_is_vertex_list_end(graph, iter)); + auto vertex = grin_get_vertex_from_list(graph, vertex_list_2, i); + auto vertex2 = grin_get_vertex_from_iter(graph, iter); + ASSERT(vertex == vertex2); + auto id = grin_get_vertex_internal_id_by_type(graph, vertex_type, vertex); + std::cout << "vertex internal id: " << id << std::endl; + // check order + auto pos = grin_get_position_of_vertex_from_sorted_list( + graph, vertex_list_2, vertex); + ASSERT(pos == i); + // get next & destroy + grin_get_next_vertex_list_iter(graph, iter); + grin_destroy_vertex(graph, vertex); + grin_destroy_vertex(graph, vertex2); + } + ASSERT(grin_is_vertex_list_end(graph, iter)); + grin_destroy_vertex_list_iter(graph, iter); + std::cout << "check array & iterator done" << std::endl; + + // destroy + grin_destroy_label(graph, label); + grin_destroy_label_list(graph, label_list); + grin_destroy_vertex(graph, vertex); + grin_destroy_vertex_list(graph, vertex_list); + grin_destroy_vertex_type(graph, vertex_type); + grin_destroy_vertex_list(graph, vertex_list_2); +} + +void test_edge_label(GRIN_GRAPH graph) { + std::cout << "\n++++ test index: edge label ++++" << std::endl; + auto edge_label_list = grin_get_edge_label_list(graph); + auto edge_label_list_size = grin_get_label_list_size(graph, edge_label_list); + std::cout << "edge label list size: " << edge_label_list_size << std::endl; + + for (size_t i = 0; i < edge_label_list_size; ++i) { + auto edge_label = grin_get_label_from_list(graph, edge_label_list, i); + auto edge_label_name = grin_get_label_name(graph, edge_label); + std::cout << "edge label name: " << edge_label_name << std::endl; + auto edge_label_2 = grin_get_label_by_name(graph, edge_label_name); + ASSERT(edge_label == edge_label_2); + + // get vertex types by label + auto edge_type_list = grin_get_edge_type_list_by_label(graph, edge_label); + auto edge_type_list_size = grin_get_label_list_size(graph, edge_type_list); + std::cout << "edge type list size for this label: " << edge_type_list_size + << std::endl; + + // destroy + grin_destroy_label(graph, edge_label); + grin_destroy_label(graph, edge_label_2); + grin_destroy_vertex_type_list(graph, edge_type_list); + } + + // destroy edge label list + grin_destroy_label_list(graph, edge_label_list); + + auto edge_type = grin_get_edge_type_by_name(graph, "knows"); + auto edge_list = grin_get_edge_list_by_type(graph, edge_type); + auto edge = grin_get_edge_from_list(graph, edge_list, 0); + auto label_list = grin_get_label_list_by_edge(graph, edge); + auto label_list_size = grin_get_label_list_size(graph, label_list); + std::cout << "label list size for edge knows #0: " << label_list_size + << std::endl; + + for (size_t i = 0; i < label_list_size; ++i) { + auto label = grin_get_label_from_list(graph, label_list, i); + auto label_name = grin_get_label_name(graph, label); + std::cout << "label name: " << label_name << std::endl; + grin_destroy_label(graph, label); + } + + // get edge list by label + auto label = grin_get_label_by_name(graph, "e_label_0"); + auto edge_list_2 = + grin_get_edge_list_by_type_by_label(graph, edge_type, label); + auto edge_list_size = grin_get_edge_list_size(graph, edge_list_2); + std::cout << "edge list size for e_label_0 of type #0: " << edge_list_size + << std::endl; + + // check array & iterator + auto iter = grin_get_edge_list_begin(graph, edge_list_2); + for (size_t i = 0; i < edge_list_size; ++i) { + ASSERT(!grin_is_edge_list_end(graph, iter)); + auto edge = grin_get_edge_from_list(graph, edge_list_2, i); + auto edge2 = grin_get_edge_from_iter(graph, iter); + ASSERT(edge == edge2); + std::cout << "edge " << i << std::endl; + // get next & destroy + grin_destroy_edge(graph, edge); + grin_destroy_edge(graph, edge2); + grin_get_next_edge_list_iter(graph, iter); + } + ASSERT(grin_is_edge_list_end(graph, iter)); + grin_destroy_edge_list_iter(graph, iter); + std::cout << "check array & iterator done" << std::endl; + + // destroy + grin_destroy_label(graph, label); + grin_destroy_label_list(graph, label_list); + grin_destroy_edge(graph, edge); + grin_destroy_edge_list(graph, edge_list); + grin_destroy_edge_type(graph, edge_type); + grin_destroy_edge_list(graph, edge_list_2); +} + +int main() { + // load graph + std::cout << "load modern graph" << std::endl; + std::string graph_name = "modern_graph"; + char* graph_name_str = new char[graph_name.size() + 1]; + snprintf(graph_name_str, graph_name.size() + 1, "%s", graph_name.c_str()); + demo_storage_load_modern_graph(graph_name_str, 1, 0); + delete[] graph_name_str; + + // get grin graph + std::string uri = "demo_storage://" + graph_name; + std::cout << "get grin graph from uri: " << uri << std::endl; + char* uri_str = new char[uri.size() + 1]; + snprintf(uri_str, uri.size() + 1, "%s", uri.c_str()); + GRIN_GRAPH graph = grin_get_graph_from_storage(uri_str); + delete[] uri_str; + + // test vertex label + test_vertex_label(graph); + + // test edge label + test_edge_label(graph); + + // destroy graph + grin_destroy_graph(graph); + + return 0; +} diff --git a/demo_storage/test/test_partition.cc b/demo_storage/test/test_partition.cc new file mode 100644 index 0000000..e8a9f0a --- /dev/null +++ b/demo_storage/test/test_partition.cc @@ -0,0 +1,120 @@ +/** Copyright 2020 Alibaba Group Holding Limited. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include + +// predefine for GRIN +#include "../predefine.h" +// storage headers +#include "storage/loadmoderngraph.h" +// test config headers +#include "test/config.h" +// GRIN headers +#include "partition/partition.h" +#include "topology/structure.h" + +void test_partition_partition(GRIN_PARTITIONED_GRAPH pg, unsigned n) { + std::cout << "\n++++ test partition: partition ++++" << std::endl; + + // check partition number + ASSERT(pg != GRIN_NULL_GRAPH); + auto partition_num = grin_get_total_partitions_number(pg); + ASSERT(partition_num == n); + std::cout << "partition number = " << partition_num << std::endl; + + // check partition list + auto partition_list = grin_get_local_partition_list(pg); + ASSERT(partition_list != GRIN_NULL_PARTITION_LIST); + auto partition_list_size = grin_get_partition_list_size(pg, partition_list); + ASSERT(partition_list_size == 1); + std::cout << "local partition number = " << partition_list_size << std::endl; + + // check create new partition list + auto new_partition_list = grin_create_partition_list(pg); + ASSERT(new_partition_list != GRIN_NULL_PARTITION_LIST); + for (auto i = 0; i < partition_list_size; ++i) { + // get & insert partition + auto partition = grin_get_partition_from_list(pg, partition_list, i); + auto status = + grin_insert_partition_to_list(pg, new_partition_list, partition); + ASSERT(status == true); + // check & destroy partition + auto partition_from_new_list = + grin_get_partition_from_list(pg, new_partition_list, i); + ASSERT(grin_equal_partition(pg, partition, partition_from_new_list) == + true); + grin_destroy_partition(pg, partition); + grin_destroy_partition(pg, partition_from_new_list); + } + ASSERT(grin_get_partition_list_size(pg, new_partition_list) == + partition_list_size); + grin_destroy_partition_list(pg, new_partition_list); + + // check partition id + auto partition_a = grin_get_partition_from_list(pg, partition_list, 0); + auto id = grin_get_partition_id(pg, partition_a); + auto partition_b = grin_get_partition_by_id(pg, id); + ASSERT(grin_equal_partition(pg, partition_a, partition_b) == true); + grin_destroy_partition(pg, partition_a); + grin_destroy_partition(pg, partition_b); + + // check get local graph + for (auto i = 0; i < partition_list_size; ++i) { + // get local graph from partition + auto partition = grin_get_partition_from_list(pg, partition_list, i); + auto info = grin_get_partition_info(pg, partition); + std::cout << "info of local partition " << i << std::endl; + std::cout << " " << static_cast(info) << std::endl; + auto graph = grin_get_local_graph_by_partition(pg, partition); + ASSERT(graph != GRIN_NULL_GRAPH); + // destroy + grin_destroy_partition(pg, partition); + grin_destroy_graph(graph); + } + + // destroy + grin_destroy_partition_list(pg, partition_list); + std::cout << "---- test partition: partition completed ----" << std::endl; +} + +int main() { + // load graph + uint32_t partition_num = 4; + uint32_t partition_id = 0; + std::cout << "load modern graph, partition_num = " << partition_num + << ", partition_id = " << partition_id << std::endl; + std::string graph_name = "modern_graph"; + char* graph_name_str = new char[graph_name.size() + 1]; + snprintf(graph_name_str, graph_name.size() + 1, "%s", graph_name.c_str()); + demo_storage_load_modern_graph(graph_name_str, partition_num, partition_id); + delete[] graph_name_str; + + // get grin graph + std::string uri = "demo_storage://" + graph_name + + "?partition_num=" + std::to_string(partition_num); + std::cout << "get grin graph from uri: " << uri << std::endl; + char* uri_str = new char[uri.size() + 1]; + snprintf(uri_str, uri.size() + 1, "%s", uri.c_str()); + GRIN_PARTITIONED_GRAPH pg = grin_get_partitioned_graph_from_storage(uri_str); + delete[] uri_str; + + // test partitioned graph + test_partition_partition(pg, partition_num); + + // destroy partitioned graph + grin_destroy_partitioned_graph(pg); + + return 0; +} diff --git a/demo_storage/test/test_partition_reference.cc b/demo_storage/test/test_partition_reference.cc new file mode 100644 index 0000000..048ec68 --- /dev/null +++ b/demo_storage/test/test_partition_reference.cc @@ -0,0 +1,276 @@ +/** Copyright 2020 Alibaba Group Holding Limited. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include + +// predefine for GRIN +#include "../predefine.h" +// storage headers +#include "storage/loadmoderngraph.h" +// test config headers +#include "test/config.h" +// GRIN headers +#include "partition/partition.h" +#include "partition/reference.h" +#include "property/topology.h" +#include "property/type.h" +#include "topology/edgelist.h" +#include "topology/structure.h" +#include "topology/vertexlist.h" + +void test_vertex_ref(GRIN_PARTITIONED_GRAPH pg, GRIN_GRAPH graph, + GRIN_VERTEX v) { + std::cout << "\n== test vertex ref ==" << std::endl; + + // check vertex ref + auto vr = grin_get_vertex_ref_by_vertex(graph, v); + auto v_from_vr = grin_get_vertex_from_vertex_ref(graph, vr); + ASSERT(grin_equal_vertex(graph, v, v_from_vr) == true); + + // serialize & deserialize vertex ref + auto msg = grin_serialize_vertex_ref(graph, vr); + std::cout << "serialized vertex ref = " << msg << std::endl; + auto vr_from_msg = grin_deserialize_to_vertex_ref(graph, msg); + auto v_from_vr_from_msg = grin_get_vertex_from_vertex_ref(graph, vr_from_msg); + ASSERT(grin_equal_vertex(graph, v, v_from_vr_from_msg) == true); + + // serialize & deserialize vertex ref as int64 + auto int64_msg = grin_serialize_vertex_ref_as_int64(graph, vr); + std::cout << "serialized vertex ref as int64 = " << int64_msg << std::endl; + auto vr_from_int64_msg = + grin_deserialize_int64_to_vertex_ref(graph, int64_msg); + auto v_from_vr_from_int64_msg = + grin_get_vertex_from_vertex_ref(graph, vr_from_int64_msg); + ASSERT(grin_equal_vertex(graph, v, v_from_vr_from_int64_msg) == true); + + // check master or mirror + auto is_master = grin_is_master_vertex(graph, v); + auto is_mirror = grin_is_mirror_vertex(graph, v); + ASSERT((is_master || is_mirror) && !(is_master && is_mirror)); + if (is_master) { + std::cout << "vertex is master, "; + } else { + std::cout << "vertex is mirror, "; + } + // get master partition id + auto master_partition = grin_get_master_partition_from_vertex_ref(graph, vr); + auto master_partition_id = grin_get_partition_id(pg, master_partition); + std::cout << "master partition id = " << master_partition_id << std::endl; + // get mirror_partition_list + if (is_master) { + ASSERT(grin_get_mirror_vertex_mirror_partition_list(graph, v) == + GRIN_NULL_PARTITION_LIST); + auto partition_list = + grin_get_master_vertex_mirror_partition_list(graph, v); + + std::cout << "mirror partition ids = "; + auto partition_list_size = grin_get_partition_list_size(pg, partition_list); + for (auto i = 0; i < partition_list_size; ++i) { + auto partition = grin_get_partition_from_list(pg, partition_list, i); + auto partition_id = grin_get_partition_id(pg, partition); + std::cout << " " << partition_id; + grin_destroy_partition(pg, partition); + } + std::cout << std::endl; + + grin_destroy_partition_list(pg, partition_list); + + } else { + ASSERT(grin_get_master_vertex_mirror_partition_list(graph, v) == + GRIN_NULL_PARTITION_LIST); + auto partition_list = + grin_get_mirror_vertex_mirror_partition_list(graph, v); + + std::cout << "mirror partition ids = "; + auto partition_list_size = grin_get_partition_list_size(pg, partition_list); + for (auto i = 0; i < partition_list_size; ++i) { + auto partition = grin_get_partition_from_list(pg, partition_list, i); + auto partition_id = grin_get_partition_id(pg, partition); + std::cout << " " << partition_id; + grin_destroy_partition(pg, partition); + } + std::cout << std::endl; + + grin_destroy_partition_list(pg, partition_list); + } + + // destroy + grin_destroy_partition(graph, master_partition); + grin_destroy_vertex(graph, v_from_vr); + grin_destroy_vertex(graph, v_from_vr_from_msg); + grin_destroy_vertex(graph, v_from_vr_from_int64_msg); + grin_destroy_vertex_ref(graph, vr); + grin_destroy_vertex_ref(graph, vr_from_msg); + grin_destroy_vertex_ref(graph, vr_from_int64_msg); + grin_destroy_serialized_vertex_ref(graph, msg); +} + +void test_edge_ref(GRIN_PARTITIONED_GRAPH pg, GRIN_GRAPH graph, GRIN_EDGE e) { + std::cout << "\n== test edge ref ==" << std::endl; + + // check edge ref + auto er = grin_get_vertex_ref_by_vertex(graph, e); + auto e_from_er = grin_get_vertex_from_vertex_ref(graph, er); + ASSERT(grin_equal_vertex(graph, e, e_from_er) == true); + + // serialize & deserialize edge ref + auto msg = grin_serialize_vertex_ref(graph, er); + std::cout << "serialized edge ref = " << msg << std::endl; + auto er_from_msg = grin_deserialize_to_vertex_ref(graph, msg); + auto e_from_er_from_msg = grin_get_vertex_from_vertex_ref(graph, er_from_msg); + ASSERT(grin_equal_vertex(graph, e, e_from_er_from_msg) == true); + + // check master or mirror + auto is_master = grin_is_master_vertex(graph, e); + auto is_mirror = grin_is_mirror_vertex(graph, e); + ASSERT((is_master || is_mirror) && !(is_master && is_mirror)); + if (is_master) { + std::cout << "edge is master, "; + } else { + std::cout << "edgeis mirror, "; + } + // get master partition id + auto master_partition = grin_get_master_partition_from_edge_ref(graph, er); + auto master_partition_id = grin_get_partition_id(pg, master_partition); + std::cout << "master partition id = " << master_partition_id << std::endl; + // get mirror_partition_list + if (is_master) { + ASSERT(grin_get_mirror_edge_mirror_partition_list(graph, e) == + GRIN_NULL_PARTITION_LIST); + auto partition_list = grin_get_master_edge_mirror_partition_list(graph, e); + + std::cout << "mirror partition ids = "; + auto partition_list_size = grin_get_partition_list_size(pg, partition_list); + for (auto i = 0; i < partition_list_size; ++i) { + auto partition = grin_get_partition_from_list(pg, partition_list, i); + auto partition_id = grin_get_partition_id(pg, partition); + std::cout << " " << partition_id; + grin_destroy_partition(pg, partition); + } + std::cout << std::endl; + + grin_destroy_partition_list(pg, partition_list); + + } else { + ASSERT(grin_get_master_edge_mirror_partition_list(graph, e) == + GRIN_NULL_PARTITION_LIST); + auto partition_list = grin_get_mirror_edge_mirror_partition_list(graph, e); + + std::cout << "mirror partition ids = "; + auto partition_list_size = grin_get_partition_list_size(pg, partition_list); + for (auto i = 0; i < partition_list_size; ++i) { + auto partition = grin_get_partition_from_list(pg, partition_list, i); + auto partition_id = grin_get_partition_id(pg, partition); + std::cout << " " << partition_id; + grin_destroy_partition(pg, partition); + } + std::cout << std::endl; + + grin_destroy_partition_list(pg, partition_list); + } + + // destroy + grin_destroy_partition(graph, master_partition); + grin_destroy_vertex(graph, e_from_er); + grin_destroy_vertex(graph, e_from_er_from_msg); + grin_destroy_vertex_ref(graph, er); + grin_destroy_vertex_ref(graph, er_from_msg); + grin_destroy_serialized_vertex_ref(graph, msg); +} + +void test_partition_reference(GRIN_PARTITIONED_GRAPH pg, unsigned n) { + std::cout << "\n++++ test partition: reference ++++" << std::endl; + + // check partition number + ASSERT(pg != GRIN_NULL_GRAPH); + auto partition_num = grin_get_total_partitions_number(pg); + ASSERT(partition_num == n); + + // create a local graph + auto partition0 = grin_get_partition_by_id(pg, 0); + auto graph = grin_get_local_graph_by_partition(pg, partition0); + + // test vertex ref + auto vtype = grin_get_vertex_type_by_id(graph, 0); + auto vertex_list = grin_get_vertex_list_by_type(graph, vtype); + // get vertex 0 & test + if (grin_get_vertex_list_size(graph, vertex_list) > 0) { + auto v = grin_get_vertex_from_list(graph, vertex_list, 0); + test_vertex_ref(pg, graph, v); + grin_destroy_vertex(graph, v); + } + // get vertex 1 & test + if (grin_get_vertex_list_size(graph, vertex_list) > 1) { + auto v = grin_get_vertex_from_list(graph, vertex_list, 1); + test_vertex_ref(pg, graph, v); + grin_destroy_vertex(graph, v); + } + + // test edge ref + auto etype = grin_get_edge_type_by_id(graph, 0); + auto edge_list = grin_get_edge_list_by_type(graph, etype); + // get edge 0 & test + if (grin_get_edge_list_size(graph, edge_list) > 0) { + auto e = grin_get_edge_from_list(graph, edge_list, 0); + test_edge_ref(pg, graph, e); + grin_destroy_edge(graph, e); + } + // get edge 1 & test + if (grin_get_edge_list_size(graph, edge_list) > 1) { + auto e = grin_get_edge_from_list(graph, edge_list, 1); + test_edge_ref(pg, graph, e); + grin_destroy_edge(graph, e); + } + + // destroy + grin_destroy_partition(graph, partition0); + grin_destroy_graph(graph); + grin_destroy_vertex_list(graph, vertex_list); + grin_destroy_vertex_type(graph, vtype); + grin_destroy_edge_list(graph, edge_list); + grin_destroy_edge_type(graph, etype); + + std::cout << "---- test partition: reference completed ----" << std::endl; +} + +int main() { + // load graph + uint32_t partition_num = 4; + uint32_t partition_id = 0; + std::cout << "load modern graph, partition_num = " << partition_num + << ", partition_id = " << partition_id << std::endl; + std::string graph_name = "modern_graph"; + char* graph_name_str = new char[graph_name.size() + 1]; + snprintf(graph_name_str, graph_name.size() + 1, "%s", graph_name.c_str()); + demo_storage_load_modern_graph(graph_name_str, partition_num, partition_id); + delete[] graph_name_str; + + // get grin graph + std::string uri = "demo_storage://" + graph_name + + "?partition_num=" + std::to_string(partition_num); + std::cout << "get grin graph from uri: " << uri << std::endl; + char* uri_str = new char[uri.size() + 1]; + snprintf(uri_str, uri.size() + 1, "%s", uri.c_str()); + GRIN_PARTITIONED_GRAPH pg = grin_get_partitioned_graph_from_storage(uri_str); + delete[] uri_str; + + // test partitioned graph + test_partition_reference(pg, partition_num); + + // destroy partitioned graph + grin_destroy_partitioned_graph(pg); + + return 0; +} diff --git a/demo_storage/test/test_partition_topology.cc b/demo_storage/test/test_partition_topology.cc new file mode 100644 index 0000000..47bad3f --- /dev/null +++ b/demo_storage/test/test_partition_topology.cc @@ -0,0 +1,364 @@ +/** Copyright 2020 Alibaba Group Holding Limited. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include + +// predefine for GRIN +#include "../predefine.h" +// storage headers +#include "storage/loadmoderngraph.h" +// test config headers +#include "test/config.h" +// GRIN headers +#include "index/order.h" +#include "partition/partition.h" +#include "partition/reference.h" +#include "partition/topology.h" +#include "property/topology.h" +#include "property/type.h" +#include "topology/adjacentlist.h" +#include "topology/edgelist.h" +#include "topology/structure.h" +#include "topology/vertexlist.h" + +void check_vertex_list(GRIN_GRAPH g, GRIN_VERTEX_LIST vl) { + // check vertex list + auto vl_size = grin_get_vertex_list_size(g, vl); + auto vl_iter = grin_get_vertex_list_begin(g, vl); + for (auto i = 0; i < vl_size; ++i) { + auto v0 = grin_get_vertex_from_list(g, vl, i); + ASSERT(grin_is_vertex_list_end(g, vl_iter) == false); + auto v1 = grin_get_vertex_from_iter(g, vl_iter); + ASSERT(grin_equal_vertex(g, v0, v1) == true); + grin_get_next_vertex_list_iter(g, vl_iter); + // destroy vertex + grin_destroy_vertex(g, v0); + grin_destroy_vertex(g, v1); + } + ASSERT(grin_is_vertex_list_end(g, vl_iter) == true); + // destroy vertex list iter + grin_destroy_vertex_list_iter(g, vl_iter); + + std::cout << "(Correct) check vertex list succeed" << std::endl; + + // test vertex order in list + if (vl_size >= 2) { + size_t idx0 = 0, idx1 = 1; + auto v0 = grin_get_vertex_from_list(g, vl, idx0); + auto v1 = grin_get_vertex_from_list(g, vl, idx1); + ASSERT(grin_smaller_vertex(g, v0, v1) == true); + ASSERT(grin_smaller_vertex(g, v1, v0) == false); + size_t pos0 = grin_get_position_of_vertex_from_sorted_list(g, vl, v0); + size_t pos1 = grin_get_position_of_vertex_from_sorted_list(g, vl, v1); + ASSERT(pos0 == idx0); + ASSERT(pos1 == idx1); + + // destroy vertex + grin_destroy_vertex(g, v0); + grin_destroy_vertex(g, v1); + + std::cout << "(Correct) check vertex order succeed" << std::endl; + } +} + +void test_vertex_list(GRIN_PARTITIONED_GRAPH pg, GRIN_GRAPH graph) { + std::cout << "\n== test vertex list ==" << std::endl; + // get vertex list + auto type = grin_get_vertex_type_by_name(graph, "person"); + auto vertex_list = grin_get_vertex_list_by_type(graph, type); + auto vertex_list_size = grin_get_vertex_list_size(graph, vertex_list); + std::cout << "vertex list for \"person\", size = " << vertex_list_size + << std::endl; + + // select master + auto master_vertex_list = + grin_get_vertex_list_by_type_select_master(graph, type); + auto master_vertex_list_size = + grin_get_vertex_list_size(graph, master_vertex_list); + std::cout << "master vertex list size = " << master_vertex_list_size + << std::endl; + check_vertex_list(graph, master_vertex_list); + + // select mirror + auto mirror_vertex_list = + grin_get_vertex_list_by_type_select_mirror(graph, type); + auto mirror_vertex_list_size = + grin_get_vertex_list_size(graph, mirror_vertex_list); + std::cout << "mirror vertex list size = " << mirror_vertex_list_size + << std::endl; + check_vertex_list(graph, mirror_vertex_list); + + // check vertex number + ASSERT(vertex_list_size == master_vertex_list_size + mirror_vertex_list_size); + + // select by partition + auto partition1 = grin_get_partition_by_id(pg, 1); + auto vertex_list1 = + grin_get_vertex_list_by_type_select_partition(graph, type, partition1); + auto vertex_list1_size = grin_get_vertex_list_size(graph, vertex_list1); + std::cout << "vertex list size of partition 1 = " << vertex_list1_size + << std::endl; + check_vertex_list(graph, vertex_list1); + + // destroy + grin_destroy_partition(graph, partition1); + grin_destroy_vertex_list(graph, vertex_list); + grin_destroy_vertex_list(graph, master_vertex_list); + grin_destroy_vertex_list(graph, mirror_vertex_list); + grin_destroy_vertex_list(graph, vertex_list1); + grin_destroy_vertex_type(graph, type); +} + +void check_edge_list(GRIN_GRAPH graph, GRIN_EDGE_LIST edge_list) { + // check edge list + auto el_size = grin_get_edge_list_size(graph, edge_list); + auto el_iter = grin_get_edge_list_begin(graph, edge_list); + for (auto i = 0; i < el_size; ++i) { + auto e0 = grin_get_edge_from_list(graph, edge_list, i); + ASSERT(grin_is_edge_list_end(graph, el_iter) == false); + auto e1 = grin_get_edge_from_iter(graph, el_iter); + grin_get_next_edge_list_iter(graph, el_iter); + auto v0_1 = grin_get_src_vertex_from_edge(graph, e0); + auto v0_2 = grin_get_dst_vertex_from_edge(graph, e0); + auto v1_1 = grin_get_src_vertex_from_edge(graph, e1); + auto v1_2 = grin_get_dst_vertex_from_edge(graph, e1); + ASSERT(grin_equal_vertex(graph, v0_1, v1_1) == true); + ASSERT(grin_equal_vertex(graph, v0_2, v1_2) == true); + // destroy vertex + grin_destroy_vertex(graph, v0_1); + grin_destroy_vertex(graph, v0_2); + grin_destroy_vertex(graph, v1_1); + grin_destroy_vertex(graph, v1_2); + // destroy edge + grin_destroy_edge(graph, e0); + grin_destroy_edge(graph, e1); + } + + ASSERT(grin_is_edge_list_end(graph, el_iter) == true); + // destroy edge list iter + grin_destroy_edge_list_iter(graph, el_iter); + + std::cout << "(Correct) check edge list succeed" << std::endl; +} + +void test_edge_list(GRIN_PARTITIONED_GRAPH pg, GRIN_GRAPH graph) { + std::cout << "\n== test edge list ==" << std::endl; + // get edge list + auto type = grin_get_edge_type_by_name(graph, "created"); + auto edge_list = grin_get_edge_list_by_type(graph, type); + auto edge_list_size = grin_get_edge_list_size(graph, edge_list); + std::cout << "edge list for \"created\", size = " << edge_list_size + << std::endl; + + // select master + auto master_edge_list = grin_get_edge_list_by_type_select_master(graph, type); + auto master_edge_list_size = grin_get_edge_list_size(graph, master_edge_list); + std::cout << "master edge list size = " << master_edge_list_size << std::endl; + check_edge_list(graph, master_edge_list); + + // select mirror + auto mirror_edge_list = grin_get_edge_list_by_type_select_mirror(graph, type); + auto mirror_edge_list_size = grin_get_edge_list_size(graph, mirror_edge_list); + std::cout << "mirror edge list size = " << mirror_edge_list_size << std::endl; + check_edge_list(graph, mirror_edge_list); + + // check edge number + ASSERT(edge_list_size == master_edge_list_size + mirror_edge_list_size); + + // select by partition + auto partition1 = grin_get_partition_by_id(pg, 1); + auto edge_list1 = + grin_get_edge_list_by_type_select_partition(graph, type, partition1); + auto edge_list1_size = grin_get_edge_list_size(graph, edge_list1); + std::cout << "edge list size of partition 1 = " << edge_list1_size + << std::endl; + check_edge_list(graph, edge_list1); + + // destroy + grin_destroy_partition(graph, partition1); + grin_destroy_edge_list(graph, edge_list); + grin_destroy_edge_list(graph, master_edge_list); + grin_destroy_edge_list(graph, mirror_edge_list); + grin_destroy_edge_list(graph, edge_list1); + grin_destroy_edge_type(graph, type); +} + +void check_adjacency_list(GRIN_GRAPH graph, GRIN_ADJACENT_LIST adj_list) { + // check adjacency list + auto al_size = grin_get_adjacent_list_size(graph, adj_list); + auto al_iter = grin_get_adjacent_list_begin(graph, adj_list); + for (auto i = 0; i < al_size; ++i) { + auto e0 = grin_get_edge_from_adjacent_list(graph, adj_list, i); + auto nbr0 = grin_get_neighbor_from_adjacent_list(graph, adj_list, i); + ASSERT(grin_is_adjacent_list_end(graph, al_iter) == false); + auto e1 = grin_get_edge_from_adjacent_list_iter(graph, al_iter); + auto nbr1 = grin_get_neighbor_from_adjacent_list_iter(graph, al_iter); + grin_get_next_adjacent_list_iter(graph, al_iter); + auto v0_1 = grin_get_src_vertex_from_edge(graph, e0); + auto v0_2 = grin_get_dst_vertex_from_edge(graph, e0); + auto v1_1 = grin_get_src_vertex_from_edge(graph, e1); + auto v1_2 = grin_get_dst_vertex_from_edge(graph, e1); + ASSERT(grin_equal_vertex(graph, v0_1, v1_1) == true); + ASSERT(grin_equal_vertex(graph, v0_2, v1_2) == true); + ASSERT(grin_equal_vertex(graph, nbr0, nbr1) == true); + // destroy vertex + grin_destroy_vertex(graph, v0_1); + grin_destroy_vertex(graph, v0_2); + grin_destroy_vertex(graph, v1_1); + grin_destroy_vertex(graph, v1_2); + grin_destroy_vertex(graph, nbr0); + grin_destroy_vertex(graph, nbr1); + // destroy edge + grin_destroy_edge(graph, e0); + grin_destroy_edge(graph, e1); + } + + ASSERT(grin_is_adjacent_list_end(graph, al_iter) == true); + // destroy adjacency list iter + grin_destroy_adjacent_list_iter(graph, al_iter); + + std::cout << "(Correct) check adjacency list succeed" << std::endl; +} + +void test_adjacency_list(GRIN_PARTITIONED_GRAPH pg, GRIN_GRAPH graph, + GRIN_VERTEX vertex, GRIN_DIRECTION dir) { + std::cout << "\n== test adjacency list: "; + if (dir == GRIN_DIRECTION::IN) + std::cout << "IN ==" << std::endl; + else if (dir == GRIN_DIRECTION::OUT) + std::cout << "OUT ==" << std::endl; + else + std::cout << "BOTH ==" << std::endl; + + // get adjacency list + auto edge_type = grin_get_edge_type_by_name(graph, "knows"); + auto adj_list = + grin_get_adjacent_list_by_edge_type(graph, dir, vertex, edge_type); + auto al_size = grin_get_adjacent_list_size(graph, adj_list); + std::cout << "adjacency list of \"knows\" for vertex #3, size = " << al_size + << std::endl; + + // select master + auto master_adj_list = + grin_get_adjacent_list_by_edge_type_select_master_neighbor( + graph, dir, vertex, edge_type); + auto master_al_size = grin_get_adjacent_list_size(graph, master_adj_list); + std::cout << "master adjacency list size = " << master_al_size << std::endl; + check_adjacency_list(graph, master_adj_list); + + // select mirror + auto mirror_adj_list = + grin_get_adjacent_list_by_edge_type_select_mirror_neighbor( + graph, dir, vertex, edge_type); + auto mirror_al_size = grin_get_adjacent_list_size(graph, mirror_adj_list); + std::cout << "mirror adjacency list size = " << mirror_al_size << std::endl; + check_adjacency_list(graph, mirror_adj_list); + + // check adjacency list size + ASSERT(al_size == master_al_size + mirror_al_size); + + // select by partition + auto partition1 = grin_get_partition_by_id(pg, 2); + auto adj_list2 = + grin_get_adjacent_list_by_edge_type_select_partition_neighbor( + graph, dir, vertex, edge_type, partition1); + auto adj_list2_size = grin_get_adjacent_list_size(graph, adj_list2); + std::cout << "adjacency list size of partition 2 = " << adj_list2_size + << std::endl; + check_adjacency_list(graph, adj_list2); + + // destroy + grin_destroy_partition(graph, partition1); + grin_destroy_adjacent_list(graph, adj_list); + grin_destroy_adjacent_list(graph, master_adj_list); + grin_destroy_adjacent_list(graph, mirror_adj_list); + grin_destroy_adjacent_list(graph, adj_list2); + grin_destroy_edge_type(graph, edge_type); +} + +void test_partition_topology(GRIN_PARTITIONED_GRAPH pg, unsigned n) { + std::cout << "\n++++ test partition: topology ++++" << std::endl; + + // check partition number + ASSERT(pg != GRIN_NULL_GRAPH); + auto partition_num = grin_get_total_partitions_number(pg); + ASSERT(partition_num == n); + + // local partitions + auto partition_list = grin_get_local_partition_list(pg); + ASSERT(partition_list != GRIN_NULL_PARTITION_LIST); + auto partition_list_size = grin_get_partition_list_size(pg, partition_list); + ASSERT(partition_list_size == 1); + + for (auto idx = 0; idx < partition_list_size; ++idx) { + auto partition_id = grin_get_partition_from_list(pg, partition_list, idx); + std::cout << "partition id = " << partition_id << std::endl; + // create a local graph + auto partition = grin_get_partition_by_id(pg, partition_id); + auto graph = grin_get_local_graph_by_partition(pg, partition); + + // get vertex + auto vtype = grin_get_vertex_type_by_name(graph, "person"); + auto vertex_list = grin_get_vertex_list_by_type(graph, vtype); + auto vertex = grin_get_vertex_from_list(graph, vertex_list, 3); + + // test + test_vertex_list(pg, graph); + test_edge_list(pg, graph); + test_adjacency_list(pg, graph, vertex, GRIN_DIRECTION::IN); + test_adjacency_list(pg, graph, vertex, GRIN_DIRECTION::OUT); + test_adjacency_list(pg, graph, vertex, GRIN_DIRECTION::BOTH); + + // destroy + grin_destroy_vertex_type(graph, vtype); + grin_destroy_vertex_list(graph, vertex_list); + grin_destroy_vertex(graph, vertex); + grin_destroy_partition(pg, partition); + grin_destroy_graph(graph); + } + + grin_destroy_partition_list(pg, partition_list); + std::cout << "\n---- test partition: topology completed ----" << std::endl; +} + +int main() { + // load graph + uint32_t partition_num = 4; + uint32_t partition_id = 0; + std::cout << "load modern graph, partition_num = " << partition_num + << ", partition_id = " << partition_id << std::endl; + std::string graph_name = "modern_graph"; + char* graph_name_str = new char[graph_name.size() + 1]; + snprintf(graph_name_str, graph_name.size() + 1, "%s", graph_name.c_str()); + demo_storage_load_modern_graph(graph_name_str, partition_num, partition_id); + delete[] graph_name_str; + + // get grin graph + std::string uri = "demo_storage://" + graph_name + + "?partition_num=" + std::to_string(partition_num); + std::cout << "get grin graph from uri: " << uri << std::endl; + char* uri_str = new char[uri.size() + 1]; + snprintf(uri_str, uri.size() + 1, "%s", uri.c_str()); + GRIN_PARTITIONED_GRAPH pg = grin_get_partitioned_graph_from_storage(uri_str); + delete[] uri_str; + + // test partitioned graph + test_partition_topology(pg, partition_num); + + // destroy partitioned graph + grin_destroy_partitioned_graph(pg); + + return 0; +} diff --git a/demo_storage/test/test_property_list.cc b/demo_storage/test/test_property_list.cc new file mode 100644 index 0000000..e6587cb --- /dev/null +++ b/demo_storage/test/test_property_list.cc @@ -0,0 +1,226 @@ +/** Copyright 2020 Alibaba Group Holding Limited. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include + +// predefine for GRIN +#include "../predefine.h" +// storage headers +#include "storage/loadmoderngraph.h" +// test config headers +#include "test/config.h" +// GRIN headers +#include "property/property.h" +#include "property/propertylist.h" +#include "property/type.h" +#include "topology/edgelist.h" +#include "topology/structure.h" +#include "topology/vertexlist.h" + +void test_vertex_property(GRIN_GRAPH graph, GRIN_VERTEX_PROPERTY property, + GRIN_VERTEX_TYPE vertex_type) { + // get property name + auto name = grin_get_vertex_property_name(graph, vertex_type, property); + std::cout << "name of vertex property: " << name << std::endl; + + // get property data type + auto data_type = grin_get_vertex_property_datatype(graph, property); + std::cout << "data type of vertex property: " << data_type << std::endl; + + // get vertex type from property + auto vertex_type2 = grin_get_vertex_type_from_property(graph, property); + ASSERT(grin_equal_vertex_type(graph, vertex_type, vertex_type2) == true); + + // get vertex property by name + auto property2 = grin_get_vertex_property_by_name(graph, vertex_type, name); + ASSERT(grin_equal_vertex_property(graph, property, property2) == true); + + // get vertex property by id + auto id = grin_get_vertex_property_id(graph, vertex_type, property); + auto property3 = grin_get_vertex_property_by_id(graph, vertex_type, id); + ASSERT(grin_equal_vertex_property(graph, property, property3) == true); + + // get vertex properties by name + auto property_list = grin_get_vertex_properties_by_name(graph, name); + auto n = grin_get_vertex_property_list_size(graph, property_list); + std::cout << "number of vertex properties with this name: " << n << std::endl; + + // destroy + grin_destroy_vertex_property(graph, property2); + grin_destroy_vertex_property(graph, property3); + grin_destroy_vertex_type(graph, vertex_type2); + grin_destroy_vertex_property_list(graph, property_list); +} + +void test_vertex_property_list(GRIN_GRAPH graph) { + std::cout << "\n++++ test property: property list (vertex) ++++" << std::endl; + + auto vertex_type_list = grin_get_vertex_type_list(graph); + for (auto i = 0; i < grin_get_vertex_type_list_size(graph, vertex_type_list); + i++) { + // get property list from vertex type + auto vertex_type = + grin_get_vertex_type_from_list(graph, vertex_type_list, i); + auto property_list = + grin_get_vertex_property_list_by_type(graph, vertex_type); + size_t n = grin_get_vertex_property_list_size(graph, property_list); + + std::cout << "\n==== test property: property (vertex) ++++" << std::endl; + std::cout << "size of property list of vtype " << i << ": " << n + << std::endl; + + // create property list + auto new_property_list = grin_create_vertex_property_list(graph); + + for (auto i = 0; i < n; i++) { + // get property from property list + auto property = + grin_get_vertex_property_from_list(graph, property_list, i); + // test methods on property + test_vertex_property(graph, property, vertex_type); + // insert property to property list + auto status = grin_insert_vertex_property_to_list( + graph, new_property_list, property); + ASSERT(status == true); + // destroy property + grin_destroy_vertex_property(graph, property); + } + + // compare size + ASSERT(grin_get_vertex_property_list_size(graph, new_property_list) == n); + + // destroy + grin_destroy_vertex_type(graph, vertex_type); + grin_destroy_vertex_property_list(graph, property_list); + grin_destroy_vertex_property_list(graph, new_property_list); + } + + // destroy + grin_destroy_vertex_type_list(graph, vertex_type_list); + + std::cout << "---- test property: property list (vertex) completed ----" + << std::endl; +} + +void test_edge_property(GRIN_GRAPH graph, GRIN_EDGE_PROPERTY property, + GRIN_EDGE_TYPE edge_type) { + // get property name + auto name = grin_get_edge_property_name(graph, edge_type, property); + std::cout << "name of edge property: " << name << std::endl; + + // get property data type + auto data_type = grin_get_edge_property_datatype(graph, property); + std::cout << "data type of edge property: " << data_type << std::endl; + + // get edge type from property + auto edge_type2 = grin_get_edge_type_from_property(graph, property); + ASSERT(grin_equal_edge_type(graph, edge_type, edge_type2) == true); + + // get edge property by name + auto property2 = grin_get_edge_property_by_name(graph, edge_type, name); + ASSERT(grin_equal_edge_property(graph, property, property2) == true); + + // get edge property by id + auto id = grin_get_edge_property_id(graph, edge_type, property); + auto property3 = grin_get_edge_property_by_id(graph, edge_type, id); + ASSERT(grin_equal_edge_property(graph, property, property3) == true); + + // get edge properties by name + auto property_list = grin_get_edge_properties_by_name(graph, name); + auto n = grin_get_edge_property_list_size(graph, property_list); + std::cout << "number of edge properties with this name: " << n << std::endl; + + // destroy + grin_destroy_edge_type(graph, edge_type2); + grin_destroy_edge_property(graph, property2); + grin_destroy_edge_property(graph, property3); + grin_destroy_edge_property_list(graph, property_list); +} + +void test_edge_property_list(GRIN_GRAPH graph) { + std::cout << "\n++++ test property: property list (edge) ++++" << std::endl; + + auto edge_type_list = grin_get_edge_type_list(graph); + for (auto i = 0; i < grin_get_edge_type_list_size(graph, edge_type_list); + i++) { + // get property list from edge type + auto edge_type = grin_get_edge_type_from_list(graph, edge_type_list, i); + auto property_list = grin_get_edge_property_list_by_type(graph, edge_type); + size_t n = grin_get_edge_property_list_size(graph, property_list); + + std::cout << "\n==== test property: property (edge) ++++" << std::endl; + std::cout << "size of property list of etype " << i << ": " << n + << std::endl; + + // create property list + auto new_property_list = grin_create_edge_property_list(graph); + + for (auto i = 0; i < n; i++) { + // get property from property list + auto property = grin_get_edge_property_from_list(graph, property_list, i); + // test methods on property + test_edge_property(graph, property, edge_type); + // insert property to property list + auto status = + grin_insert_edge_property_to_list(graph, new_property_list, property); + ASSERT(status == true); + // destroy property + grin_destroy_edge_property(graph, property); + } + + // compare size + ASSERT(grin_get_edge_property_list_size(graph, new_property_list) == n); + + // destroy + grin_destroy_edge_type(graph, edge_type); + grin_destroy_edge_property_list(graph, property_list); + grin_destroy_edge_property_list(graph, new_property_list); + } + + // destroy + grin_destroy_edge_type_list(graph, edge_type_list); + + std::cout << "---- test property: property list (edge) completed ----" + << std::endl; +} + +int main() { + // load graph + std::cout << "load modern graph" << std::endl; + std::string graph_name = "modern_graph"; + char* graph_name_str = new char[graph_name.size() + 1]; + snprintf(graph_name_str, graph_name.size() + 1, "%s", graph_name.c_str()); + demo_storage_load_modern_graph(graph_name_str, 1, 0); + delete[] graph_name_str; + + // get grin graph + std::string uri = "demo_storage://" + graph_name; + std::cout << "get grin graph from uri: " << uri << std::endl; + char* uri_str = new char[uri.size() + 1]; + snprintf(uri_str, uri.size() + 1, "%s", uri.c_str()); + GRIN_GRAPH graph = grin_get_graph_from_storage(uri_str); + delete[] uri_str; + + // test vertex property list + test_vertex_property_list(graph); + + // test edge property list + test_edge_property_list(graph); + + // destroy graph + grin_destroy_graph(graph); + + return 0; +} diff --git a/demo_storage/test/test_property_primarykey.cc b/demo_storage/test/test_property_primarykey.cc new file mode 100644 index 0000000..a3bff07 --- /dev/null +++ b/demo_storage/test/test_property_primarykey.cc @@ -0,0 +1,180 @@ +/** Copyright 2020 Alibaba Group Holding Limited. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include + +// predefine for GRIN +#include "../predefine.h" +// storage headers +#include "storage/loadmoderngraph.h" +// test config headers +#include "test/config.h" +// GRIN headers +#include "property/primarykey.h" +#include "property/property.h" +#include "property/propertylist.h" +#include "property/row.h" +#include "property/topology.h" +#include "property/type.h" +#include "topology/edgelist.h" +#include "topology/structure.h" +#include "topology/vertexlist.h" + +void test_vertex_property_primarykey(GRIN_GRAPH graph) { + std::cout << "\n++++ test property: primarykey (vertex) ++++" << std::endl; + + // get vertex types with primary key + auto primary_vertex_type_list = + grin_get_vertex_types_with_primary_keys(graph); + size_t n = grin_get_vertex_type_list_size(graph, primary_vertex_type_list); + std::cout << "number of vertex types with primary keys: " << n << std::endl; + + for (auto idx = 0; idx < n; ++idx) { + // get vertex type + auto vertex_type = + grin_get_vertex_type_from_list(graph, primary_vertex_type_list, idx); + std::cout << "\n---- test vertex type with primary key: " + << grin_get_vertex_type_name(graph, vertex_type) << " ----" + << std::endl; + + // get the property list for primary key + auto property_list = + grin_get_primary_keys_by_vertex_type(graph, vertex_type); + std::cout << "size of property list for primary key: " + << grin_get_vertex_property_list_size(graph, property_list) + << std::endl; + + // get row of primary keys for vertex A + std::cout << "get row of primary keys for vertex #0" << std::endl; + + auto vertex_list = grin_get_vertex_list_by_type(graph, vertex_type); + auto vertex = grin_get_vertex_from_list(graph, vertex_list, 0); + auto row = grin_get_vertex_primary_keys_row(graph, vertex); + + auto property_list_size = + grin_get_vertex_property_list_size(graph, property_list); + for (auto i = 0; i < property_list_size; ++i) { + auto property = + grin_get_vertex_property_from_list(graph, property_list, i); + ASSERT(grin_get_vertex_property_datatype(graph, property) == + GRIN_DATATYPE::Int64); + auto value = + grin_get_vertex_property_value_of_int64(graph, vertex, property); + auto value_in_row = grin_get_int64_from_row(graph, row, i); + ASSERT(value == value_in_row); + std::cout << "primary key: " + << grin_get_vertex_property_name(graph, vertex_type, property) + << ", value: " << value << std::endl; + grin_destroy_vertex_property(graph, property); + } + + // destroy + grin_destroy_vertex_property_list(graph, property_list); + grin_destroy_vertex_type(graph, vertex_type); + grin_destroy_vertex_list(graph, vertex_list); + grin_destroy_vertex(graph, vertex); + grin_destroy_row(graph, row); + } + // destroy vertex type list + grin_destroy_vertex_type_list(graph, primary_vertex_type_list); + + std::cout << "---- test property: primarykey (vertex) completed ----" + << std::endl; +} + +void test_edge_property_primarykey(GRIN_GRAPH graph) { + std::cout << "\n++++ test property: primarykey (edge) ++++" << std::endl; + + // get edge types with primary key + auto primary_edge_type_list = grin_get_edge_types_with_primary_keys(graph); + size_t n = grin_get_edge_type_list_size(graph, primary_edge_type_list); + std::cout << "number of edge types with primary keys: " << n << std::endl; + + for (auto idx = 0; idx < n; ++idx) { + // get edge type + auto edge_type = + grin_get_edge_type_from_list(graph, primary_edge_type_list, idx); + std::cout << "\n---- test edge type with primary key: " + << grin_get_edge_type_name(graph, edge_type) << " ----" + << std::endl; + + // get the property list for primary key + auto property_list = grin_get_primary_keys_by_edge_type(graph, edge_type); + std::cout << "size of property list for primary key: " + << grin_get_edge_property_list_size(graph, property_list) + << std::endl; + + // get row of primary keys for edge A + std::cout << "get row of primary keys for edge #0" << std::endl; + + auto edge_list = grin_get_edge_list_by_type(graph, edge_type); + auto edge = grin_get_edge_from_list(graph, edge_list, 0); + auto row = grin_get_edge_primary_keys_row(graph, edge); + + auto property_list_size = + grin_get_edge_property_list_size(graph, property_list); + for (auto i = 0; i < property_list_size; ++i) { + auto property = grin_get_edge_property_from_list(graph, property_list, i); + ASSERT(grin_get_edge_property_datatype(graph, property) == + GRIN_DATATYPE::Int64); + auto value = grin_get_edge_property_value_of_int64(graph, edge, property); + auto value_in_row = grin_get_int64_from_row(graph, row, i); + ASSERT(value == value_in_row); + std::cout << "primary key: " + << grin_get_edge_property_name(graph, edge_type, property) + << ", value: " << value << std::endl; + grin_destroy_edge_property(graph, property); + } + + // destroy + grin_destroy_edge_property_list(graph, property_list); + grin_destroy_edge_type(graph, edge_type); + grin_destroy_edge_list(graph, edge_list); + grin_destroy_edge(graph, edge); + grin_destroy_row(graph, row); + } + // destroy edge type list + grin_destroy_edge_type_list(graph, primary_edge_type_list); + + std::cout << "---- test property: primarykey (edge) completed ----" + << std::endl; +} + +int main() { + // load graph + std::cout << "load modern graph" << std::endl; + std::string graph_name = "modern_graph"; + char* graph_name_str = new char[graph_name.size() + 1]; + snprintf(graph_name_str, graph_name.size() + 1, "%s", graph_name.c_str()); + demo_storage_load_modern_graph(graph_name_str, 1, 0); + delete[] graph_name_str; + + // get grin graph + std::string uri = "demo_storage://" + graph_name; + std::cout << "get grin graph from uri: " << uri << std::endl; + char* uri_str = new char[uri.size() + 1]; + snprintf(uri_str, uri.size() + 1, "%s", uri.c_str()); + GRIN_GRAPH graph = grin_get_graph_from_storage(uri_str); + delete[] uri_str; + + // test property primary key + test_vertex_property_primarykey(graph); + test_edge_property_primarykey(graph); + + // destroy graph + grin_destroy_graph(graph); + + return 0; +} diff --git a/demo_storage/test/test_property_topology.cc b/demo_storage/test/test_property_topology.cc new file mode 100644 index 0000000..9a7dd59 --- /dev/null +++ b/demo_storage/test/test_property_topology.cc @@ -0,0 +1,196 @@ +/** Copyright 2020 Alibaba Group Holding Limited. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include + +// predefine for GRIN +#include "../predefine.h" +// storage headers +#include "storage/loadmoderngraph.h" +// test config headers +#include "test/config.h" +// GRIN headers +#include "property/topology.h" +#include "property/type.h" +#include "topology/adjacentlist.h" +#include "topology/edgelist.h" +#include "topology/structure.h" +#include "topology/vertexlist.h" + +void test_property_topology_vertex(GRIN_GRAPH graph) { + std::cout << "\n++++ test property: topology (vertex) ++++" << std::endl; + + // get vertex type list + auto vertex_type_list = grin_get_vertex_type_list(graph); + size_t n = grin_get_vertex_type_list_size(graph, vertex_type_list); + std::cout << "size of vertex type list = " << n << std::endl; + + for (auto i = 0; i < n; i++) { + std::cout << "\n== vertex type " << i << ": ==" << std::endl; + + // get vertex type from vertex type list + auto vertex_type = + grin_get_vertex_type_from_list(graph, vertex_type_list, i); + auto name = grin_get_vertex_type_name(graph, vertex_type); + size_t m = grin_get_vertex_num_by_type(graph, vertex_type); + std::cout << "name of vertex type " << i << ": " << name << std::endl; + std::cout << "vertex num of vertex type " << i << " = " << m << std::endl; + + // select vertex list + auto select_vertex_list = grin_get_vertex_list_by_type(graph, vertex_type); + std::cout << "size of vertex list of vertex type " << i << " = " + << grin_get_vertex_list_size(graph, select_vertex_list) + << std::endl; + ASSERT(grin_get_vertex_list_size(graph, select_vertex_list) == m); + + // destroy + grin_destroy_vertex_type(graph, vertex_type); + grin_destroy_vertex_list(graph, select_vertex_list); + } + + // destroy + grin_destroy_vertex_type_list(graph, vertex_type_list); + + std::cout << "---- test property: topology (vertex) completed ----" + << std::endl; +} + +void test_property_topology_edge(GRIN_GRAPH graph) { + std::cout << "\n++++ test property: topology (edge) ++++" << std::endl; + + // get edge type list + auto edge_type_list = grin_get_edge_type_list(graph); + size_t n = grin_get_edge_type_list_size(graph, edge_type_list); + std::cout << "size of edge type list = " << n << std::endl; + + for (auto i = 0; i < n; i++) { + std::cout << "\n== edge type " << i << ": ==" << std::endl; + + // get edge type from edge type list + auto edge_type = grin_get_edge_type_from_list(graph, edge_type_list, i); + size_t m = grin_get_edge_num_by_type(graph, edge_type); + std::cout << "edge num of edge type " << i << " = " << m << std::endl; + auto name = grin_get_edge_type_name(graph, edge_type); + std::cout << "name of edge type " << i << ": " << name << std::endl; + + // select edge list + auto select_edge_list = grin_get_edge_list_by_type(graph, edge_type); + auto it = grin_get_edge_list_begin(graph, select_edge_list); + auto count = 0; + while (grin_is_edge_list_end(graph, it) == false) { + grin_get_next_edge_list_iter(graph, it); + count++; + } + ASSERT(count == m); + std::cout << "size of edge list of edge type " << i << " = " << m + << std::endl; + + // destroy + grin_destroy_edge_list_iter(graph, it); + grin_destroy_edge_list(graph, select_edge_list); + grin_destroy_edge_type(graph, edge_type); + } + + // destroy + grin_destroy_edge_type_list(graph, edge_type_list); + + std::cout << "---- test property: topology (edge) completed ----" + << std::endl; +} + +void test_property_topology_adj_list(GRIN_GRAPH graph) { + std::cout << "\n++++ test property: topology (adj_list) ++++" << std::endl; + + // get edge type list + auto edge_type_list = grin_get_edge_type_list(graph); + size_t ne = grin_get_edge_type_list_size(graph, edge_type_list); + std::cout << "size of edge type list = " << ne << std::endl; + + // get vertex type list + auto vertex_type_list = grin_get_vertex_type_list(graph); + size_t nv = grin_get_vertex_type_list_size(graph, vertex_type_list); + std::cout << "size of vertex type list = " << nv << std::endl; + + // get vertex + auto vtype = grin_get_vertex_type_by_id(graph, 0); + auto vertex_list = grin_get_vertex_list_by_type(graph, vtype); + auto v = grin_get_vertex_from_list(graph, vertex_list, 3); + + // get adj list of vertex + for (auto i = 0; i < ne; i++) { + std::cout << "\n== edge type " << i << ": ==" << std::endl; + + // get edge type from edge type list + auto edge_type = grin_get_edge_type_from_list(graph, edge_type_list, i); + + // get adj list by edge type + auto select_adj_list = grin_get_adjacent_list_by_edge_type( + graph, GRIN_DIRECTION::BOTH, v, edge_type); + auto adj_list_it = grin_get_adjacent_list_begin(graph, select_adj_list); + auto adj_list_size = 0; + while (grin_is_adjacent_list_end(graph, adj_list_it) == false) { + grin_get_next_adjacent_list_iter(graph, adj_list_it); + adj_list_size++; + } + std::cout << "adj list size (BOTH) of edge type " << i + << " for vertex #3 = " << adj_list_size << std::endl; + + // destroy + grin_destroy_adjacent_list_iter(graph, adj_list_it); + grin_destroy_adjacent_list(graph, select_adj_list); + grin_destroy_edge_type(graph, edge_type); + } + + // destroy + grin_destroy_vertex_list(graph, vertex_list); + grin_destroy_vertex_type(graph, vtype); + grin_destroy_vertex_type_list(graph, vertex_type_list); + grin_destroy_edge_type_list(graph, edge_type_list); + + std::cout << "---- test property: topology (adj_list) completed ----" + << std::endl; +} + +int main() { + // load graph + std::cout << "load modern graph" << std::endl; + std::string graph_name = "modern_graph"; + char* graph_name_str = new char[graph_name.size() + 1]; + snprintf(graph_name_str, graph_name.size() + 1, "%s", graph_name.c_str()); + demo_storage_load_modern_graph(graph_name_str, 1, 0); + delete[] graph_name_str; + + // get grin graph + std::string uri = "demo_storage://" + graph_name; + std::cout << "get grin graph from uri: " << uri << std::endl; + char* uri_str = new char[uri.size() + 1]; + snprintf(uri_str, uri.size() + 1, "%s", uri.c_str()); + GRIN_GRAPH graph = grin_get_graph_from_storage(uri_str); + delete[] uri_str; + + // test property topology (vertex) + test_property_topology_vertex(graph); + + // test property topology (edge) + test_property_topology_edge(graph); + + // test property topology (adj_list) + test_property_topology_adj_list(graph); + + // destroy graph + grin_destroy_graph(graph); + + return 0; +} diff --git a/demo_storage/test/test_property_type.cc b/demo_storage/test/test_property_type.cc new file mode 100644 index 0000000..7340148 --- /dev/null +++ b/demo_storage/test/test_property_type.cc @@ -0,0 +1,244 @@ +/** Copyright 2020 Alibaba Group Holding Limited. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include +#include + +// predefine for GRIN +#include "../predefine.h" +// storage headers +#include "storage/loadmoderngraph.h" +// test config headers +#include "test/config.h" +// GRIN headers +#include "property/topology.h" +#include "property/type.h" +#include "topology/edgelist.h" +#include "topology/structure.h" +#include "topology/vertexlist.h" + +void test_property_type_vertex(GRIN_GRAPH graph) { + std::cout << "\n== test vertex type ==" << std::endl; + + // get vertex type from vertex + auto vtype = grin_get_vertex_type_by_id(graph, 0); + auto vertex_list = grin_get_vertex_list_by_type(graph, vtype); + size_t idx0 = 0, idx1 = 1; + auto v0 = grin_get_vertex_from_list(graph, vertex_list, idx0); + auto v1 = grin_get_vertex_from_list(graph, vertex_list, idx1); + auto vertex_type0 = grin_get_vertex_type(graph, v0); + auto vertex_type1 = grin_get_vertex_type(graph, v1); + + // destroy vertex & vertex list + grin_destroy_vertex(graph, v0); + grin_destroy_vertex(graph, v1); + grin_destroy_vertex_list(graph, vertex_list); + + // compare + ASSERT(grin_equal_vertex_type(graph, vertex_type0, vertex_type0) == true); + + // vertex type name + auto name = grin_get_vertex_type_name(graph, vertex_type0); + std::cout << "vertex type name of vertex 0: " << name << std::endl; + auto vertex_type3 = grin_get_vertex_type_by_name(graph, name); + ASSERT(grin_equal_vertex_type(graph, vertex_type0, vertex_type3) == true); + auto vertex_type4 = grin_get_vertex_type_by_name(graph, "invalid"); + ASSERT(vertex_type4 == GRIN_NULL_VERTEX_TYPE); + + // vertex type id + auto id = grin_get_vertex_type_id(graph, vertex_type0); + auto vertex_type5 = grin_get_vertex_type_by_id(graph, id); + ASSERT(grin_equal_vertex_type(graph, vertex_type0, vertex_type5) == true); + + // destroy vertex type + grin_destroy_vertex_type(graph, vertex_type0); + grin_destroy_vertex_type(graph, vertex_type1); + grin_destroy_vertex_type(graph, vertex_type3); + grin_destroy_vertex_type(graph, vertex_type5); + + // get vertex type list + auto vertex_type_list = grin_get_vertex_type_list(graph); + size_t n = grin_get_vertex_type_list_size(graph, vertex_type_list); + std::cout << "size of vertex type list = " << n << std::endl; + + // create vertex type list + auto new_vertex_type_list = grin_create_vertex_type_list(graph); + + // get vertex type from list and add to a new list + for (auto i = 0; i < n; i++) { + auto vertex_type = + grin_get_vertex_type_from_list(graph, vertex_type_list, i); + // insert to list + grin_insert_vertex_type_to_list(graph, new_vertex_type_list, vertex_type); + // get name from vertex type + auto name = grin_get_vertex_type_name(graph, vertex_type); + std::cout << "name of vertex type " << i << ": " << name << std::endl; + // destroy + grin_destroy_vertex_type(graph, vertex_type); + } + + size_t m = grin_get_vertex_type_list_size(graph, new_vertex_type_list); + std::cout << "size of new vertex type list = " << m << std::endl; + ASSERT(m == n); + + // destroy vertex type list + grin_destroy_vertex_type_list(graph, vertex_type_list); + grin_destroy_vertex_type_list(graph, new_vertex_type_list); + grin_destroy_vertex_type(graph, vtype); +} + +void test_property_type_edge(GRIN_GRAPH graph) { + std::cout << "\n== test edge type ==" << std::endl; + + auto etype = grin_get_edge_type_by_id(graph, 0); + auto edge_list = grin_get_edge_list_by_type(graph, etype); + auto e = grin_get_edge_from_list(graph, edge_list, 0); + + // get edge type from edge & compare + auto edge_type = grin_get_edge_type(graph, e); + ASSERT(grin_equal_edge_type(graph, edge_type, edge_type) == true); + + // destroy edge & edge list + grin_destroy_edge(graph, e); + grin_destroy_edge_list(graph, edge_list); + + // edge type name + auto name = grin_get_edge_type_name(graph, edge_type); + std::cout << "edge type name of edge 0: " << name << std::endl; + auto edge_type2 = grin_get_edge_type_by_name(graph, name); + ASSERT(grin_equal_edge_type(graph, edge_type, edge_type2) == true); + auto edge_type3 = grin_get_edge_type_by_name(graph, "invalid"); + + ASSERT(edge_type3 == GRIN_NULL_EDGE_TYPE); + + // edge type id + auto id = grin_get_edge_type_id(graph, edge_type); + auto edge_type4 = grin_get_edge_type_by_id(graph, id); + ASSERT(grin_equal_edge_type(graph, edge_type, edge_type4) == true); + + // destroy edge type + grin_destroy_edge_type(graph, edge_type); + grin_destroy_edge_type(graph, edge_type2); + grin_destroy_edge_type(graph, edge_type4); + + // get edge type list + auto edge_type_list = grin_get_edge_type_list(graph); + size_t n = grin_get_edge_type_list_size(graph, edge_type_list); + std::cout << "size of edge type list = " << n << std::endl; + + // create edge type list + auto new_edge_type_list = grin_create_edge_type_list(graph); + + // get edgetype from list and add to a new list + for (auto i = 0; i < n; i++) { + auto edge_type = grin_get_edge_type_from_list(graph, edge_type_list, i); + // insert to list + grin_insert_edge_type_to_list(graph, new_edge_type_list, edge_type); + // get name from edge type + auto name = grin_get_edge_type_name(graph, edge_type); + std::cout << "name of edge type " << i << ": " << name << std::endl; + // destroy + grin_destroy_edge_type(graph, edge_type); + } + + size_t m = grin_get_edge_type_list_size(graph, new_edge_type_list); + std::cout << "size of new edge type list = " << m << std::endl; + ASSERT(m == n); + + // destroy edge type list + grin_destroy_edge_type_list(graph, edge_type_list); + grin_destroy_edge_type_list(graph, new_edge_type_list); + grin_destroy_edge_type(graph, etype); +} + +void test_property_type_vertex_and_edge(GRIN_GRAPH graph) { + std::cout << "\n== test vertex and edge type ==" << std::endl; + + // get edge type list + auto edge_type_list = grin_get_edge_type_list(graph); + size_t n = grin_get_edge_type_list_size(graph, edge_type_list); + + if (n > 0) { + // get edge type from list + auto edge_type = grin_get_edge_type_from_list(graph, edge_type_list, 0); + + // get vertex types from edge type + auto src_type_list = grin_get_src_types_by_edge_type(graph, edge_type); + auto dst_type_list = grin_get_dst_types_by_edge_type(graph, edge_type); + ASSERT(grin_get_vertex_type_list_size(graph, src_type_list) == + grin_get_vertex_type_list_size(graph, dst_type_list)); + std::cout << "size of vertex type list from edge type = " + << grin_get_vertex_type_list_size(graph, dst_type_list) + << std::endl; + + // get edge type from vertex types + auto src_type = grin_get_vertex_type_from_list(graph, src_type_list, 0); + auto dst_type = grin_get_vertex_type_from_list(graph, dst_type_list, 0); + auto edge_type_list_2 = + grin_get_edge_types_by_vertex_type_pair(graph, src_type, dst_type); + std::cout << "size of edge type list from vertex type pair = " + << grin_get_edge_type_list_size(graph, edge_type_list_2) + << std::endl; + + // destroy + grin_destroy_edge_type(graph, edge_type); + grin_destroy_vertex_type_list(graph, src_type_list); + grin_destroy_vertex_type_list(graph, dst_type_list); + grin_destroy_vertex_type(graph, src_type); + grin_destroy_vertex_type(graph, dst_type); + grin_destroy_edge_type_list(graph, edge_type_list_2); + } + + // destroy edge type list + grin_destroy_edge_type_list(graph, edge_type_list); +} + +void test_property_type(GRIN_GRAPH graph) { + std::cout << "\n++++ test property: type ++++" << std::endl; + + test_property_type_vertex(graph); + + test_property_type_edge(graph); + + test_property_type_vertex_and_edge(graph); + + std::cout << "---- test property: type completed ----" << std::endl; +} + +int main() { + // load graph + std::cout << "load modern graph" << std::endl; + std::string graph_name = "modern_graph"; + char* graph_name_str = new char[graph_name.size() + 1]; + snprintf(graph_name_str, graph_name.size() + 1, "%s", graph_name.c_str()); + demo_storage_load_modern_graph(graph_name_str, 1, 0); + delete[] graph_name_str; + + // get grin graph + std::string uri = "demo_storage://" + graph_name; + std::cout << "get grin graph from uri: " << uri << std::endl; + char* uri_str = new char[uri.size() + 1]; + snprintf(uri_str, uri.size() + 1, "%s", uri.c_str()); + GRIN_GRAPH graph = grin_get_graph_from_storage(uri_str); + delete[] uri_str; + + // test property type + test_property_type(graph); + + // destroy graph + grin_destroy_graph(graph); + + return 0; +} diff --git a/demo_storage/test/test_property_value.cc b/demo_storage/test/test_property_value.cc new file mode 100644 index 0000000..dfc817b --- /dev/null +++ b/demo_storage/test/test_property_value.cc @@ -0,0 +1,327 @@ +/** Copyright 2020 Alibaba Group Holding Limited. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include + +// predefine for GRIN +#include "../predefine.h" +// storage headers +#include "storage/loadmoderngraph.h" +// test config headers +#include "test/config.h" +// GRIN headers +#include "common/error.h" +#include "property/property.h" +#include "property/propertylist.h" +#include "property/row.h" +#include "property/topology.h" +#include "property/type.h" +#include "topology/adjacentlist.h" +#include "topology/edgelist.h" +#include "topology/structure.h" +#include "topology/vertexlist.h" + +void test_property_row(GRIN_GRAPH graph) { + std::cout << "\n++++ test property: row ++++" << std::endl; + + // create row + auto row = grin_create_row(graph); + + // insert value to row + int32_t value0 = 0; + const char* value1 = "Test String"; + uint64_t value2 = 2; + double value3 = 3.3; + + std::cout << "put value0: " << value0 << std::endl; + std::cout << "put value1: " << value1 << std::endl; + std::cout << "put value2: " << value2 << std::endl; + std::cout << "put value3: " << value3 << std::endl; + auto status = grin_insert_int32_to_row(graph, row, value0); + ASSERT(status == true); + status = grin_insert_string_to_row(graph, row, value1); + ASSERT(status == true); + status = grin_insert_uint64_to_row(graph, row, value2); + ASSERT(status == true); + status = grin_insert_double_to_row(graph, row, value3); + ASSERT(status == true); + + // get value from row + auto value0_ = grin_get_int32_from_row(graph, row, 0); + auto value1_ = grin_get_string_from_row(graph, row, 1); + auto invalid_value = grin_get_float_from_row(graph, row, 100); + ASSERT(grin_get_last_error_code() == INVALID_VALUE && invalid_value == 0.0); + auto value2_ = grin_get_uint64_from_row(graph, row, 2); + auto value3_ = grin_get_double_from_row(graph, row, 3); + ASSERT(grin_get_last_error_code() == NO_ERROR); + + // check value + std::cout << "get value0: " << value0_ << std::endl; + std::cout << "get value1: " << value1_ << std::endl; + std::cout << "get value2: " << value2_ << std::endl; + std::cout << "get value3: " << value3_ << std::endl; + ASSERT(value0_ == value0); + ASSERT(strcmp(value1_, value1) == 0); + ASSERT(value2_ == value2); + ASSERT(value3_ == value3); + + // get const value ptr from row + auto value0_ptr = + grin_get_value_from_row(graph, row, GRIN_DATATYPE::Int32, 0); + ASSERT(grin_get_last_error_code() == NO_ERROR); + ASSERT(*static_cast(value0_ptr) == value0); + auto value1_ptr = + grin_get_value_from_row(graph, row, GRIN_DATATYPE::String, 1); + ASSERT(grin_get_last_error_code() == NO_ERROR); + ASSERT(strcmp(static_cast(value1_ptr), value1) == 0); + auto invalid_value_ptr = + grin_get_value_from_row(graph, row, GRIN_DATATYPE::Int32, 100); + ASSERT(grin_get_last_error_code() == INVALID_VALUE && + invalid_value_ptr == NULL); + std::cout << "check getting const value ptr from row completed" << std::endl; + + // destroy + grin_destroy_string_value(graph, value1_); + grin_destroy_row(graph, row); + + std::cout << "---- test property: row completed ----" << std::endl; +} + +void test_property_vertex(GRIN_GRAPH graph) { + std::cout << "\n++++ test property: vertex ++++" << std::endl; + + // get vertex type list + auto vertex_type_list = grin_get_vertex_type_list(graph); + size_t n = grin_get_vertex_type_list_size(graph, vertex_type_list); + std::cout << "size of vertex type list = " << n << std::endl; + + for (auto i = 0; i < n; i++) { + std::cout << "== vertex type " << i << ": ==" << std::endl; + auto vertex_type = + grin_get_vertex_type_from_list(graph, vertex_type_list, i); + + // get vertex list + auto vertex_list = grin_get_vertex_list_by_type(graph, vertex_type); + + // get property list by vertex type + auto property_list = + grin_get_vertex_property_list_by_type(graph, vertex_type); + auto property_list_size = + grin_get_vertex_property_list_size(graph, property_list); + + for (int property_id = 0; property_id < property_list_size; property_id++) { + // get vertex from vertex list + auto vertex = grin_get_vertex_from_list(graph, vertex_list, 0); + + // get property from property list + auto property = + grin_get_vertex_property_from_list(graph, property_list, property_id); + auto name = grin_get_vertex_property_name(graph, vertex_type, property); + auto data_type = grin_get_vertex_property_datatype(graph, property); + std::cout << "get value of property \"" << name << "\" for vertex 0" + << std::endl; + + // get row + auto r = grin_get_vertex_row(graph, vertex); + + // get const value ptr + auto value = grin_get_vertex_property_value(graph, vertex, property); + ASSERT(grin_get_last_error_code() == NO_ERROR); + + // check value from row and from property (int64) + if (data_type == GRIN_DATATYPE::Int64) { + auto value1 = grin_get_int64_from_row(graph, r, property_id); + auto value2 = + grin_get_vertex_property_value_of_int64(graph, vertex, property); + ASSERT(value1 == value2); + ASSERT(value1 == *static_cast(value)); + std::cout << "value of property \"" << name + << "\" for vertex 0 of vertex type " << i << ": " << value1 + << std::endl; + std::cout << "check values from row and from property are equal (int64)" + << std::endl; + } + + // check value from row and from property (string) + if (data_type == GRIN_DATATYPE::String) { + auto value1 = grin_get_string_from_row(graph, r, property_id); + auto value2 = + grin_get_vertex_property_value_of_string(graph, vertex, property); + ASSERT(grin_get_last_error_code() == NO_ERROR); + ASSERT(strcmp(value1, value2) == 0); + ASSERT(strcmp(value1, static_cast(value)) == 0); + + std::cout << "value of property \"" << name + << "\" for vertex 0 of vertex type " << i << ": " << value1 + << std::endl; + std::cout + << "check values from row and from property are equal (string)" + << std::endl; + + // destroy + grin_destroy_string_value(graph, value1); + grin_destroy_string_value(graph, value2); + } + + // check getting value of invalid property + auto invalid_value = grin_get_vertex_property_value( + graph, vertex, GRIN_NULL_VERTEX_PROPERTY); + ASSERT(grin_get_last_error_code() == INVALID_VALUE); + ASSERT(invalid_value == NULL); + auto invalid_value1 = grin_get_vertex_property_value_of_int64( + graph, vertex, GRIN_NULL_VERTEX_PROPERTY); + ASSERT(grin_get_last_error_code() == INVALID_VALUE); + ASSERT(invalid_value1 == 0); + std::cout << "check error_code is INVALID_VALUE when getting value of " + "invalid property" + << std::endl; + + // destroy + grin_destroy_row(graph, r); + grin_destroy_vertex(graph, vertex); + grin_destroy_vertex_property(graph, property); + } + + // destroy + grin_destroy_vertex_property_list(graph, property_list); + grin_destroy_vertex_list(graph, vertex_list); + grin_destroy_vertex_type(graph, vertex_type); + } + + // destroy + grin_destroy_vertex_type_list(graph, vertex_type_list); + + std::cout << "---- test property: vertex completed ----" << std::endl; +} + +void test_property_edge(GRIN_GRAPH graph) { + std::cout << "\n++++ test property: edge ++++" << std::endl; + + // get edge type list + auto edge_type_list = grin_get_edge_type_list(graph); + size_t n = grin_get_edge_type_list_size(graph, edge_type_list); + std::cout << "size of edge type list = " << n << std::endl; + + for (auto i = 0; i < n; i++) { + std::cout << "== edge type " << i << ": ==" << std::endl; + auto edge_type = grin_get_edge_type_from_list(graph, edge_type_list, i); + + // get edge list + auto edge_list = grin_get_edge_list_by_type(graph, edge_type); + + // get property list by edge type + auto property_list = grin_get_edge_property_list_by_type(graph, edge_type); + auto property_list_size = + grin_get_edge_property_list_size(graph, property_list); + + for (auto property_id = 0; property_id < property_list_size; + property_id++) { + // get edge from edge list iter + auto edge = grin_get_edge_from_list(graph, edge_list, 0); + + // get property from property list + auto property = + grin_get_edge_property_from_list(graph, property_list, property_id); + + auto name = grin_get_edge_property_name(graph, edge_type, property); + auto data_type = grin_get_edge_property_datatype(graph, property); + std::cout << "get value of property \"" << name << "\" for edge 0" + << std::endl; + + // get row + auto r = grin_get_edge_row(graph, edge); + + // get const value ptr + auto value = grin_get_edge_property_value(graph, edge, property); + ASSERT(grin_get_last_error_code() == NO_ERROR); + + // check value from row and from property (int64) + if (data_type == GRIN_DATATYPE::Double) { + auto value1 = grin_get_double_from_row(graph, r, property_id); + auto value2 = + grin_get_edge_property_value_of_double(graph, edge, property); + ASSERT(grin_get_last_error_code() == NO_ERROR); + ASSERT(value1 == value2); + ASSERT(value1 == *static_cast(value)); + std::cout << "value of property \"" << name + << "\" for edge 0 of edge type " << i << ": " << value1 + << std::endl; + std::cout + << "check values from row and from property are equal (double)" + << std::endl; + } + + // check getting value of invalid property + auto invalid_value = + grin_get_edge_property_value(graph, edge, GRIN_NULL_EDGE_PROPERTY); + ASSERT(grin_get_last_error_code() == INVALID_VALUE); + ASSERT(invalid_value == NULL); + auto invalid_value1 = grin_get_edge_property_value_of_int64( + graph, edge, GRIN_NULL_EDGE_PROPERTY); + ASSERT(grin_get_last_error_code() == INVALID_VALUE); + ASSERT(invalid_value1 == 0); + std::cout << "check error_code is INVALID_VALUE when getting value of " + "invalid property" + << std::endl; + + // destroy + grin_destroy_row(graph, r); + grin_destroy_edge(graph, edge); + grin_destroy_edge_property(graph, property); + } + + // destroy + grin_destroy_edge_property_list(graph, property_list); + grin_destroy_edge_list(graph, edge_list); + grin_destroy_edge_type(graph, edge_type); + } + + // destroy + grin_destroy_edge_type_list(graph, edge_type_list); + + std::cout << "---- test property: edge completed ----" << std::endl; +} + +int main() { + // load graph + std::cout << "load modern graph" << std::endl; + std::string graph_name = "modern_graph"; + char* graph_name_str = new char[graph_name.size() + 1]; + snprintf(graph_name_str, graph_name.size() + 1, "%s", graph_name.c_str()); + demo_storage_load_modern_graph(graph_name_str, 1, 0); + delete[] graph_name_str; + + // get grin graph + std::string uri = "demo_storage://" + graph_name; + std::cout << "get grin graph from uri: " << uri << std::endl; + char* uri_str = new char[uri.size() + 1]; + snprintf(uri_str, uri.size() + 1, "%s", uri.c_str()); + GRIN_GRAPH graph = grin_get_graph_from_storage(uri_str); + delete[] uri_str; + + // test property row + test_property_row(graph); + + // test property for vertex + test_property_vertex(graph); + + // test property for edge + test_property_edge(graph); + + // destroy graph + grin_destroy_graph(graph); + + return 0; +} diff --git a/demo_storage/test/test_topology.cc b/demo_storage/test/test_topology.cc new file mode 100644 index 0000000..f5a39e3 --- /dev/null +++ b/demo_storage/test/test_topology.cc @@ -0,0 +1,257 @@ +/** Copyright 2020 Alibaba Group Holding Limited. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include +#include + +// predefine for GRIN +#include "../predefine.h" +// storage headers +#include "storage/loadmoderngraph.h" +// test config headers +#include "test/config.h" +// GRIN headers +#include "common/message.h" +#include "property/topology.h" +#include "property/type.h" +#include "topology/adjacentlist.h" +#include "topology/edgelist.h" +#include "topology/structure.h" +#include "topology/vertexlist.h" + +void test_protobuf() { + std::cout << "\n++++ test protobuf ++++" << std::endl; + + std::cout << grin_get_static_storage_feature_msg() << std::endl; + + std::cout << "---- test protobuf ----" << std::endl; +} + +void test_topology_structure(GRIN_GRAPH graph) { + std::cout << "\n++++ test topology: structure ++++" << std::endl; + + std::cout << "is directed: " << grin_is_directed(graph) << std::endl; + + std::cout << "is multigraph: " << grin_is_multigraph(graph) << std::endl; + + std::cout << "---- test topology: structure ----" << std::endl; +} + +void test_topology_vertexlist(GRIN_GRAPH graph) { + std::cout << "\n++++ test topology: vertexlist ++++" << std::endl; + // get vertex list + auto vtype = grin_get_vertex_type_by_name(graph, "person"); + auto vertex_list = grin_get_vertex_list_by_type(graph, vtype); + + // test vertex list array + auto n = grin_get_vertex_list_size(graph, vertex_list); + std::cout << "vertex list size = " << n << std::endl; + auto v0 = grin_get_vertex_from_list(graph, vertex_list, 0); + auto v1 = grin_get_vertex_from_list(graph, vertex_list, 1); + auto v2 = grin_get_vertex_from_list(graph, vertex_list, 100000000); + ASSERT(grin_equal_vertex(graph, v0, v0) == true); + ASSERT(grin_equal_vertex(graph, v0, v1) == false); + ASSERT(v2 == GRIN_NULL_VERTEX); + + grin_destroy_vertex(graph, v0); + grin_destroy_vertex(graph, v1); + + // test vertex list iterator + auto it = grin_get_vertex_list_begin(graph, vertex_list); + auto count = 0; + while (grin_is_vertex_list_end(graph, it) == false) { + auto v = grin_get_vertex_from_iter(graph, it); + // methods on vertex + auto vdata_type = grin_get_vertex_data_datatype(graph, v); + auto vdata = grin_get_vertex_data_value(graph, v); + if (vdata_type == GRIN_DATATYPE::Int64) + std::cout << "data of \"person\" vertex #" << count << " = " + << *static_cast(vdata) << std::endl; + if (vdata_type == GRIN_DATATYPE::String) + std::cout << "data of \"person\" vertex #" << count << " = " + << static_cast(vdata) << std::endl; + grin_destroy_vertex(graph, v); + grin_get_next_vertex_list_iter(graph, it); + count++; + } + ASSERT(count == n); + grin_destroy_vertex_list_iter(graph, it); + + // destroy vertex list + grin_destroy_vertex_list(graph, vertex_list); + grin_destroy_vertex_type(graph, vtype); + + std::cout << "---- test topology: vertexlist ----" << std::endl; +} + +void test_topology_edgelist(GRIN_GRAPH graph) { + std::cout << "\n++++ test topology: edgelist ++++" << std::endl; + // get edge list + auto etype = grin_get_edge_type_by_name(graph, "knows"); + auto edge_list = grin_get_edge_list_by_type(graph, etype); + + // test edge list array + auto n = grin_get_edge_list_size(graph, edge_list); + std::cout << "edge list size = " << n << std::endl; + auto e0 = grin_get_edge_from_list(graph, edge_list, 0); + auto e1 = grin_get_edge_from_list(graph, edge_list, 1); + auto e2 = grin_get_edge_from_list(graph, edge_list, 100000000); + ASSERT(e2 == GRIN_NULL_EDGE); + + grin_destroy_vertex(graph, e0); + grin_destroy_vertex(graph, e1); + + // test edge list iterator + auto it = grin_get_edge_list_begin(graph, edge_list); + auto count = 0; + while (grin_is_edge_list_end(graph, it) == false) { + // methods on edge + auto e = grin_get_edge_from_iter(graph, it); + auto v1 = grin_get_src_vertex_from_edge(graph, e); + auto v2 = grin_get_dst_vertex_from_edge(graph, e); + auto edata_type = grin_get_edge_data_datatype(graph, e); + auto edata = grin_get_edge_data_value(graph, e); + if (edata_type == GRIN_DATATYPE::Double) + std::cout << "data of \"knows\" edge #" << count << " = " + << *static_cast(edata) << std::endl; + + grin_destroy_vertex(graph, v1); + grin_destroy_vertex(graph, v2); + grin_destroy_edge(graph, e); + grin_get_next_edge_list_iter(graph, it); + count++; + } + std::cout << "edge list size = " << count << std::endl; + grin_destroy_edge_list_iter(graph, it); + + // destroy edge list + grin_destroy_edge_list(graph, edge_list); + grin_destroy_edge_type(graph, etype); + + std::cout << "---- test topology: edgelist -----" << std::endl; +} + +void test_topology_adjlist(GRIN_GRAPH graph, GRIN_DIRECTION direction) { + std::cout << "test topology: adjlist "; + if (direction == GRIN_DIRECTION::IN) + std::cout << "IN" << std::endl; + else if (direction == GRIN_DIRECTION::OUT) + std::cout << "OUT" << std::endl; + else + std::cout << "BOTH" << std::endl; + // get adj list + auto vtype = grin_get_vertex_type_by_name(graph, "person"); + auto vertex_list = grin_get_vertex_list_by_type(graph, vtype); + auto etype = grin_get_edge_type_by_name(graph, "knows"); + auto v = grin_get_vertex_from_list(graph, vertex_list, 3); + auto adj_list = + grin_get_adjacent_list_by_edge_type(graph, direction, v, etype); + auto n = grin_get_adjacent_list_size(graph, adj_list); + + // iterate adj list + auto it = grin_get_adjacent_list_begin(graph, adj_list); + auto count = 0; + while (grin_is_adjacent_list_end(graph, it) == false) { + // iterator + auto e = grin_get_edge_from_adjacent_list_iter(graph, it); + auto v1 = grin_get_src_vertex_from_edge(graph, e); + auto v2 = grin_get_dst_vertex_from_edge(graph, e); + auto nbr = grin_get_neighbor_from_adjacent_list_iter(graph, it); + // array + auto e_ = grin_get_edge_from_adjacent_list(graph, adj_list, count); + auto v1_ = grin_get_src_vertex_from_edge(graph, e_); + auto v2_ = grin_get_dst_vertex_from_edge(graph, e_); + auto nbr_ = grin_get_neighbor_from_adjacent_list(graph, adj_list, count); + + // check src & dst + ASSERT(grin_equal_vertex(graph, v1, v1_) == true); + ASSERT(grin_equal_vertex(graph, v2, v2_) == true); + ASSERT(grin_equal_vertex(graph, v2, v) == true && + grin_equal_vertex(graph, v1, nbr) == true || + grin_equal_vertex(graph, v1, v) == true && + grin_equal_vertex(graph, v2, nbr) == true); + + grin_destroy_vertex(graph, v1); + grin_destroy_vertex(graph, v2); + grin_destroy_vertex(graph, nbr); + grin_destroy_edge(graph, e); + grin_destroy_vertex(graph, v1_); + grin_destroy_vertex(graph, v2_); + grin_destroy_vertex(graph, nbr_); + grin_destroy_edge(graph, e_); + grin_get_next_adjacent_list_iter(graph, it); + count++; + } + ASSERT(count == n); + std::cout << "adj list size of \"person\" vertex #3 = " << count << std::endl; + grin_destroy_adjacent_list_iter(graph, it); + + // destory + grin_destroy_vertex(graph, v); + grin_destroy_vertex_list(graph, vertex_list); + grin_destroy_vertex_type(graph, vtype); + grin_destroy_edge_type(graph, etype); + grin_destroy_adjacent_list(graph, adj_list); +} + +void test_topology_adjlist(GRIN_GRAPH graph) { + std::cout << "\n++++ test topology: adjlist ++++" << std::endl; + + test_topology_adjlist(graph, GRIN_DIRECTION::IN); + + test_topology_adjlist(graph, GRIN_DIRECTION::OUT); + + test_topology_adjlist(graph, GRIN_DIRECTION::BOTH); + + std::cout << "---- test topology: adjlist ----" << std::endl; +} + +int main() { + // load graph + std::cout << "load modern graph" << std::endl; + std::string graph_name = "modern_graph"; + char* graph_name_str = new char[graph_name.size() + 1]; + snprintf(graph_name_str, graph_name.size() + 1, "%s", graph_name.c_str()); + demo_storage_load_modern_graph(graph_name_str, 1, 0); + delete[] graph_name_str; + + // get grin graph + std::string uri = "demo_storage://" + graph_name; + std::cout << "get grin graph from uri: " << uri << std::endl; + char* uri_str = new char[uri.size() + 1]; + snprintf(uri_str, uri.size() + 1, "%s", uri.c_str()); + GRIN_GRAPH graph = grin_get_graph_from_storage(uri_str); + delete[] uri_str; + + // test protobuf + test_protobuf(); + + // test topology structure + test_topology_structure(graph); + + // test topology vertexlist + test_topology_vertexlist(graph); + + // test topology edgelist + test_topology_edgelist(graph); + + // test topology adjlist + test_topology_adjlist(graph); + + // destroy graph + grin_destroy_graph(graph); + + return 0; +} From 6b2792fc2f151be42e3b1e778256eba40fe5be8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Tue, 26 Sep 2023 14:42:18 +0800 Subject: [PATCH 28/48] Update rust --- rust/grin.rs | 6 +++--- rust/grin_demo_storage.h | 4 ++-- rust/grin_demo_storage.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/rust/grin.rs b/rust/grin.rs index 3504365..e761cb5 100644 --- a/rust/grin.rs +++ b/rust/grin.rs @@ -230,7 +230,7 @@ cfg_if::cfg_if! { pub const GRIN_NULL_EDGE_PROPERTY_ID: GrinEdgePropertyId = u32::MAX; pub const GRIN_NULL_ROW: GrinRow = std::ptr::null_mut(); pub const GRIN_NULL_SIZE: u32 = u32::MAX; - } elif #[cfg(feature = "grin_features_enable_demo_storage")]{ + } else if #[cfg(feature = "grin_features_enable_demo_storage")]{ pub type GrinGraph = *mut ::std::os::raw::c_void; pub type GrinVertex = i64; pub type GrinEdge = i64; @@ -287,12 +287,12 @@ cfg_if::cfg_if! { pub const GRIN_NULL_VERTEX_PROPERTY_ID: GrinVertexPropertyId = u32::MAX; pub const GRIN_NULL_EDGE_TYPE: GrinEdgeType = u32::MAX; pub const GRIN_NULL_EDGE_TYPE_LIST: GrinEdgeTypeList = std::ptr::null_mut(); - pub const GRIN_NULL_VEV_TYPE: GrinVevType = u32::MAX; - pub const GRIN_NULL_VEV_TYPE_LIST: GrinVevTypeList = std::ptr::null_mut(); pub const GRIN_NULL_EDGE_PROPERTY: GrinEdgeProperty = u32::MAX; pub const GRIN_NULL_EDGE_PROPERTY_LIST: GrinEdgePropertyList = std::ptr::null_mut(); pub const GRIN_NULL_EDGE_TYPE_ID: GrinEdgeTypeId = u32::MAX; pub const GRIN_NULL_EDGE_PROPERTY_ID: GrinEdgePropertyId = u32::MAX; + pub const GRIN_NULL_EDGE_LABEL: GrinLabel = u32::MAX; + pub const GRIN_NULL_EDGE_LABEL_LIST: GrinLabelList = std::ptr::null_mut(); pub const GRIN_NULL_ROW: GrinRow = std::ptr::null_mut(); pub const GRIN_NULL_SIZE: u32 = u32::MAX; } else { diff --git a/rust/grin_demo_storage.h b/rust/grin_demo_storage.h index f6b6c9a..e20b050 100644 --- a/rust/grin_demo_storage.h +++ b/rust/grin_demo_storage.h @@ -31,12 +31,12 @@ /// RUST_KEEP pub const GRIN_NULL_VERTEX_PROPERTY_ID: GrinVertexPropertyId = u32::MAX; /// RUST_KEEP pub const GRIN_NULL_EDGE_TYPE: GrinEdgeType = u32::MAX; /// RUST_KEEP pub const GRIN_NULL_EDGE_TYPE_LIST: GrinEdgeTypeList = std::ptr::null_mut(); -/// RUST_KEEP pub const GRIN_NULL_VEV_TYPE: GrinVevType = u32::MAX; -/// RUST_KEEP pub const GRIN_NULL_VEV_TYPE_LIST: GrinVevTypeList = std::ptr::null_mut(); /// RUST_KEEP pub const GRIN_NULL_EDGE_PROPERTY: GrinEdgeProperty = u32::MAX; /// RUST_KEEP pub const GRIN_NULL_EDGE_PROPERTY_LIST: GrinEdgePropertyList = std::ptr::null_mut(); /// RUST_KEEP pub const GRIN_NULL_EDGE_TYPE_ID: GrinEdgeTypeId = u32::MAX; /// RUST_KEEP pub const GRIN_NULL_EDGE_PROPERTY_ID: GrinEdgePropertyId = u32::MAX; +/// RUST_KEEP pub const GRIN_NULL_EDGE_LABEL: GrinLabel = u32::MAX; +/// RUST_KEEP pub const GRIN_NULL_EDGE_LABEL_LIST: GrinLabelList = std::ptr::null_mut(); /// RUST_KEEP pub const GRIN_NULL_ROW: GrinRow = std::ptr::null_mut(); /// RUST_KEEP pub const GRIN_NULL_SIZE: u32 = u32::MAX; int __rust_keep_grin_null; diff --git a/rust/grin_demo_storage.rs b/rust/grin_demo_storage.rs index c14573d..633186c 100644 --- a/rust/grin_demo_storage.rs +++ b/rust/grin_demo_storage.rs @@ -82,6 +82,6 @@ pub type GRIN_EDGE_TYPE_ID = ::std::os::raw::c_uint; pub type GRIN_EDGE_PROPERTY_ID = ::std::os::raw::c_uint; pub type GRIN_ROW = *mut ::std::os::raw::c_void; extern "C" { - #[doc = " GRIN_FEATURES_ENABLE_DEMOSTORAGE\n RUST_KEEP pub const GRIN_NULL_DATATYPE: GrinDatatype = GRIN_DATATYPE_UNDEFINED;\n RUST_KEEP pub const GRIN_NULL_GRAPH: GrinGraph = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_VERTEX: GrinVertex = -1;\n RUST_KEEP pub const GRIN_NULL_EDGE: GrinEdge = -1;\n RUST_KEEP pub const GRIN_NULL_VERTEX_DATA: GrinVertexData = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_VERTEX_LIST: GrinVertexList = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_VERTEX_LIST_ITERATOR: GrinVertexListIterator = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_ADJACENT_LIST: GrinAdjacentList = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_ADJACENT_LIST_ITERATOR: GrinAdjacentListIterator = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_EDGE_DATA: GrinEdgeData = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_EDGE_LIST: GrinEdgeList = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_EDGE_LIST_ITERATOR: GrinEdgeListIterator = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_PARTITIONED_GRAPH: GrinPartitionedGraph = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_PARTITION: GrinPartition = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_PARTITION_LIST: GrinPartitionList = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_PARTITION_ID: GrinPartitionId = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_VERTEX_REF: GrinVertexRef = -1;\n RUST_KEEP pub const GRIN_NULL_EDGE_REF: GrinEdgeRef = -1;\n RUST_KEEP pub const GRIN_NULL_VERTEX_TYPE: GrinVertexType = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_VERTEX_TYPE_LIST: GrinVertexTypeList = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_VERTEX_PROPERTY: GrinVertexProperty = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_VERTEX_PROPERTY_LIST: GrinVertexPropertyList = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_VERTEX_TYPE_ID: GrinVertexTypeId = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_VERTEX_PROPERTY_ID: GrinVertexPropertyId = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_EDGE_TYPE: GrinEdgeType = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_EDGE_TYPE_LIST: GrinEdgeTypeList = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_VEV_TYPE: GrinVevType = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_VEV_TYPE_LIST: GrinVevTypeList = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_EDGE_PROPERTY: GrinEdgeProperty = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_EDGE_PROPERTY_LIST: GrinEdgePropertyList = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_EDGE_TYPE_ID: GrinEdgeTypeId = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_EDGE_PROPERTY_ID: GrinEdgePropertyId = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_ROW: GrinRow = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_SIZE: u32 = u32::MAX;"] + #[doc = " GRIN_FEATURES_ENABLE_DEMOSTORAGE\n RUST_KEEP pub const GRIN_NULL_DATATYPE: GrinDatatype = GRIN_DATATYPE_UNDEFINED;\n RUST_KEEP pub const GRIN_NULL_GRAPH: GrinGraph = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_VERTEX: GrinVertex = -1;\n RUST_KEEP pub const GRIN_NULL_EDGE: GrinEdge = -1;\n RUST_KEEP pub const GRIN_NULL_VERTEX_DATA: GrinVertexData = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_VERTEX_LIST: GrinVertexList = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_VERTEX_LIST_ITERATOR: GrinVertexListIterator = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_ADJACENT_LIST: GrinAdjacentList = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_ADJACENT_LIST_ITERATOR: GrinAdjacentListIterator = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_EDGE_DATA: GrinEdgeData = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_EDGE_LIST: GrinEdgeList = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_EDGE_LIST_ITERATOR: GrinEdgeListIterator = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_PARTITIONED_GRAPH: GrinPartitionedGraph = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_PARTITION: GrinPartition = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_PARTITION_LIST: GrinPartitionList = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_PARTITION_ID: GrinPartitionId = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_VERTEX_REF: GrinVertexRef = -1;\n RUST_KEEP pub const GRIN_NULL_EDGE_REF: GrinEdgeRef = -1;\n RUST_KEEP pub const GRIN_NULL_VERTEX_TYPE: GrinVertexType = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_VERTEX_TYPE_LIST: GrinVertexTypeList = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_VERTEX_PROPERTY: GrinVertexProperty = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_VERTEX_PROPERTY_LIST: GrinVertexPropertyList = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_VERTEX_TYPE_ID: GrinVertexTypeId = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_VERTEX_PROPERTY_ID: GrinVertexPropertyId = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_EDGE_TYPE: GrinEdgeType = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_EDGE_TYPE_LIST: GrinEdgeTypeList = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_EDGE_PROPERTY: GrinEdgeProperty = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_EDGE_PROPERTY_LIST: GrinEdgePropertyList = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_EDGE_TYPE_ID: GrinEdgeTypeId = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_EDGE_PROPERTY_ID: GrinEdgePropertyId = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_EDGE_LABEL: GrinLabel = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_EDGE_LABEL_LIST: GrinLabelList = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_ROW: GrinRow = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_SIZE: u32 = u32::MAX;"] pub static mut __rust_keep_grin_null: ::std::os::raw::c_int; } From 6824589edb75eb40769e5ce2240a3ce41b0d7ba8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Mon, 26 Feb 2024 11:09:03 +0800 Subject: [PATCH 29/48] update predefine --- demo_storage/predefine.h | 72 +++++----------------------- storage/demo_storage/predefine.h | 80 +++++++------------------------- 2 files changed, 28 insertions(+), 124 deletions(-) diff --git a/demo_storage/predefine.h b/demo_storage/predefine.h index eeb90cb..176de71 100644 --- a/demo_storage/predefine.h +++ b/demo_storage/predefine.h @@ -31,38 +31,7 @@ extern "C" { #include #include -/* 1. Predefined enumerate types of GRIN */ -/// Enumerates the directions of edges with respect to a certain vertex -typedef enum { - IN = 0, ///< incoming - OUT = 1, ///< outgoing - BOTH = 2, ///< incoming & outgoing -} GRIN_DIRECTION; - -/// Enumerates the datatype supported in the storage -typedef enum { - Undefined = 0, ///< other unknown types - Int32 = 1, ///< int - UInt32 = 2, ///< unsigned int - Int64 = 3, ///< long int - UInt64 = 4, ///< unsigned long int - Float = 5, ///< float - Double = 6, ///< double - String = 7, ///< string - Date32 = 8, ///< date - Time32 = 9, ///< Time32 - Timestamp64 = 10, ///< Timestamp -} GRIN_DATATYPE; - -/// Enumerates the error codes of grin -typedef enum { - NO_ERROR = 0, ///< success - UNKNOWN_ERROR = 1, ///< unknown error - INVALID_VALUE = 2, ///< invalid value - UNKNOWN_DATATYPE = 3, ///< unknown datatype -} GRIN_ERROR_CODE; - -/* 2. Define supported macros based on storage features */ +/* 1. Define supported macros based on storage features */ // Topology #define GRIN_ASSUME_HAS_DIRECTED_GRAPH #define GRIN_ASSUME_HAS_UNDIRECTED_GRAPH @@ -97,18 +66,12 @@ typedef enum { // Property #define GRIN_ENABLE_ROW #define GRIN_TRAIT_CONST_VALUE_PTR +#define GRIN_ENABLE_SCHEMA +// #define GRIN_TRAIT_PROPERTY_VALUE_OF_FLOAT_ARRAY #define GRIN_WITH_VERTEX_PROPERTY -#define GRIN_WITH_VERTEX_PROPERTY_NAME -#define GRIN_WITH_VERTEX_TYPE_NAME -#define GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_TYPE #define GRIN_ENABLE_VERTEX_PRIMARY_KEYS -#define GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_PROPERTY #define GRIN_WITH_EDGE_PROPERTY -#define GRIN_WITH_EDGE_PROPERTY_NAME -#define GRIN_WITH_EDGE_TYPE_NAME -#define GRIN_TRAIT_NATURAL_ID_FOR_EDGE_TYPE #define GRIN_ENABLE_EDGE_PRIMARY_KEYS -#define GRIN_TRAIT_NATURAL_ID_FOR_EDGE_PROPERTY // Index #define GRIN_WITH_VERTEX_LABEL #define GRIN_WITH_EDGE_LABEL @@ -118,10 +81,8 @@ typedef enum { #define GRIN_ENABLE_VERTEX_EXTERNAL_ID_OF_STRING #define GRIN_ENABLE_VERTEX_PK_INDEX #define GRIN_ENABLE_EDGE_PK_INDEX -// Common -// #define GRIN_TRAIT_LOOSE_SCHEMA -/* 3. Define the handles using typedef */ +/* 2. Define the handles using typedef */ typedef void *GRIN_GRAPH; typedef long long int GRIN_VERTEX; typedef long long int GRIN_EDGE; @@ -177,33 +138,24 @@ typedef long long int GRIN_EDGE_REF; #endif #ifdef GRIN_WITH_VERTEX_PROPERTY -typedef unsigned GRIN_VERTEX_TYPE; -typedef void* GRIN_VERTEX_TYPE_LIST; typedef unsigned GRIN_VERTEX_PROPERTY; typedef void* GRIN_VERTEX_PROPERTY_LIST; #endif -#ifdef GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_TYPE -typedef unsigned GRIN_VERTEX_TYPE_ID; -#endif - -#ifdef GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_PROPERTY -typedef unsigned GRIN_VERTEX_PROPERTY_ID; -#endif - #ifdef GRIN_WITH_EDGE_PROPERTY -typedef unsigned GRIN_EDGE_TYPE; -typedef void* GRIN_EDGE_TYPE_LIST; typedef unsigned GRIN_EDGE_PROPERTY; typedef void* GRIN_EDGE_PROPERTY_LIST; #endif -#ifdef GRIN_TRAIT_NATURAL_ID_FOR_EDGE_TYPE +#ifdef GRIN_ENABLE_SCHEMA +typedef unsigned GRIN_VERTEX_TYPE; +typedef void* GRIN_VERTEX_TYPE_LIST; +typedef unsigned GRIN_VERTEX_TYPE_ID; +typedef unsigned GRIN_VERTEX_PROPERTY_ID; typedef unsigned GRIN_EDGE_TYPE_ID; -#endif - -#ifdef GRIN_TRAIT_NATURAL_ID_FOR_EDGE_PROPERTY typedef unsigned GRIN_EDGE_PROPERTY_ID; +typedef unsigned GRIN_EDGE_TYPE; +typedef void* GRIN_EDGE_TYPE_LIST; #endif #ifdef GRIN_ENABLE_ROW @@ -215,7 +167,7 @@ typedef unsigned GRIN_LABEL; typedef void* GRIN_LABEL_LIST; #endif -/* 4. Define invalid values for returns of handles */ +/* 3. Define invalid values for returns of handles */ #define GRIN_NULL_GRAPH NULL #define GRIN_NULL_VERTEX -1 #define GRIN_NULL_EDGE -1 diff --git a/storage/demo_storage/predefine.h b/storage/demo_storage/predefine.h index 6732714..176de71 100644 --- a/storage/demo_storage/predefine.h +++ b/storage/demo_storage/predefine.h @@ -31,38 +31,7 @@ extern "C" { #include #include -/* 1. Predefined enumerate types of GRIN */ -/// Enumerates the directions of edges with respect to a certain vertex -typedef enum { - IN = 0, ///< incoming - OUT = 1, ///< outgoing - BOTH = 2, ///< incoming & outgoing -} GRIN_DIRECTION; - -/// Enumerates the datatype supported in the storage -typedef enum { - Undefined = 0, ///< other unknown types - Int32 = 1, ///< int - UInt32 = 2, ///< unsigned int - Int64 = 3, ///< long int - UInt64 = 4, ///< unsigned long int - Float = 5, ///< float - Double = 6, ///< double - String = 7, ///< string - Date32 = 8, ///< date - Time32 = 9, ///< Time32 - Timestamp64 = 10, ///< Timestamp -} GRIN_DATATYPE; - -/// Enumerates the error codes of grin -typedef enum { - NO_ERROR = 0, ///< success - UNKNOWN_ERROR = 1, ///< unknown error - INVALID_VALUE = 2, ///< invalid value - UNKNOWN_DATATYPE = 3, ///< unknown datatype -} GRIN_ERROR_CODE; - -/* 2. Define supported macros based on storage features */ +/* 1. Define supported macros based on storage features */ // Topology #define GRIN_ASSUME_HAS_DIRECTED_GRAPH #define GRIN_ASSUME_HAS_UNDIRECTED_GRAPH @@ -97,31 +66,23 @@ typedef enum { // Property #define GRIN_ENABLE_ROW #define GRIN_TRAIT_CONST_VALUE_PTR +#define GRIN_ENABLE_SCHEMA +// #define GRIN_TRAIT_PROPERTY_VALUE_OF_FLOAT_ARRAY #define GRIN_WITH_VERTEX_PROPERTY -#define GRIN_WITH_VERTEX_PROPERTY_NAME -#define GRIN_WITH_VERTEX_TYPE_NAME -#define GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_TYPE #define GRIN_ENABLE_VERTEX_PRIMARY_KEYS -#define GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_PROPERTY #define GRIN_WITH_EDGE_PROPERTY -#define GRIN_WITH_EDGE_PROPERTY_NAME -#define GRIN_WITH_EDGE_TYPE_NAME -#define GRIN_TRAIT_NATURAL_ID_FOR_EDGE_TYPE #define GRIN_ENABLE_EDGE_PRIMARY_KEYS -#define GRIN_TRAIT_NATURAL_ID_FOR_EDGE_PROPERTY // Index -// #define GRIN_WITH_VERTEX_LABEL -// #define GRIN_WITH_EDGE_LABEL +#define GRIN_WITH_VERTEX_LABEL +#define GRIN_WITH_EDGE_LABEL #define GRIN_ASSUME_ALL_VERTEX_LIST_SORTED #define GRIN_ENABLE_VERTEX_INTERNAL_ID_INDEX #define GRIN_ENABLE_VERTEX_EXTERNAL_ID_OF_INT64 #define GRIN_ENABLE_VERTEX_EXTERNAL_ID_OF_STRING #define GRIN_ENABLE_VERTEX_PK_INDEX #define GRIN_ENABLE_EDGE_PK_INDEX -// Common -// #define GRIN_TRAIT_LOOSE_SCHEMA -/* 3. Define the handles using typedef */ +/* 2. Define the handles using typedef */ typedef void *GRIN_GRAPH; typedef long long int GRIN_VERTEX; typedef long long int GRIN_EDGE; @@ -177,33 +138,24 @@ typedef long long int GRIN_EDGE_REF; #endif #ifdef GRIN_WITH_VERTEX_PROPERTY -typedef unsigned GRIN_VERTEX_TYPE; -typedef void* GRIN_VERTEX_TYPE_LIST; typedef unsigned GRIN_VERTEX_PROPERTY; typedef void* GRIN_VERTEX_PROPERTY_LIST; #endif -#ifdef GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_TYPE -typedef unsigned GRIN_VERTEX_TYPE_ID; -#endif - -#ifdef GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_PROPERTY -typedef unsigned GRIN_VERTEX_PROPERTY_ID; -#endif - #ifdef GRIN_WITH_EDGE_PROPERTY -typedef unsigned GRIN_EDGE_TYPE; -typedef void* GRIN_EDGE_TYPE_LIST; typedef unsigned GRIN_EDGE_PROPERTY; typedef void* GRIN_EDGE_PROPERTY_LIST; #endif -#ifdef GRIN_TRAIT_NATURAL_ID_FOR_EDGE_TYPE +#ifdef GRIN_ENABLE_SCHEMA +typedef unsigned GRIN_VERTEX_TYPE; +typedef void* GRIN_VERTEX_TYPE_LIST; +typedef unsigned GRIN_VERTEX_TYPE_ID; +typedef unsigned GRIN_VERTEX_PROPERTY_ID; typedef unsigned GRIN_EDGE_TYPE_ID; -#endif - -#ifdef GRIN_TRAIT_NATURAL_ID_FOR_EDGE_PROPERTY typedef unsigned GRIN_EDGE_PROPERTY_ID; +typedef unsigned GRIN_EDGE_TYPE; +typedef void* GRIN_EDGE_TYPE_LIST; #endif #ifdef GRIN_ENABLE_ROW @@ -211,11 +163,11 @@ typedef void* GRIN_ROW; #endif #if defined(GRIN_WITH_VERTEX_LABEL) || defined(GRIN_WITH_EDGE_LABEL) -typedef void* GRIN_LABEL; +typedef unsigned GRIN_LABEL; typedef void* GRIN_LABEL_LIST; #endif -/* 4. Define invalid values for returns of handles */ +/* 3. Define invalid values for returns of handles */ #define GRIN_NULL_GRAPH NULL #define GRIN_NULL_VERTEX -1 #define GRIN_NULL_EDGE -1 @@ -246,7 +198,7 @@ typedef void* GRIN_LABEL_LIST; #define GRIN_NULL_EDGE_TYPE_ID (unsigned)~0 #define GRIN_NULL_EDGE_PROPERTY_ID (unsigned)~0 #define GRIN_NULL_ROW NULL -#define GRIN_NULL_LABEL NULL +#define GRIN_NULL_LABEL (unsigned)~0 #define GRIN_NULL_LABEL_LIST NULL #define GRIN_NULL_SIZE (unsigned)~0 #define GRIN_NULL_NAME NULL From eab54150d79ef3788224f6f90aebb75417e1fdda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Mon, 26 Feb 2024 11:54:03 +0800 Subject: [PATCH 30/48] update --- demo_storage/CMakeLists.txt | 25 ++- demo_storage/src/common/message.cc | 326 ++--------------------------- demo_storage/storage/storage.h | 2 + 3 files changed, 43 insertions(+), 310 deletions(-) diff --git a/demo_storage/CMakeLists.txt b/demo_storage/CMakeLists.txt index 2e8e529..14b0938 100644 --- a/demo_storage/CMakeLists.txt +++ b/demo_storage/CMakeLists.txt @@ -14,7 +14,7 @@ endif() set(GRIN_MAJOR_VERSION 0) set(GRIN_MINOR_VERSION 1) -set(GRIN_PATCH_VERSION 0) +set(GRIN_PATCH_VERSION 4) set(GRIN_VERSION ${GRIN_MAJOR_VERSION}.${GRIN_MINOR_VERSION}.${GRIN_PATCH_VERSION}) project(grin-demo-storage LANGUAGES C CXX VERSION ${GRIN_VERSION}) @@ -122,6 +122,29 @@ endforeach() set_source_files_properties(${PROTO_SRCS} ${PROTO_HDRS} PROPERTIES GENERATED TRUE) +# ------------------------------------------------------------------------------ +# complile protobuf to generate cpp files +# ------------------------------------------------------------------------------ +set(DST_DIR "${PROJECT_SOURCE_DIR}/src/common/") + +list(APPEND PROTO_FLAGS -I${PROJECT_SOURCE_DIR}/../proto/grin_schema) + +file(GLOB PROTO_FILES RELATIVE "${PROJECT_SOURCE_DIR}/../proto/grin_schema" "${PROJECT_SOURCE_DIR}/../proto/grin_schema/*.proto") + +set(PROTO_SRCS "") +set(PROTO_HDRS "") + +foreach(f ${PROTO_FILES}) + message(STATUS "Found proto - " ${f}) + get_filename_component(FIL_WE ${f} NAME_WE) + list(APPEND PROTO_SRCS "${DST_DIR}/${FIL_WE}.pb.cc") + list(APPEND PROTO_HDRS "${DST_DIR}/${FIL_WE}.pb.h") + + execute_process(COMMAND ${Protobuf_PROTOC_EXECUTABLE} ${PROTO_FLAGS} --cpp_out=${DST_DIR} ${f}) +endforeach() + +set_source_files_properties(${PROTO_SRCS} ${PROTO_HDRS} PROPERTIES GENERATED TRUE) + # ------------------------------------------------------------------------------ # build tests # ------------------------------------------------------------------------------ diff --git a/demo_storage/src/common/message.cc b/demo_storage/src/common/message.cc index 464ad20..f406395 100644 --- a/demo_storage/src/common/message.cc +++ b/demo_storage/src/common/message.cc @@ -14,316 +14,24 @@ limitations under the License. #include #include "../predefine.h" -#include "./graph.pb.h" - -// GRIN headers #include "common/message.h" +#include "partition/partition.h" +#include "property/type.h" +#include "property/propertylist.h" +#include "property/property.h" +#include "property/primarykey.h" +#include "graph.pb.h" + +void grin_destroy_graph_schema_msg(const char* s) { + delete[] s; +} -const char* grin_get_static_storage_feature_msg() { - grin::Graph g; - g.set_uri("demo_storage"); - g.set_grin_version("0.1.0"); - - { - auto storage_feature = g.add_features(); - // topology - auto feature = storage_feature->mutable_topology_feature(); - -#ifdef GRIN_ASSUME_HAS_DIRECTED_GRAPH - feature->set_grin_assume_has_directed_graph(true); -#endif - -#ifdef GRIN_ASSUME_HAS_UNDIRECTED_GRAPH - feature->set_grin_assume_has_undirected_graph(true); -#endif - -#ifdef GRIN_ASSUME_HAS_MULTI_EDGE_GRAPH - feature->set_grin_assume_has_multi_edge_graph(true); -#endif - -#ifdef GRIN_WITH_VERTEX_DATA - feature->set_grin_with_vertex_data(true); -#endif - -#ifdef GRIN_WITH_EDGE_DATA - feature->set_grin_with_edge_data(true); -#endif - -#ifdef GRIN_ENABLE_VERTEX_LIST_ARRAY -#ifndef GRIN_ENABLE_VERTEX_LIST - LOG(ERROR) - << "GRIN_ENABLE_VERTEX_LIST_ARRAY requires GRIN_ENABLE_VERTEX_LIST" -#endif - feature->add_vertex_list_retrievals( - grin::ListRetrieval::LR_ARRAY_LIKE); -#endif - -#ifdef GRIN_ENABLE_VERTEX_LIST_ITERATOR -#ifndef GRIN_ENABLE_VERTEX_LIST - LOG(ERROR) - << "GRIN_ENABLE_VERTEX_LIST_ITERATOR requires GRIN_ENABLE_VERTEX_LIST" -#endif - feature->add_vertex_list_retrievals( - grin::ListRetrieval::LR_ITERATOR); -#endif - -#ifdef GRIN_ENABLE_EDGE_LIST_ARRAY -#ifndef GRIN_ENABLE_EDGE_LIST - LOG(ERROR) << "GRIN_ENABLE_EDGE_LIST_ARRAY requires GRIN_ENABLE_EDGE_LIST" -#endif - feature->add_edge_list_retrievals( - grin::ListRetrieval::LR_ARRAY_LIKE); -#endif - -#ifdef GRIN_ENABLE_EDGE_LIST_ITERATOR -#ifndef GRIN_ENABLE_EDGE_LIST - LOG(ERROR) - << "GRIN_ENABLE_EDGE_LIST_ITERATOR requires GRIN_ENABLE_EDGE_LIST" -#endif - feature->add_edge_list_retrievals(grin::ListRetrieval::LR_ITERATOR); -#endif - -#ifdef GRIN_ENABLE_ADJACENT_LIST_ARRAY -#ifndef GRIN_ENABLE_ADJACENT_LIST - LOG(ERROR) - << "GRIN_ENABLE_ADJACENT_LIST_ARRAY requires GRIN_ENABLE_ADJACENT_LIST" -#endif - feature->add_adjacent_list_retrievals( - grin::ListRetrieval::LR_ARRAY_LIKE); -#endif - -#ifdef GRIN_ENABLE_ADJACENT_LIST_ITERATOR -#ifndef GRIN_ENABLE_ADJACENT_LIST - LOG(ERROR) << "GRIN_ENABLE_ADJACENT_LIST_ITERATOR requires " - "GRIN_ENABLE_ADJACENT_LIST" -#endif - feature->add_adjacent_list_retrievals( - grin::ListRetrieval::LR_ITERATOR); -#endif - } - - { - auto storage_feature = g.add_features(); - auto feature = storage_feature->mutable_partition_feature(); - auto cnt = 0; -#ifndef GRIN_ENABLE_GRAPH_PARTITION - feature->set_graph_partition_strategy(grin::GraphPartitionStrategy::GPS_NA); -#else -#ifdef GRIN_ASSUME_ALL_REPLICATE_PARTITION - feature->set_graph_partition_strategy( - grin::GraphPartitionStrategy::GPS_ALL_REPLICATE); - cnt++; -#endif - -#ifdef GRIN_ASSUME_EDGE_CUT_PARTITION - feature->set_graph_partition_strategy( - grin::GraphPartitionStrategy::GPS_EDGE_CUT); - cnt++; -#endif - -#ifdef GRIN_ASSUME_VERTEX_CUT_PARTITION - feature->set_graph_partition_strategy( - grin::GraphPartitionStrategy::GPS_VERTEX_CUT); - cnt++; -#endif - if (cnt > 1) { - LOG(ERROR) << "More than one partition strategy is enabled"; - } -#endif - -#ifdef GRIN_TRAIT_NATURAL_ID_FOR_PARTITION - feature->set_grin_trait_natural_id_for_partition(true); -#endif - -#ifdef GRIN_ENABLE_VERTEX_REF - feature->set_grin_enable_vertex_ref(true); -#endif - -#ifdef GRIN_TRAIT_FAST_VERTEX_REF - feature->set_grin_trait_fast_vertex_ref(true); -#endif - -#ifdef GRIN_ENABLE_EDGE_REF - feature->set_grin_enable_edge_ref(true); -#endif - -#ifdef GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_VERTEX_DATA -#ifdef GRIN_WITH_VERTEX_DATA - feature->set_vertex_data( - grin::PropertyDataPartitionStrategy::PDPS_MASTER_ONLY); -#else - feature->set_vertex_data(grin::PropertyDataPartitionStrategy::PDPS_NA); -#endif -#endif - -#ifdef GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_VERTEX_DATA -#ifdef GRIN_WITH_VERTEX_DATA - feature->set_vertex_data( - grin::PropertyDataPartitionStrategy::PDPS_REPLICATE_MASTER_MIRROR); -#else - feature->set_vertex_data(grin::PropertyDataPartitionStrategy::PDPS_NA); -#endif -#endif - -#ifdef GRIN_ASSUME_MASTER_ONLY_PARTITION_FOR_EDGE_DATA -#ifdef GRIN_WITH_EDGE_DATA - feature->set_edge_data( - grin::PropertyDataPartitionStrategy::PDPS_MASTER_ONLY); -#else - feature->set_edge_data(grin::PropertyDataPartitionStrategy::PDPS_NA); -#endif -#endif - -#ifdef GRIN_ASSUME_REPLICATE_MASTER_MIRROR_PARTITION_FOR_EDGE_DATA -#ifdef GRIN_WITH_EDGE_DATA - feature->set_edge_data( - grin::PropertyDataPartitionStrategy::PDPS_REPLICATE_MASTER_MIRROR); -#else - feature->set_edge_data(grin::PropertyDataPartitionStrategy::PDPS_NA); -#endif -#endif - - auto mpl_feature = feature->mutable_mirror_partition_list_feature(); -#ifdef GRIN_TRAIT_MASTER_VERTEX_MIRROR_PARTITION_LIST - mpl_feature->set_grin_trait_master_vertex_mirror_partition_list(true); -#endif - -#ifdef GRIN_TRAIT_MIRROR_VERTEX_MIRROR_PARTITION_LIST - mpl_feature->set_grin_trait_mirror_vertex_mirror_partition_list(true); -#endif - -#ifdef GRIN_TRAIT_MASTER_EDGE_MIRROR_PARTITION_LIST - mpl_feature->set_grin_trait_master_edge_mirror_partition_list(true); -#endif - -#ifdef GRIN_TRAIT_MIRROR_EDGE_MIRROR_PARTITION_LIST - mpl_feature->set_grin_trait_mirror_edge_mirror_partition_list(true); -#endif - -#ifdef GRIN_TRAIT_SELECT_MASTER_FOR_VERTEX_LIST - feature->set_grin_trait_select_master_for_vertex_list(true); -#endif - -#ifdef GRIN_TRAIT_SELECT_PARTITION_FOR_VERTEX_LIST - feature->set_grin_trait_select_partition_for_vertex_list(true); -#endif - -#ifdef GRIN_TRAIT_SELECT_MASTER_FOR_EDGE_LIST - feature->set_grin_trait_select_master_for_edge_list(true); -#endif - -#ifdef GRIN_TRAIT_SELECT_PARTITION_FOR_EDGE_LIST - feature->set_grin_trait_select_partition_for_edge_list(true); -#endif - -#ifdef GRIN_TRAIT_SELECT_MASTER_NEIGHBOR_FOR_ADJACENT_LIST - feature->set_grin_trait_select_master_neighbor_for_adjacent_list(true); -#endif - -#ifdef GRIN_TRAIT_SELECT_NEIGHBOR_PARTITION_FOR_ADJACENT_LIST - feature->set_grin_trait_select_neighbor_partition_for_adjacent_list(true); -#endif - } - - { - auto storage_feature = g.add_features(); - auto feature = storage_feature->mutable_property_feature(); -#ifdef GRIN_ENABLE_ROW - feature->set_grin_enable_row(true); -#endif - - auto vfeature = feature->mutable_vertex_property_feature(); -#ifdef GRIN_WITH_VERTEX_PROPERTY - vfeature->set_grin_with_vertex_property(true); -#endif - -#ifdef GRIN_WITH_VERTEX_PROPERTY_NAME - vfeature->set_grin_with_vertex_property_name(true); -#endif - -#ifdef GRIN_WITH_VERTEX_TYPE_NAME - vfeature->set_grin_with_vertex_type_name(true); -#endif - -#ifdef GRIN_ENABLE_VERTEX_PRIMARY_KEYS - vfeature->set_grin_enable_vertex_primary_keys(true); -#endif - -#ifdef GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_TYPE - vfeature->set_grin_trait_natural_id_for_vertex_type(true); -#endif - -#ifdef GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_PROPERTY - vfeature->set_grin_trait_natural_id_for_vertex_property(true); -#endif - - auto efeature = feature->mutable_edge_property_feature(); -#ifdef GRIN_WITH_EDGE_PROPERTY - efeature->set_grin_with_edge_property(true); -#endif - -#ifdef GRIN_WITH_EDGE_PROPERTY_NAME - efeature->set_grin_with_edge_property_name(true); -#endif - -#ifdef GRIN_WITH_EDGE_TYPE_NAME - efeature->set_grin_with_edge_type_name(true); -#endif - -#ifdef GRIN_ENABLE_EDGE_PRIMARY_KEYS - efeature->set_grin_enable_edge_primary_keys(true); -#endif - -#ifdef GRIN_TRAIT_NATURAL_ID_FOR_EDGE_TYPE - efeature->set_grin_trait_natural_id_for_edge_type(true); -#endif - -#ifdef GRIN_TRAIT_NATURAL_ID_FOR_EDGE_PROPERTY - efeature->set_grin_trait_natural_id_for_edge_property(true); -#endif - -#ifdef GRIN_TRAIT_SPECIFIC_VEV_RELATION - feature->set_grin_trait_specific_vev_relation(true); -#endif - -#ifdef GRIN_TRAIT_CONST_VALUE_PTR - feature->set_grin_trait_const_value_ptr(true); -#endif - } - - { - auto storage_feature = g.add_features(); - auto feature = storage_feature->mutable_index_feature(); -#ifdef GRIN_WITH_VERTEX_LABEL - feature->set_grin_with_vertex_label(true); -#endif - -#ifdef GRIN_WITH_EDGE_LABEL - feature->set_grin_with_edge_label(true); -#endif - -#ifdef GRIN_ASSUME_ALL_VERTEX_LIST_SORTED - feature->set_grin_assume_all_vertex_list_sorted(true); -#endif - -#ifdef GRIN_ENABLE_VERTEX_INTERNAL_ID_INDEX - feature->set_grin_enable_vertex_internal_id_index(true); -#endif - -#ifdef GRIN_ENABLE_VERTEX_PK_INDEX - feature->set_grin_enable_vertex_pk_index(true); -#endif - -#ifdef GRIN_ENABLE_EDGE_PK_INDEX - feature->set_grin_enable_edge_pk_index(true); -#endif - } - - std::string graph_def; - google::protobuf::util::MessageToJsonString(g, &graph_def); - - int len = graph_def.length() + 1; +const char* grin_get_graph_schema_msg(const char* uri) { + // TODO: implement the function + std::string msg = "demo storage: " + std::string(uri); + + int len = msg.length() + 1; char* out = new char[len]; - snprintf(out, len, "%s", graph_def.c_str()); + snprintf(out, len, "%s", msg.c_str()); return out; -} +} \ No newline at end of file diff --git a/demo_storage/storage/storage.h b/demo_storage/storage/storage.h index 2e3d09a..c958b6b 100644 --- a/demo_storage/storage/storage.h +++ b/demo_storage/storage/storage.h @@ -16,6 +16,8 @@ limitations under the License. #ifndef STORAGE_STORAGE_H_ #define STORAGE_STORAGE_H_ +#include "common/enum_types.h" + #include #include #include From 44b4fa773dc6823202303b2ce8954bdb9d7d9185 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Mon, 26 Feb 2024 14:09:26 +0800 Subject: [PATCH 31/48] internal & external id --- demo_storage/src/common/message.cc | 14 ++++++-------- demo_storage/src/index/external_id.cc | 4 ++++ demo_storage/src/index/internal_id.cc | 4 ++-- demo_storage/test/test_index.cc | 4 ++++ 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/demo_storage/src/common/message.cc b/demo_storage/src/common/message.cc index f406395..4ff5477 100644 --- a/demo_storage/src/common/message.cc +++ b/demo_storage/src/common/message.cc @@ -15,21 +15,19 @@ limitations under the License. #include "../predefine.h" #include "common/message.h" +#include "graph.pb.h" #include "partition/partition.h" -#include "property/type.h" -#include "property/propertylist.h" -#include "property/property.h" #include "property/primarykey.h" -#include "graph.pb.h" +#include "property/property.h" +#include "property/propertylist.h" +#include "property/type.h" -void grin_destroy_graph_schema_msg(const char* s) { - delete[] s; -} +void grin_destroy_graph_schema_msg(const char* s) { delete[] s; } const char* grin_get_graph_schema_msg(const char* uri) { // TODO: implement the function std::string msg = "demo storage: " + std::string(uri); - + int len = msg.length() + 1; char* out = new char[len]; snprintf(out, len, "%s", msg.c_str()); diff --git a/demo_storage/src/index/external_id.cc b/demo_storage/src/index/external_id.cc index 08906f6..d5afb06 100644 --- a/demo_storage/src/index/external_id.cc +++ b/demo_storage/src/index/external_id.cc @@ -27,6 +27,10 @@ long long int grin_get_vertex_external_id_of_int64(GRIN_GRAPH g, // NOLINT #endif #ifdef GRIN_ENABLE_VERTEX_EXTERNAL_ID_OF_STRING +void grin_destroy_vertex_external_id_of_string(GRIN_GRAPH g, const char* id) { + delete[] id; +} + GRIN_VERTEX grin_get_vertex_by_external_id_of_string(GRIN_GRAPH g, const char* id) { return std::stoi(std::string(id)); diff --git a/demo_storage/src/index/internal_id.cc b/demo_storage/src/index/internal_id.cc index cabc198..6f8dce8 100644 --- a/demo_storage/src/index/internal_id.cc +++ b/demo_storage/src/index/internal_id.cc @@ -15,7 +15,7 @@ limitations under the License. #include "index/internal_id.h" #if defined(GRIN_ENABLE_VERTEX_INTERNAL_ID_INDEX) && \ - !defined(GRIN_WITH_VERTEX_PROPERTY) + !defined(GRIN_ENABLE_SCHEMA) long long int grin_get_vertex_internal_id(GRIN_GRAPH, GRIN_VERTEX); // NOLINT GRIN_VERTEX grin_get_vertex_by_internal_id(GRIN_GRAPH, @@ -27,7 +27,7 @@ long long int grin_get_vertex_internal_id_lower_bound(GRIN_GRAPH); // NOLINT #endif #if defined(GRIN_ENABLE_VERTEX_INTERNAL_ID_INDEX) && \ - defined(GRIN_WITH_VERTEX_PROPERTY) + defined(GRIN_ENABLE_SCHEMA) long long int grin_get_vertex_internal_id_by_type(GRIN_GRAPH g, // NOLINT GRIN_VERTEX_TYPE vtype, diff --git a/demo_storage/test/test_index.cc b/demo_storage/test/test_index.cc index 07ea542..b41a5e4 100644 --- a/demo_storage/test/test_index.cc +++ b/demo_storage/test/test_index.cc @@ -138,6 +138,10 @@ void test_external_id(GRIN_GRAPH graph) { ASSERT(grin_equal_vertex(graph, v0, v0_from_id_str) == true); ASSERT(grin_equal_vertex(graph, v1, v1_from_id_str) == true); + // destroy string id + grin_destroy_vertex_external_id_of_string(graph, id0_str); + grin_destroy_vertex_external_id_of_string(graph, id1_str); + // destroy grin_destroy_vertex(graph, v0); grin_destroy_vertex(graph, v1); From dd19c00da9e17ccfe7cc8bb5584770ef5af3b5c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Mon, 26 Feb 2024 14:16:57 +0800 Subject: [PATCH 32/48] fix --- demo_storage/CMakeLists.txt | 26 +++++++++++++++++++++++--- demo_storage/src/common/message.cc | 7 ++++--- demo_storage/src/index/internal_id.cc | 3 +-- demo_storage/storage/storage.h | 4 ++-- 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/demo_storage/CMakeLists.txt b/demo_storage/CMakeLists.txt index 14b0938..11fea87 100644 --- a/demo_storage/CMakeLists.txt +++ b/demo_storage/CMakeLists.txt @@ -178,12 +178,32 @@ endif() file(GLOB_RECURSE FILES_NEED_FORMAT "storage/*.h" "storage/*.cc" "src/*.h" "src/*.cc" "test/*.h" "test/*.cc") -list(REMOVE_ITEM FILES_NEED_FORMAT "${PROJECT_SOURCE_DIR}/src/common/graph.pb.h" "${PROJECT_SOURCE_DIR}/src/common/graph.pb.cc") - +list(REMOVE_ITEM FILES_NEED_FORMAT + "${PROJECT_SOURCE_DIR}/src/common/graph.pb.h" + "${PROJECT_SOURCE_DIR}/src/common/graph.pb.cc" + "${PROJECT_SOURCE_DIR}/src/common/data_type.pb.h" + "${PROJECT_SOURCE_DIR}/src/common/data_type.pb.cc" + "${PROJECT_SOURCE_DIR}/src/common/schema.pb.h" + "${PROJECT_SOURCE_DIR}/src/common/schema.pb.cc" + "${PROJECT_SOURCE_DIR}/src/common/partition.pb.h" + "${PROJECT_SOURCE_DIR}/src/common/partition.pb.cc" + "${PROJECT_SOURCE_DIR}/src/common/storage.pb.h" + "${PROJECT_SOURCE_DIR}/src/common/storage.pb.cc") + file(GLOB_RECURSE FILES_NEED_LINT "storage/*.h" "storage/*.cc" "src/*.h" "src/*.cc" "test/*.h" "test/*.cc") -list(REMOVE_ITEM FILES_NEED_LINT "${PROJECT_SOURCE_DIR}/src/common/graph.pb.h" "${PROJECT_SOURCE_DIR}/src/common/graph.pb.cc") +list(REMOVE_ITEM FILES_NEED_LINT + "${PROJECT_SOURCE_DIR}/src/common/graph.pb.h" + "${PROJECT_SOURCE_DIR}/src/common/graph.pb.cc" + "${PROJECT_SOURCE_DIR}/src/common/data_type.pb.h" + "${PROJECT_SOURCE_DIR}/src/common/data_type.pb.cc" + "${PROJECT_SOURCE_DIR}/src/common/schema.pb.h" + "${PROJECT_SOURCE_DIR}/src/common/schema.pb.cc" + "${PROJECT_SOURCE_DIR}/src/common/partition.pb.h" + "${PROJECT_SOURCE_DIR}/src/common/partition.pb.cc" + "${PROJECT_SOURCE_DIR}/src/common/storage.pb.h" + "${PROJECT_SOURCE_DIR}/src/common/storage.pb.cc") add_custom_target(grin-clformat COMMAND clang-format-8 --style=file -i ${FILES_NEED_FORMAT} diff --git a/demo_storage/src/common/message.cc b/demo_storage/src/common/message.cc index 4ff5477..7ed55fd 100644 --- a/demo_storage/src/common/message.cc +++ b/demo_storage/src/common/message.cc @@ -14,8 +14,9 @@ limitations under the License. #include #include "../predefine.h" +#include "./graph.pb.h" +// GRIN headers #include "common/message.h" -#include "graph.pb.h" #include "partition/partition.h" #include "property/primarykey.h" #include "property/property.h" @@ -25,11 +26,11 @@ limitations under the License. void grin_destroy_graph_schema_msg(const char* s) { delete[] s; } const char* grin_get_graph_schema_msg(const char* uri) { - // TODO: implement the function + // to implement the function std::string msg = "demo storage: " + std::string(uri); int len = msg.length() + 1; char* out = new char[len]; snprintf(out, len, "%s", msg.c_str()); return out; -} \ No newline at end of file +} diff --git a/demo_storage/src/index/internal_id.cc b/demo_storage/src/index/internal_id.cc index 6f8dce8..ed132ac 100644 --- a/demo_storage/src/index/internal_id.cc +++ b/demo_storage/src/index/internal_id.cc @@ -26,8 +26,7 @@ long long int grin_get_vertex_internal_id_upper_bound(GRIN_GRAPH); // NOLINT long long int grin_get_vertex_internal_id_lower_bound(GRIN_GRAPH); // NOLINT #endif -#if defined(GRIN_ENABLE_VERTEX_INTERNAL_ID_INDEX) && \ - defined(GRIN_ENABLE_SCHEMA) +#if defined(GRIN_ENABLE_VERTEX_INTERNAL_ID_INDEX) && defined(GRIN_ENABLE_SCHEMA) long long int grin_get_vertex_internal_id_by_type(GRIN_GRAPH g, // NOLINT GRIN_VERTEX_TYPE vtype, diff --git a/demo_storage/storage/storage.h b/demo_storage/storage/storage.h index c958b6b..f60e232 100644 --- a/demo_storage/storage/storage.h +++ b/demo_storage/storage/storage.h @@ -16,8 +16,6 @@ limitations under the License. #ifndef STORAGE_STORAGE_H_ #define STORAGE_STORAGE_H_ -#include "common/enum_types.h" - #include #include #include @@ -26,6 +24,8 @@ limitations under the License. #include #include +#include "common/enum_types.h" + #define DEMO_STORAGE_NAMESPACE demo_storage_namespace namespace DEMO_STORAGE_NAMESPACE { From cb6a4ea2fe5cf4575cd8ca04a2c83dcb1b50d9c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Mon, 26 Feb 2024 14:44:29 +0800 Subject: [PATCH 33/48] label --- demo_storage/src/index/label.cc | 95 +----------------- demo_storage/src/property/label.cc | 138 ++++++++++++++++++++++++++ demo_storage/test/test_index_label.cc | 15 +++ 3 files changed, 157 insertions(+), 91 deletions(-) create mode 100644 demo_storage/src/property/label.cc diff --git a/demo_storage/src/index/label.cc b/demo_storage/src/index/label.cc index 47a4eaf..b6360c4 100644 --- a/demo_storage/src/index/label.cc +++ b/demo_storage/src/index/label.cc @@ -14,49 +14,6 @@ limitations under the License. // GRIN headers #include "index/label.h" -#if defined(GRIN_WITH_VERTEX_LABEL) || defined(GRIN_WITH_EDGE_LABEL) -size_t grin_get_label_list_size(GRIN_GRAPH g, GRIN_LABEL_LIST ll) { - auto _ll = static_cast(ll); - return _ll->size(); -} - -GRIN_LABEL grin_get_label_from_list(GRIN_GRAPH g, GRIN_LABEL_LIST ll, - size_t idx) { - auto _ll = static_cast(ll); - if (idx >= _ll->size()) { - return GRIN_NULL_LABEL; - } - return _ll->at(idx); -} - -GRIN_LABEL grin_get_label_by_name(GRIN_GRAPH g, const char* name) { - auto _g = static_cast(g); - auto idx = _g->GetLabelId(std::string(name)); - if (idx == -1) { - return GRIN_NULL_LABEL; - } - return idx; -} - -const char* grin_get_label_name(GRIN_GRAPH g, GRIN_LABEL label) { - auto _g = static_cast(g); - if (label < _g->GetVertexLabelNum()) { - return _g->GetVertexLabelName(label).c_str(); - } else if (label < _g->GetVertexLabelNum() + _g->GetEdgeLabelNum()) { - return _g->GetEdgeLabelName(label - _g->GetVertexLabelNum()).c_str(); - } else { - return nullptr; - } -} - -void grin_destroy_label(GRIN_GRAPH g, GRIN_LABEL label) { return; } - -void grin_destroy_label_list(GRIN_GRAPH g, GRIN_LABEL_LIST ll) { - auto _ll = static_cast(ll); - delete _ll; -} -#endif - #ifdef GRIN_WITH_VERTEX_LABEL GRIN_LABEL_LIST grin_get_vertex_label_list(GRIN_GRAPH g) { auto _g = static_cast(g); @@ -66,24 +23,13 @@ GRIN_LABEL_LIST grin_get_vertex_label_list(GRIN_GRAPH g) { } return ll; } - -GRIN_LABEL_LIST grin_get_label_list_by_vertex(GRIN_GRAPH g, GRIN_VERTEX v) { - auto _g = static_cast(g); - auto& _v = _g->GetVertex(v); - auto ll = new GRIN_LABEL_LIST_T(); - auto& labels = _v.GetLabels(); - for (auto& label : labels) { - ll->push_back(_g->GetVertexLabelId(label)); - } - return ll; -} #endif -#if defined(GRIN_WITH_VERTEX_LABEL) && !defined(GRIN_WITH_VERTEX_PROPERTY) +#if defined(GRIN_WITH_VERTEX_LABEL) && !defined(GRIN_ENABLE_SCHEMA) GRIN_VERTEX_LIST grin_get_vertex_list_by_label(GRIN_GRAPH, GRIN_LABEL); #endif -#if defined(GRIN_WITH_VERTEX_LABEL) && defined(GRIN_WITH_VERTEX_PROPERTY) +#if defined(GRIN_WITH_VERTEX_LABEL) && defined(GRIN_ENABLE_SCHEMA) GRIN_VERTEX_LIST grin_get_vertex_list_by_type_by_label(GRIN_GRAPH g, GRIN_VERTEX_TYPE vtype, GRIN_LABEL label) { @@ -93,17 +39,6 @@ GRIN_VERTEX_LIST grin_get_vertex_list_by_type_by_label(GRIN_GRAPH g, auto vl = new GRIN_VERTEX_LIST_T(vtype, ALL_PARTITION, 0, label); return vl; } - -GRIN_VERTEX_TYPE_LIST grin_get_vertex_type_list_by_label(GRIN_GRAPH g, - GRIN_LABEL label) { - auto _g = static_cast(g); - auto vtl = new GRIN_VERTEX_TYPE_LIST_T(); - auto& vtypes = _g->GetVertexTypesByLabel(label); - for (auto& vtype : vtypes) { - vtl->push_back(vtype); - } - return vtl; -} #endif #ifdef GRIN_WITH_EDGE_LABEL @@ -115,24 +50,13 @@ GRIN_LABEL_LIST grin_get_edge_label_list(GRIN_GRAPH g) { } return ll; } - -GRIN_LABEL_LIST grin_get_label_list_by_edge(GRIN_GRAPH g, GRIN_EDGE e) { - auto _g = static_cast(g); - auto& _e = _g->GetEdge(e); - auto ll = new GRIN_LABEL_LIST_T(); - auto& labels = _e.GetLabels(); - for (auto& label : labels) { - ll->push_back(_g->GetEdgeLabelId(label) + _g->GetVertexLabelNum()); - } - return ll; -} #endif -#if defined(GRIN_WITH_EDGE_LABEL) && !defined(GRIN_WITH_EDGE_PROPERTY) +#if defined(GRIN_WITH_EDGE_LABEL) && !defined(GRIN_ENABLE_SCHEMA) GRIN_EDGE_LIST grin_get_edge_list_by_label(GRIN_GRAPH, GRIN_LABEL); #endif -#if defined(GRIN_WITH_EDGE_LABEL) && defined(GRIN_WITH_EDGE_PROPERTY) +#if defined(GRIN_WITH_EDGE_LABEL) && defined(GRIN_ENABLE_SCHEMA) GRIN_EDGE_LIST grin_get_edge_list_by_type_by_label(GRIN_GRAPH g, GRIN_EDGE_TYPE etype, GRIN_LABEL label) { @@ -143,15 +67,4 @@ GRIN_EDGE_LIST grin_get_edge_list_by_type_by_label(GRIN_GRAPH g, label - _g->GetVertexLabelNum()); return el; } - -GRIN_EDGE_TYPE_LIST grin_get_edge_type_list_by_label(GRIN_GRAPH g, - GRIN_LABEL label) { - auto _g = static_cast(g); - auto etl = new GRIN_EDGE_TYPE_LIST_T(); - auto& etypes = _g->GetEdgeTypesByLabel(label - _g->GetVertexLabelNum()); - for (auto& etype : etypes) { - etl->push_back(etype); - } - return etl; -} #endif diff --git a/demo_storage/src/property/label.cc b/demo_storage/src/property/label.cc new file mode 100644 index 0000000..7e73d6b --- /dev/null +++ b/demo_storage/src/property/label.cc @@ -0,0 +1,138 @@ +/** Copyright 2020 Alibaba Group Holding Limited. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "src/predefine.h" +// GRIN headers +#include "property/label.h" + +#if defined(GRIN_WITH_VERTEX_LABEL) || defined(GRIN_WITH_EDGE_LABEL) +size_t grin_get_label_list_size(GRIN_GRAPH g, GRIN_LABEL_LIST ll) { + auto _ll = static_cast(ll); + return _ll->size(); +} + +GRIN_LABEL grin_get_label_from_list(GRIN_GRAPH g, GRIN_LABEL_LIST ll, + size_t idx) { + auto _ll = static_cast(ll); + if (idx >= _ll->size()) { + return GRIN_NULL_LABEL; + } + return _ll->at(idx); +} + +GRIN_LABEL grin_get_label_by_name(GRIN_GRAPH g, const char* name) { + auto _g = static_cast(g); + auto idx = _g->GetLabelId(std::string(name)); + if (idx == -1) { + return GRIN_NULL_LABEL; + } + return idx; +} + +const char* grin_get_label_name(GRIN_GRAPH g, GRIN_LABEL label) { + auto _g = static_cast(g); + if (label < _g->GetVertexLabelNum()) { + return _g->GetVertexLabelName(label).c_str(); + } else if (label < _g->GetVertexLabelNum() + _g->GetEdgeLabelNum()) { + return _g->GetEdgeLabelName(label - _g->GetVertexLabelNum()).c_str(); + } else { + return nullptr; + } +} + +void grin_destroy_label(GRIN_GRAPH g, GRIN_LABEL label) { return; } + +void grin_destroy_label_list(GRIN_GRAPH g, GRIN_LABEL_LIST ll) { + auto _ll = static_cast(ll); + delete _ll; +} +#endif + +#ifdef GRIN_WITH_VERTEX_LABEL +GRIN_LABEL_LIST grin_get_label_list_by_vertex(GRIN_GRAPH g, GRIN_VERTEX v) { + auto _g = static_cast(g); + auto& _v = _g->GetVertex(v); + auto ll = new GRIN_LABEL_LIST_T(); + auto& labels = _v.GetLabels(); + for (auto& label : labels) { + ll->push_back(_g->GetVertexLabelId(label)); + } + return ll; +} +#endif + +#if defined(GRIN_WITH_VERTEX_LABEL) && defined(GRIN_ENABLE_SCHEMA) +GRIN_VERTEX_TYPE_LIST grin_get_vertex_type_list_by_label(GRIN_GRAPH g, + GRIN_LABEL label) { + auto _g = static_cast(g); + auto vtl = new GRIN_VERTEX_TYPE_LIST_T(); + auto& vtypes = _g->GetVertexTypesByLabel(label); + for (auto& vtype : vtypes) { + vtl->push_back(vtype); + } + return vtl; +} + +GRIN_LABEL_LIST grin_get_label_list_by_vertex_type(GRIN_GRAPH g, + GRIN_VERTEX_TYPE vtype) { + auto _g = static_cast(g); + auto ll = new GRIN_LABEL_LIST_T(); + auto n = _g->GetVertexLabelNum(); + for (auto i = 0; i < n; ++i) { + auto& vtypes = _g->GetVertexTypesByLabel(i); + if (vtypes.find(vtype) != vtypes.end()) { + ll->push_back(i); + } + } + return ll; +} +#endif + +#ifdef GRIN_WITH_EDGE_LABEL +GRIN_LABEL_LIST grin_get_label_list_by_edge(GRIN_GRAPH g, GRIN_EDGE e) { + auto _g = static_cast(g); + auto& _e = _g->GetEdge(e); + auto ll = new GRIN_LABEL_LIST_T(); + auto& labels = _e.GetLabels(); + for (auto& label : labels) { + ll->push_back(_g->GetEdgeLabelId(label) + _g->GetVertexLabelNum()); + } + return ll; +} +#endif + +#if defined(GRIN_WITH_EDGE_LABEL) && defined(GRIN_ENABLE_SCHEMA) +GRIN_EDGE_TYPE_LIST grin_get_edge_type_list_by_label(GRIN_GRAPH g, + GRIN_LABEL label) { + auto _g = static_cast(g); + auto etl = new GRIN_EDGE_TYPE_LIST_T(); + auto& etypes = _g->GetEdgeTypesByLabel(label - _g->GetVertexLabelNum()); + for (auto& etype : etypes) { + etl->push_back(etype); + } + return etl; +} + +GRIN_LABEL_LIST grin_get_label_list_by_edge_type(GRIN_GRAPH g, + GRIN_EDGE_TYPE etype) { + auto _g = static_cast(g); + auto ll = new GRIN_LABEL_LIST_T(); + auto n = _g->GetEdgeLabelNum(); + for (auto i = 0; i < n; ++i) { + auto& etypes = _g->GetEdgeTypesByLabel(i); + if (etypes.find(etype) != etypes.end()) { + ll->push_back(i + _g->GetVertexLabelNum()); + } + } + return ll; +} +#endif diff --git a/demo_storage/test/test_index_label.cc b/demo_storage/test/test_index_label.cc index 1f7836b..3d47b6a 100644 --- a/demo_storage/test/test_index_label.cc +++ b/demo_storage/test/test_index_label.cc @@ -25,6 +25,7 @@ limitations under the License. #include "index/internal_id.h" #include "index/label.h" #include "index/order.h" +#include "property/label.h" #include "property/topology.h" #include "property/type.h" #include "topology/edgelist.h" @@ -78,6 +79,12 @@ void test_vertex_label(GRIN_GRAPH graph) { grin_destroy_label(graph, label); } + // get vertex label list by type + auto label_list_2 = grin_get_label_list_by_vertex_type(graph, vertex_type); + auto label_list_size_2 = grin_get_label_list_size(graph, label_list_2); + std::cout << "label list size for vertex type #0: " << label_list_size_2 + << std::endl; + // get vertex list by label auto label = grin_get_label_by_name(graph, "v_label_0"); auto vertex_list_2 = @@ -111,6 +118,7 @@ void test_vertex_label(GRIN_GRAPH graph) { // destroy grin_destroy_label(graph, label); grin_destroy_label_list(graph, label_list); + grin_destroy_label_list(graph, label_list_2); grin_destroy_vertex(graph, vertex); grin_destroy_vertex_list(graph, vertex_list); grin_destroy_vertex_type(graph, vertex_type); @@ -160,6 +168,12 @@ void test_edge_label(GRIN_GRAPH graph) { grin_destroy_label(graph, label); } + // get edge label list by type + auto label_list_2 = grin_get_label_list_by_edge_type(graph, edge_type); + auto label_list_size_2 = grin_get_label_list_size(graph, label_list_2); + std::cout << "label list size for edge type #0: " << label_list_size_2 + << std::endl; + // get edge list by label auto label = grin_get_label_by_name(graph, "e_label_0"); auto edge_list_2 = @@ -188,6 +202,7 @@ void test_edge_label(GRIN_GRAPH graph) { // destroy grin_destroy_label(graph, label); grin_destroy_label_list(graph, label_list); + grin_destroy_label_list(graph, label_list_2); grin_destroy_edge(graph, edge); grin_destroy_edge_list(graph, edge_list); grin_destroy_edge_type(graph, edge_type); From 6c2a3ceca859dceb86b3de373922a5b9eda2a88f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Mon, 26 Feb 2024 14:45:50 +0800 Subject: [PATCH 34/48] test label --- demo_storage/test/{test_index_label.cc => test_label.cc} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename demo_storage/test/{test_index_label.cc => test_label.cc} (100%) diff --git a/demo_storage/test/test_index_label.cc b/demo_storage/test/test_label.cc similarity index 100% rename from demo_storage/test/test_index_label.cc rename to demo_storage/test/test_label.cc From 17de70fd64e1d477ffd174d82ee604cbf706cac7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Mon, 26 Feb 2024 15:17:05 +0800 Subject: [PATCH 35/48] partition --- demo_storage/predefine.h | 1 + demo_storage/src/partition/topology.cc | 52 +++++++++++++++++++++----- 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/demo_storage/predefine.h b/demo_storage/predefine.h index 176de71..2ed7da0 100644 --- a/demo_storage/predefine.h +++ b/demo_storage/predefine.h @@ -49,6 +49,7 @@ extern "C" { #define GRIN_ENABLE_ADJACENT_LIST_ITERATOR // Partition #define GRIN_ENABLE_GRAPH_PARTITION +// #define GRIN_ASSUME_WITH_UNIVERSAL_VERTICES #define GRIN_TRAIT_NATURAL_ID_FOR_PARTITION #define GRIN_ENABLE_VERTEX_REF #define GRIN_TRAIT_FAST_VERTEX_REF diff --git a/demo_storage/src/partition/topology.cc b/demo_storage/src/partition/topology.cc index 8b49f3b..61a73a1 100644 --- a/demo_storage/src/partition/topology.cc +++ b/demo_storage/src/partition/topology.cc @@ -18,14 +18,14 @@ limitations under the License. #include "partition/topology.h" #if defined(GRIN_TRAIT_SELECT_MASTER_FOR_VERTEX_LIST) && \ - !defined(GRIN_WITH_VERTEX_PROPERTY) + !defined(GRIN_ENABLE_SCHEMA) GRIN_VERTEX_LIST grin_get_vertex_list_select_master(GRIN_GRAPH); GRIN_VERTEX_LIST grin_get_vertex_list_select_mirror(GRIN_GRAPH); #endif #if defined(GRIN_TRAIT_SELECT_MASTER_FOR_VERTEX_LIST) && \ - defined(GRIN_WITH_VERTEX_PROPERTY) + defined(GRIN_ENABLE_SCHEMA) GRIN_VERTEX_LIST grin_get_vertex_list_by_type_select_master( GRIN_GRAPH g, GRIN_VERTEX_TYPE vtype) { auto _g = static_cast(g); @@ -47,7 +47,7 @@ GRIN_VERTEX_LIST grin_get_vertex_list_select_partition(GRIN_GRAPH, #endif #if defined(GRIN_TRAIT_SELECT_PARTITION_FOR_VERTEX_LIST) && \ - defined(GRIN_WITH_VERTEX_PROPERTY) + defined(GRIN_ENABLE_SCHEMA) GRIN_VERTEX_LIST grin_get_vertex_list_by_type_select_partition( GRIN_GRAPH g, GRIN_VERTEX_TYPE vtype, GRIN_PARTITION p) { auto _g = static_cast(g); @@ -59,14 +59,14 @@ GRIN_VERTEX_LIST grin_get_vertex_list_by_type_select_partition( #endif #if defined(GRIN_TRAIT_SELECT_MASTER_FOR_EDGE_LIST) && \ - !defined(GRIN_WITH_EDGE_PROPERTY) + !defined(GRIN_ENABLE_SCHEMA) GRIN_EDGE_LIST grin_get_edge_list_select_master(GRIN_GRAPH); GRIN_EDGE_LIST grin_get_edge_list_select_mirror(GRIN_GRAPH); #endif #if defined(GRIN_TRAIT_SELECT_MASTER_FOR_EDGE_LIST) && \ - defined(GRIN_WITH_EDGE_PROPERTY) + defined(GRIN_ENABLE_SCHEMA) GRIN_EDGE_LIST grin_get_edge_list_by_type_select_master(GRIN_GRAPH g, GRIN_EDGE_TYPE etype) { auto _g = static_cast(g); @@ -82,12 +82,12 @@ GRIN_EDGE_LIST grin_get_edge_list_by_type_select_mirror(GRIN_GRAPH g, #endif #if defined(GRIN_TRAIT_SELECT_PARTITION_FOR_EDGE_LIST) && \ - !defined(GRIN_WITH_EDGE_PROPERTY) + !defined(GRIN_ENABLE_SCHEMA) GRIN_EDGE_LIST grin_get_edge_list_select_partition(GRIN_GRAPH, GRIN_PARTITION); #endif #if defined(GRIN_TRAIT_SELECT_PARTITION_FOR_EDGE_LIST) && \ - defined(GRIN_WITH_EDGE_PROPERTY) + defined(GRIN_ENABLE_SCHEMA) GRIN_EDGE_LIST grin_get_edge_list_by_type_select_partition(GRIN_GRAPH g, GRIN_EDGE_TYPE etype, GRIN_PARTITION p) { @@ -100,7 +100,7 @@ GRIN_EDGE_LIST grin_get_edge_list_by_type_select_partition(GRIN_GRAPH g, #endif #if defined(GRIN_TRAIT_SELECT_MASTER_NEIGHBOR_FOR_ADJACENT_LIST) && \ - !defined(GRIN_WITH_VERTEX_PROPERTY) + !defined(GRIN_ENABLE_SCHEMA) GRIN_ADJACENT_LIST grin_get_adjacent_list_select_master_neighbor(GRIN_GRAPH, GRIN_DIRECTION, GRIN_VERTEX); @@ -111,7 +111,7 @@ GRIN_ADJACENT_LIST grin_get_adjacent_list_select_mirror_neighbor(GRIN_GRAPH, #endif #if defined(GRIN_TRAIT_SELECT_MASTER_NEIGHBOR_FOR_ADJACENT_LIST) && \ - defined(GRIN_WITH_VERTEX_PROPERTY) + defined(GRIN_ENABLE_SCHEMA) GRIN_ADJACENT_LIST grin_get_adjacent_list_by_edge_type_select_master_neighbor( GRIN_GRAPH g, GRIN_DIRECTION d, GRIN_VERTEX v, GRIN_EDGE_TYPE etype) { auto _g = static_cast(g); @@ -138,7 +138,7 @@ GRIN_ADJACENT_LIST grin_get_adjacent_list_select_partition_neighbor( #endif #if defined(GRIN_TRAIT_SELECT_NEIGHBOR_PARTITION_FOR_ADJACENT_LIST) && \ - defined(GRIN_WITH_VERTEX_PROPERTY) + defined(GRIN_ENABLE_SCHEMA) GRIN_ADJACENT_LIST grin_get_adjacent_list_by_edge_type_select_partition_neighbor( GRIN_GRAPH g, GRIN_DIRECTION d, GRIN_VERTEX v, GRIN_EDGE_TYPE etype, @@ -152,3 +152,35 @@ grin_get_adjacent_list_by_edge_type_select_partition_neighbor( return new GRIN_ADJACENT_LIST_T(vtype, vid, d, etype, ONE_PARTITION, p); } #endif + +#if defined(GRIN_ASSUME_WITH_UNIVERSAL_VERTICES) && defined(GRIN_ENABLE_SCHEMA) +GRIN_VERTEX_TYPE_LIST grin_get_vertex_type_list_select_universal(GRIN_GRAPH); + +GRIN_VERTEX_TYPE_LIST grin_get_vertex_type_list_select_non_universal( + GRIN_GRAPH); + +bool grin_is_vertex_type_unisversal(GRIN_GRAPH, GRIN_VERTEX_TYPE); +#endif + +#if defined(GRIN_ASSUME_WITH_UNIVERSAL_VERTICES) && \ + !defined(GRIN_ENABLE_SCHEMA) && defined(GRIN_ENABLE_VERTEX_LIST) +GRIN_VERTEX_LIST grin_get_vertex_list_select_universal(GRIN_GRAPH); + +GRIN_VERTEX_LIST grin_get_vertex_list_select_non_universal(GRIN_GRAPH); +#endif + +#if defined(GRIN_ASSUME_WITH_UNIVERSAL_VERTICES) && \ + !defined(GRIN_ENABLE_SCHEMA) && defined(GRIN_ENABLE_EDGE_LIST) +GRIN_EDGE_LIST grin_get_edge_list_select_universal(GRIN_GRAPH); + +GRIN_EDGE_LIST grin_get_edge_list_select_non_universal(GRIN_GRAPH); +#endif + +#if defined(GRIN_ASSUME_WITH_UNIVERSAL_VERTICES) && \ + !defined(GRIN_ENABLE_SCHEMA) && defined(GRIN_ENABLE_ADJACENT_LIST) +GRIN_ADJACENT_LIST grin_get_adjacent_list_select_universal_neighbor( + GRIN_GRAPH, GRIN_DIRECTION, GRIN_VERTEX); + +GRIN_ADJACENT_LIST grin_get_adjacent_list_select_non_universal_neighbor( + GRIN_GRAPH, GRIN_DIRECTION, GRIN_VERTEX); +#endif From ea5c6e768756608062a43c836c9bd565e86b7d4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Mon, 26 Feb 2024 15:22:28 +0800 Subject: [PATCH 36/48] topology --- demo_storage/src/topology/adjacentlist.cc | 2 +- demo_storage/src/topology/edgelist.cc | 2 +- demo_storage/src/topology/structure.cc | 4 +--- demo_storage/src/topology/vertexlist.cc | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/demo_storage/src/topology/adjacentlist.cc b/demo_storage/src/topology/adjacentlist.cc index 6763097..caa986a 100644 --- a/demo_storage/src/topology/adjacentlist.cc +++ b/demo_storage/src/topology/adjacentlist.cc @@ -17,7 +17,7 @@ limitations under the License. // GRIN headers #include "topology/adjacentlist.h" -#if defined(GRIN_ENABLE_ADJACENT_LIST) && !defined(GRIN_WITH_EDGE_PROPERTY) +#if defined(GRIN_ENABLE_ADJACENT_LIST) && !defined(GRIN_ENABLE_SCHEMA) GRIN_ADJACENT_LIST grin_get_adjacent_list(GRIN_GRAPH, GRIN_DIRECTION, GRIN_VERTEX); #endif diff --git a/demo_storage/src/topology/edgelist.cc b/demo_storage/src/topology/edgelist.cc index 9495ed4..5075f39 100644 --- a/demo_storage/src/topology/edgelist.cc +++ b/demo_storage/src/topology/edgelist.cc @@ -17,7 +17,7 @@ limitations under the License. // GRIN headers #include "topology/edgelist.h" -#if defined(GRIN_ENABLE_EDGE_LIST) && !defined(GRIN_WITH_EDGE_PROPERTY) +#if defined(GRIN_ENABLE_EDGE_LIST) && !defined(GRIN_ENABLE_SCHEMA) GRIN_EDGE_LIST grin_get_edge_list(GRIN_GRAPH); #endif diff --git a/demo_storage/src/topology/structure.cc b/demo_storage/src/topology/structure.cc index b547d74..1d17764 100644 --- a/demo_storage/src/topology/structure.cc +++ b/demo_storage/src/topology/structure.cc @@ -49,11 +49,9 @@ bool grin_is_directed(GRIN_GRAPH g) { bool grin_is_multigraph(GRIN_GRAPH) { return true; } #endif -#if !defined(GRIN_WITH_VERTEX_PROPERTY) +#ifndef GRIN_ENABLE_SCHEMA size_t grin_get_vertex_num(GRIN_GRAPH); -#endif -#if !defined(GRIN_WITH_EDGE_PROPERTY) size_t grin_get_edge_num(GRIN_GRAPH); #endif diff --git a/demo_storage/src/topology/vertexlist.cc b/demo_storage/src/topology/vertexlist.cc index ddd8935..3e358af 100644 --- a/demo_storage/src/topology/vertexlist.cc +++ b/demo_storage/src/topology/vertexlist.cc @@ -17,7 +17,7 @@ limitations under the License. // GRIN headers #include "topology/vertexlist.h" -#if defined(GRIN_ENABLE_VERTEX_LIST) && !defined(GRIN_WITH_VERTEX_PROPERTY) +#if defined(GRIN_ENABLE_VERTEX_LIST) && !defined(GRIN_ENABLE_SCHEMA) GRIN_VERTEX_LIST grin_get_vertex_list(GRIN_GRAPH); #endif From c367dd5a2f9073696c0ce3d81023a417626eef8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Mon, 26 Feb 2024 15:31:31 +0800 Subject: [PATCH 37/48] type --- demo_storage/src/property/topology.cc | 10 +-- demo_storage/src/property/type.cc | 109 ++++++++++++-------------- 2 files changed, 53 insertions(+), 66 deletions(-) diff --git a/demo_storage/src/property/topology.cc b/demo_storage/src/property/topology.cc index ffff9ac..b637dc9 100644 --- a/demo_storage/src/property/topology.cc +++ b/demo_storage/src/property/topology.cc @@ -14,21 +14,19 @@ limitations under the License. // GRIN headers #include "property/topology.h" -#ifdef GRIN_WITH_VERTEX_PROPERTY +#ifdef GRIN_ENABLE_SCHEMA size_t grin_get_vertex_num_by_type(GRIN_GRAPH g, GRIN_VERTEX_TYPE vtype) { auto _g = static_cast(g); return _g->GetVertexNum(vtype); } -#endif -#ifdef GRIN_WITH_EDGE_PROPERTY size_t grin_get_edge_num_by_type(GRIN_GRAPH g, GRIN_EDGE_TYPE etype) { auto _g = static_cast(g); return _g->GetEdgeNum(etype); } #endif -#if defined(GRIN_ENABLE_VERTEX_LIST) && defined(GRIN_WITH_VERTEX_PROPERTY) +#if defined(GRIN_ENABLE_VERTEX_LIST) && defined(GRIN_ENABLE_SCHEMA) GRIN_VERTEX_LIST grin_get_vertex_list_by_type(GRIN_GRAPH g, GRIN_VERTEX_TYPE vtype) { auto _g = static_cast(g); @@ -39,7 +37,7 @@ GRIN_VERTEX_LIST grin_get_vertex_list_by_type(GRIN_GRAPH g, } #endif -#if defined(GRIN_ENABLE_EDGE_LIST) && defined(GRIN_WITH_EDGE_PROPERTY) +#if defined(GRIN_ENABLE_EDGE_LIST) && defined(GRIN_ENABLE_SCHEMA) GRIN_EDGE_LIST grin_get_edge_list_by_type(GRIN_GRAPH g, GRIN_EDGE_TYPE etype) { auto _g = static_cast(g); if (etype >= _g->GetEdgeTypeNum()) @@ -49,7 +47,7 @@ GRIN_EDGE_LIST grin_get_edge_list_by_type(GRIN_GRAPH g, GRIN_EDGE_TYPE etype) { } #endif -#if defined(GRIN_ENABLE_ADJACENT_LIST) && defined(GRIN_WITH_EDGE_PROPERTY) +#if defined(GRIN_ENABLE_ADJACENT_LIST) && defined(GRIN_ENABLE_SCHEMA) GRIN_ADJACENT_LIST grin_get_adjacent_list_by_edge_type(GRIN_GRAPH g, GRIN_DIRECTION d, GRIN_VERTEX v, diff --git a/demo_storage/src/property/type.cc b/demo_storage/src/property/type.cc index 234a86c..37d21d4 100644 --- a/demo_storage/src/property/type.cc +++ b/demo_storage/src/property/type.cc @@ -14,7 +14,7 @@ limitations under the License. // GRIN headers #include "property/type.h" -#ifdef GRIN_WITH_VERTEX_PROPERTY +#ifdef GRIN_ENABLE_SCHEMA // Vertex type bool grin_equal_vertex_type(GRIN_GRAPH g, GRIN_VERTEX_TYPE vtype1, GRIN_VERTEX_TYPE vtype2) { @@ -27,6 +27,31 @@ GRIN_VERTEX_TYPE grin_get_vertex_type(GRIN_GRAPH g, GRIN_VERTEX v) { void grin_destroy_vertex_type(GRIN_GRAPH g, GRIN_VERTEX_TYPE vtype) { return; } +const char* grin_get_vertex_type_name(GRIN_GRAPH g, GRIN_VERTEX_TYPE vtype) { + auto _g = static_cast(g); + if (vtype >= _g->GetVertexTypeNum()) + return NULL; + return _g->GetVertexTypeName(vtype).c_str(); +} + +GRIN_VERTEX_TYPE grin_get_vertex_type_by_name(GRIN_GRAPH g, const char* name) { + auto _g = static_cast(g); + auto type_id = _g->GetVertexTypeId(std::string(name)); + if (type_id == -1) + return GRIN_NULL_VERTEX_TYPE; + return type_id; +} + +GRIN_VERTEX_TYPE_ID grin_get_vertex_type_id(GRIN_GRAPH g, + GRIN_VERTEX_TYPE vtype) { + return vtype; +} + +GRIN_VERTEX_TYPE grin_get_vertex_type_by_id(GRIN_GRAPH g, + GRIN_VERTEX_TYPE_ID vti) { + return vti; +} + // Vertex type list GRIN_VERTEX_TYPE_LIST grin_get_vertex_type_list(GRIN_GRAPH g) { auto _g = static_cast(g); @@ -67,50 +92,42 @@ GRIN_VERTEX_TYPE grin_get_vertex_type_from_list(GRIN_GRAPH g, return GRIN_NULL_VERTEX_TYPE; return (*_vtl)[idx]; } -#endif -#ifdef GRIN_WITH_VERTEX_TYPE_NAME -const char* grin_get_vertex_type_name(GRIN_GRAPH g, GRIN_VERTEX_TYPE vtype) { +// Edge type +bool grin_equal_edge_type(GRIN_GRAPH g, GRIN_EDGE_TYPE etype1, + GRIN_EDGE_TYPE etype2) { + return etype1 == etype2; +} + +GRIN_EDGE_TYPE grin_get_edge_type(GRIN_GRAPH g, GRIN_EDGE e) { + return DEMO_STORAGE_NAMESPACE::get_type_id_from_gid(e); +} + +void grin_destroy_edge_type(GRIN_GRAPH g, GRIN_EDGE_TYPE etype) { return; } + +const char* grin_get_edge_type_name(GRIN_GRAPH g, GRIN_EDGE_TYPE etype) { auto _g = static_cast(g); - if (vtype >= _g->GetVertexTypeNum()) + if (etype >= _g->GetEdgeTypeNum()) return NULL; - return _g->GetVertexTypeName(vtype).c_str(); + return _g->GetEdgeTypeName(etype).c_str(); } -GRIN_VERTEX_TYPE grin_get_vertex_type_by_name(GRIN_GRAPH g, const char* name) { +GRIN_EDGE_TYPE grin_get_edge_type_by_name(GRIN_GRAPH g, const char* name) { auto _g = static_cast(g); - auto type_id = _g->GetVertexTypeId(std::string(name)); + auto type_id = _g->GetEdgeTypeId(std::string(name)); if (type_id == -1) - return GRIN_NULL_VERTEX_TYPE; + return GRIN_NULL_EDGE_TYPE; return type_id; } -#endif -#ifdef GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_TYPE -GRIN_VERTEX_TYPE_ID grin_get_vertex_type_id(GRIN_GRAPH g, - GRIN_VERTEX_TYPE vtype) { - return vtype; -} - -GRIN_VERTEX_TYPE grin_get_vertex_type_by_id(GRIN_GRAPH g, - GRIN_VERTEX_TYPE_ID vti) { - return vti; -} -#endif - -#ifdef GRIN_WITH_EDGE_PROPERTY -// Edge type -bool grin_equal_edge_type(GRIN_GRAPH g, GRIN_EDGE_TYPE etype1, - GRIN_EDGE_TYPE etype2) { - return etype1 == etype2; +GRIN_EDGE_TYPE_ID grin_get_edge_type_id(GRIN_GRAPH g, GRIN_EDGE_TYPE etype) { + return etype; } -GRIN_EDGE_TYPE grin_get_edge_type(GRIN_GRAPH g, GRIN_EDGE e) { - return DEMO_STORAGE_NAMESPACE::get_type_id_from_gid(e); +GRIN_EDGE_TYPE grin_get_edge_type_by_id(GRIN_GRAPH g, GRIN_EDGE_TYPE_ID eti) { + return eti; } -void grin_destroy_edge_type(GRIN_GRAPH g, GRIN_EDGE_TYPE etype) { return; } - // Edge type list GRIN_EDGE_TYPE_LIST grin_get_edge_type_list(GRIN_GRAPH g) { auto _g = static_cast(g); @@ -151,36 +168,8 @@ GRIN_EDGE_TYPE grin_get_edge_type_from_list(GRIN_GRAPH g, return GRIN_NULL_EDGE_TYPE; return (*_etl)[idx]; } -#endif - -#ifdef GRIN_WITH_EDGE_TYPE_NAME -const char* grin_get_edge_type_name(GRIN_GRAPH g, GRIN_EDGE_TYPE etype) { - auto _g = static_cast(g); - if (etype >= _g->GetEdgeTypeNum()) - return NULL; - return _g->GetEdgeTypeName(etype).c_str(); -} - -GRIN_EDGE_TYPE grin_get_edge_type_by_name(GRIN_GRAPH g, const char* name) { - auto _g = static_cast(g); - auto type_id = _g->GetEdgeTypeId(std::string(name)); - if (type_id == -1) - return GRIN_NULL_EDGE_TYPE; - return type_id; -} -#endif - -#ifdef GRIN_TRAIT_NATURAL_ID_FOR_EDGE_TYPE -GRIN_EDGE_TYPE_ID grin_get_edge_type_id(GRIN_GRAPH g, GRIN_EDGE_TYPE etype) { - return etype; -} - -GRIN_EDGE_TYPE grin_get_edge_type_by_id(GRIN_GRAPH g, GRIN_EDGE_TYPE_ID eti) { - return eti; -} -#endif -#if defined(GRIN_WITH_VERTEX_PROPERTY) && defined(GRIN_WITH_EDGE_PROPERTY) +// relations between vertex type pair and edge type GRIN_VERTEX_TYPE_LIST grin_get_src_types_by_edge_type(GRIN_GRAPH g, GRIN_EDGE_TYPE etype) { auto _g = static_cast(g); From a1e1571c00137e9d0f58ecd41ad01d27f9a3e2f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Mon, 26 Feb 2024 15:37:42 +0800 Subject: [PATCH 38/48] row --- demo_storage/src/property/row.cc | 14 ++++++++++++++ demo_storage/test/test_property_value.cc | 3 ++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/demo_storage/src/property/row.cc b/demo_storage/src/property/row.cc index 0ba60fd..1532178 100644 --- a/demo_storage/src/property/row.cc +++ b/demo_storage/src/property/row.cc @@ -22,12 +22,26 @@ limitations under the License. return x; \ } +#if defined(GRIN_ENABLE_ROW) && \ + defined(GRIN_TRAIT_PROPERTY_VALUE_OF_FLOAT_ARRAY) +void grin_destroy_row_value_of_float_array(GRIN_GRAPH, const float*, size_t); + +const float* grin_get_float_array_from_row(GRIN_GRAPH, GRIN_ROW, size_t, + size_t*); + +bool grin_insert_float_array_to_row(GRIN_GRAPH, GRIN_ROW, const float*, size_t); +#endif + #ifdef GRIN_ENABLE_ROW void grin_destroy_row(GRIN_GRAPH g, GRIN_ROW r) { auto _r = static_cast(r); delete _r; } +void grin_destroy_row_value_of_string(GRIN_GRAPH g, const char* value) { + return; +} + int grin_get_int32_from_row(GRIN_GRAPH g, GRIN_ROW r, size_t idx) { auto _r = static_cast(r); __grin_check_row(_r, 0); diff --git a/demo_storage/test/test_property_value.cc b/demo_storage/test/test_property_value.cc index dfc817b..24c0c41 100644 --- a/demo_storage/test/test_property_value.cc +++ b/demo_storage/test/test_property_value.cc @@ -61,6 +61,7 @@ void test_property_row(GRIN_GRAPH graph) { // get value from row auto value0_ = grin_get_int32_from_row(graph, row, 0); auto value1_ = grin_get_string_from_row(graph, row, 1); + auto invalid_value = grin_get_float_from_row(graph, row, 100); ASSERT(grin_get_last_error_code() == INVALID_VALUE && invalid_value == 0.0); auto value2_ = grin_get_uint64_from_row(graph, row, 2); @@ -93,7 +94,7 @@ void test_property_row(GRIN_GRAPH graph) { std::cout << "check getting const value ptr from row completed" << std::endl; // destroy - grin_destroy_string_value(graph, value1_); + grin_destroy_row_value_of_string(graph, value1_); grin_destroy_row(graph, row); std::cout << "---- test property: row completed ----" << std::endl; From efc30dec6128c851f7d7fe5eb8ce3604f7bd7aff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Mon, 26 Feb 2024 16:03:19 +0800 Subject: [PATCH 39/48] update tests --- demo_storage/test/test.c | 90 ++++++++----------- demo_storage/test/test_property_primarykey.cc | 1 + demo_storage/test/test_property_value.cc | 5 +- demo_storage/test/test_topology.cc | 9 +- 4 files changed, 47 insertions(+), 58 deletions(-) diff --git a/demo_storage/test/test.c b/demo_storage/test/test.c index 6c66c2b..d7f7d45 100644 --- a/demo_storage/test/test.c +++ b/demo_storage/test/test.c @@ -1,13 +1,14 @@ #include #include #include -#include +#include // predefine for GRIN #include "predefine.h" // storage headers #include "storage/loadmoderngraph.h" // GRIN headers #include "common/error.h" +#include "common/message.h" #include "index/external_id.h" #include "index/internal_id.h" #include "index/label.h" @@ -22,6 +23,7 @@ #include "property/row.h" #include "property/topology.h" #include "property/type.h" +#include "property/value.h" #include "topology/adjacentlist.h" #include "topology/edgelist.h" #include "topology/structure.h" @@ -191,7 +193,7 @@ void test_property_type(int argc, char** argv) { for (size_t i = 0; i < vtl_size; ++i) { printf("------------ Iterate the %zu-th vertex type ------------\n", i); GRIN_VERTEX_TYPE vt = grin_get_vertex_type_from_list(g, vtl, i); -#ifdef GRIN_WITH_VERTEX_TYPE_NAME +#ifdef GRIN_ENABLE_SCHEMA const char* vt_name = grin_get_vertex_type_name(g, vt); printf("vertex type name: %s\n", vt_name); GRIN_VERTEX_TYPE vt0 = grin_get_vertex_type_by_name(g, vt_name); @@ -199,8 +201,6 @@ void test_property_type(int argc, char** argv) { printf("vertex type name not match\n"); } grin_destroy_vertex_type(g, vt0); -#endif -#ifdef GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_TYPE printf("vertex type id: %u\n", grin_get_vertex_type_id(g, vt)); GRIN_VERTEX_TYPE vt1 = grin_get_vertex_type_by_id(g, grin_get_vertex_type_id(g, vt)); @@ -216,7 +216,7 @@ void test_property_type(int argc, char** argv) { "------------ Create a vertex type list of one type \"person\" " "------------\n"); GRIN_VERTEX_TYPE_LIST vtl2 = grin_create_vertex_type_list(g); -#ifdef GRIN_WITH_VERTEX_TYPE_NAME +#ifdef GRIN_ENABLE_SCHEMA GRIN_VERTEX_TYPE vt2_w = grin_get_vertex_type_by_name(g, "knows"); if (vt2_w == GRIN_NULL_VERTEX_TYPE) { printf("(Correct) vertex type of knows does not exists\n"); @@ -251,7 +251,7 @@ void test_property_type(int argc, char** argv) { for (size_t i = 0; i < etl_size; ++i) { printf("------------ Iterate the %zu-th edge type ------------\n", i); GRIN_EDGE_TYPE et = grin_get_edge_type_from_list(g, etl, i); -#ifdef GRIN_WITH_EDGE_TYPE_NAME +#ifdef GRIN_ENABLE_SCHEMA const char* et_name = grin_get_edge_type_name(g, et); printf("edge type name: %s\n", et_name); GRIN_EDGE_TYPE et0 = grin_get_edge_type_by_name(g, et_name); @@ -259,8 +259,7 @@ void test_property_type(int argc, char** argv) { printf("edge type name not match\n"); } grin_destroy_edge_type(g, et0); -#endif -#ifdef GRIN_TRAIT_NATURAL_ID_FOR_EDGE_TYPE + printf("edge type id: %u\n", grin_get_edge_type_id(g, et)); GRIN_EDGE_TYPE et1 = grin_get_edge_type_by_id(g, grin_get_edge_type_id(g, et)); @@ -300,7 +299,7 @@ void test_property_type(int argc, char** argv) { "------------ Create an edge type list of one type \"created\" " "------------\n"); GRIN_EDGE_TYPE_LIST etl2 = grin_create_edge_type_list(g); -#ifdef GRIN_WITH_EDGE_TYPE_NAME +#ifdef GRIN_ENABLE_SCHEMA GRIN_EDGE_TYPE et2_w = grin_get_edge_type_by_name(g, "person"); if (et2_w == GRIN_NULL_EDGE_TYPE) { printf("(Correct) edge type of person does not exists\n"); @@ -358,7 +357,7 @@ FOR_VERTEX_LIST_SELECT_MASTER_BEGIN(g, vl) long long int rv = grin_get_int64_from_row(g, row, j); assert(pv == rv); #endif - #ifdef GRIN_WITH_VERTEX_PROPERTY_NAME + #ifdef GRIN_ENABLE_SCHEMA printf("%s %s: %lld\n", v_names[__vt][vid], grin_get_vertex_property_name(g, __vt, vp), pv); #else printf("%s %zu: %lld\n", v_names[__vt][vid], j, pv); @@ -371,13 +370,13 @@ FOR_VERTEX_LIST_SELECT_MASTER_BEGIN(g, vl) const char* rv = grin_get_string_from_row(g, row, j); assert(strcmp(pv, rv) == 0); #endif - #ifdef GRIN_WITH_VERTEX_PROPERTY_NAME + #ifdef GRIN_ENABLE_SCHEMA printf("%s %s: %s\n", v_names[__vt][vid], grin_get_vertex_property_name(g, __vt, vp), pv); #else printf("%s %zu: %s\n", v_names[__vt][vid], j, pv); #endif - grin_destroy_string_value(g, pv); - grin_destroy_string_value(g, rv); + grin_destroy_vertex_property_value_of_string(g, pv); + grin_destroy_row_value_of_string(g, rv); } grin_destroy_vertex_property(g, vp); } @@ -402,7 +401,7 @@ FOR_VERTEX_LIST_END(g, vl) assert(grin_equal_vertex_type(g, vt, vt1)); grin_destroy_vertex_type(g, vt1); - #ifdef GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_PROPERTY + #ifdef GRIN_ENABLE_SCHEMA unsigned int id = grin_get_vertex_property_id(g, vt, vp); GRIN_VERTEX_PROPERTY vp1 = grin_get_vertex_property_by_id(g, vt, id); assert(grin_equal_vertex_property(g, vp, vp1)); @@ -411,7 +410,7 @@ FOR_VERTEX_LIST_END(g, vl) unsigned int id = i; #endif - #ifdef GRIN_WITH_VERTEX_PROPERTY_NAME + #ifdef GRIN_ENABLE_SCHEMA const char* vp_name = grin_get_vertex_property_name(g, vt, vp); GRIN_VERTEX_PROPERTY vp2 = grin_get_vertex_property_by_name(g, vt, vp_name); @@ -424,12 +423,12 @@ FOR_VERTEX_LIST_END(g, vl) grin_destroy_vertex_property_list(g, vpl); // corner case - #ifdef GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_PROPERTY + #ifdef GRIN_ENABLE_SCHEMA GRIN_VERTEX_PROPERTY vp3 = grin_get_vertex_property_by_id(g, vt, vpl_size); assert(vp3 == GRIN_NULL_VERTEX_PROPERTY); #endif - #ifdef GRIN_WITH_VERTEX_PROPERTY_NAME + #ifdef GRIN_ENABLE_SCHEMA GRIN_VERTEX_PROPERTY vp4 = grin_get_vertex_property_by_name(g, vt, "unknown"); assert(vp4 == GRIN_NULL_VERTEX_PROPERTY); @@ -439,7 +438,7 @@ FOR_VERTEX_LIST_END(g, vl) grin_destroy_vertex_type_list(g, vtl); // corner case -#ifdef GRIN_WITH_VERTEX_PROPERTY_NAME +#ifdef GRIN_ENABLE_SCHEMA GRIN_VERTEX_PROPERTY_LIST vpl1 = grin_get_vertex_properties_by_name(g, "unknown"); assert(vpl1 == GRIN_NULL_VERTEX_PROPERTY_LIST); @@ -502,7 +501,7 @@ FOR_VERTEX_LIST_SELECT_MASTER_BEGIN(g, vl) long long int rv = grin_get_int64_from_row(g, row, j); assert(pv == rv); #endif - #ifdef GRIN_WITH_EDGE_PROPERTY_NAME + #ifdef GRIN_ENABLE_SCHEMA printf("%s %s %s: %lld\n", v_names[__vt][vid], v_names[ut][uid], grin_get_edge_property_name(g, __et, ep), pv); #else @@ -515,7 +514,7 @@ FOR_VERTEX_LIST_SELECT_MASTER_BEGIN(g, vl) double rv = grin_get_double_from_row(g, row, j); assert(pv == rv); #endif - #ifdef GRIN_WITH_EDGE_PROPERTY_NAME + #ifdef GRIN_ENABLE_SCHEMA printf("%s %s %s: %lf\n", v_names[__vt][vid], v_names[ut][uid], grin_get_edge_property_name(g, __et, ep), pv); #else @@ -528,7 +527,7 @@ FOR_VERTEX_LIST_SELECT_MASTER_BEGIN(g, vl) const char* rv = grin_get_string_from_row(g, row, j); assert(strcmp(pv, rv) == 0); #endif - #ifdef GRIN_WITH_EDGE_PROPERTY_NAME + #ifdef GRIN_ENABLE_SCHEMA printf("%s %s %s: %s\n", v_names[__vt][vid], v_names[ut][uid], grin_get_edge_property_name(g, __et, ep), pv); #else @@ -564,7 +563,7 @@ FOR_VERTEX_LIST_END(g, vl) assert(grin_equal_edge_type(g, et, et1)); grin_destroy_edge_type(g, et1); - #ifdef GRIN_TRAIT_NATURAL_ID_FOR_EDGE_PROPERTY + #ifdef GRIN_ENABLE_SCHEMA unsigned int id = grin_get_edge_property_id(g, et, ep); GRIN_EDGE_PROPERTY ep1 = grin_get_edge_property_by_id(g, et, id); assert(grin_equal_edge_property(g, ep, ep1)); @@ -573,7 +572,7 @@ FOR_VERTEX_LIST_END(g, vl) unsigned int id = i; #endif - #ifdef GRIN_WITH_EDGE_PROPERTY_NAME + #ifdef GRIN_ENABLE_SCHEMA const char* ep_name = grin_get_edge_property_name(g, et, ep); GRIN_EDGE_PROPERTY ep2 = grin_get_edge_property_by_name(g, et, ep_name); @@ -586,12 +585,12 @@ FOR_VERTEX_LIST_END(g, vl) grin_destroy_edge_property_list(g, epl); // corner case - #ifdef GRIN_TRAIT_NATURAL_ID_FOR_EDGE_PROPERTY + #ifdef GRIN_ENABLE_SCHEMA GRIN_EDGE_PROPERTY ep3 = grin_get_edge_property_by_id(g, et, epl_size); assert(ep3 == GRIN_NULL_EDGE_PROPERTY); #endif - #ifdef GRIN_WITH_EDGE_PROPERTY_NAME + #ifdef GRIN_ENABLE_SCHEMA GRIN_EDGE_PROPERTY ep4 = grin_get_edge_property_by_name(g, et, "unknown"); assert(ep4 == GRIN_NULL_EDGE_PROPERTY); @@ -601,7 +600,7 @@ FOR_VERTEX_LIST_END(g, vl) grin_destroy_edge_type_list(g, etl); // corner case -#ifdef GRIN_WITH_EDGE_PROPERTY_NAME +#ifdef GRIN_ENABLE_SCHEMA GRIN_EDGE_PROPERTY_LIST epl1 = grin_get_edge_properties_by_name(g, "unknown"); assert(epl1 == GRIN_NULL_EDGE_PROPERTY_LIST); @@ -683,24 +682,6 @@ void test_property_primary_key(int argc, char** argv) { } #endif -void test_error_code(int argc, char** argv) { - printf("+++++++++++++++++++++ Test error code +++++++++++++++++++++\n"); - GRIN_GRAPH g = get_graph(argc, argv, 0); - - GRIN_VERTEX_TYPE vt1 = grin_get_vertex_type_by_name(g, "person"); - GRIN_VERTEX_TYPE vt2 = grin_get_vertex_type_by_name(g, "software"); - GRIN_VERTEX_PROPERTY vp = grin_get_vertex_property_by_name(g, vt2, "lang"); -#ifdef GRIN_ENABLE_GRAPH_PARTITION - GRIN_VERTEX v = get_one_master_person(g); -#else - GRIN_VERTEX v = get_one_person(g); -#endif - - const char* value = grin_get_vertex_property_value_of_string(g, v, vp); - assert(grin_get_last_error_code() == INVALID_VALUE); -} - - void test_property(int argc, char** argv) { test_property_type(argc, argv); test_property_vertex_property_value(argc, argv); @@ -709,9 +690,6 @@ void test_property(int argc, char** argv) { #ifdef GRIN_ENABLE_VERTEX_PRIMARY_KEYS test_property_primary_key(argc, argv); #endif -#ifdef GRIN_WITH_VERTEX_PROPERTY_NAME - // test_error_code(argc, argv); -#endif } @@ -738,7 +716,7 @@ FOR_VERTEX_LIST_BEGIN(g0, vl0) #else const char* sref = grin_serialize_vertex_ref(g0, vref0); GRIN_VERTEX_REF vref1 = grin_deserialize_vertex_ref(g0, sref); - grin_destroy_string_value(g0, sref); + grin_destroy_serialized_vertex_ref(g0, sref); #endif GRIN_VERTEX v1 = grin_get_vertex_from_vertex_ref(g0, vref1); if (!grin_equal_vertex(g0, v0, v1)) { @@ -758,7 +736,7 @@ FOR_VERTEX_LIST_BEGIN(g0, vl0) #else const char* sref = grin_serialize_vertex_ref(g0, vref0); GRIN_VERTEX_REF vref1 = grin_deserialize_vertex_ref(g1, sref); - grin_destroy_string_value(g0, sref); + grin_destroy_serialized_vertex_ref(g0, sref); #endif GRIN_VERTEX v1 = grin_get_vertex_from_vertex_ref(g1, vref1); if (!grin_is_master_vertex(g1, v1)) { @@ -1012,7 +990,6 @@ FOR_VERTEX_LIST_END(g, vl) grin_destroy_graph(g); } - void test_index_external_id_of_int64(int argc, char** argv) { printf("+++++++++++++++++++++ Test index external id +++++++++++++++++++++\n"); GRIN_GRAPH g = get_graph(argc, argv, 0); @@ -1066,16 +1043,23 @@ void test_perf(int argc, char** argv) { test_vertex_property_value(argc, argv); } +void test_message(int argc, char** argv) { + const char* msg = grin_get_graph_schema_msg(argv[1]); + printf("Schema Msg:\n%s\n", msg); + grin_destroy_graph_schema_msg(msg); +} + int main(int argc, char** argv) { - // load modern graph by settting partition number and partition id + // load modern graph by settting partition number and partition id unsigned partition_num = 2; demo_storage_load_modern_graph("modern_graph", partition_num, 0); demo_storage_load_modern_graph("modern_graph", partition_num, 1); - // execute tests + // execute tests + test_message(argc, argv); test_index(argc, argv); test_property(argc, argv); test_partition(argc, argv); test_topology(argc, argv); test_perf(argc, argv); return 0; -} +} \ No newline at end of file diff --git a/demo_storage/test/test_property_primarykey.cc b/demo_storage/test/test_property_primarykey.cc index a3bff07..1ae54ec 100644 --- a/demo_storage/test/test_property_primarykey.cc +++ b/demo_storage/test/test_property_primarykey.cc @@ -28,6 +28,7 @@ limitations under the License. #include "property/row.h" #include "property/topology.h" #include "property/type.h" +#include "property/value.h" #include "topology/edgelist.h" #include "topology/structure.h" #include "topology/vertexlist.h" diff --git a/demo_storage/test/test_property_value.cc b/demo_storage/test/test_property_value.cc index 24c0c41..8ca6afc 100644 --- a/demo_storage/test/test_property_value.cc +++ b/demo_storage/test/test_property_value.cc @@ -28,6 +28,7 @@ limitations under the License. #include "property/row.h" #include "property/topology.h" #include "property/type.h" +#include "property/value.h" #include "topology/adjacentlist.h" #include "topology/edgelist.h" #include "topology/structure.h" @@ -172,8 +173,8 @@ void test_property_vertex(GRIN_GRAPH graph) { << std::endl; // destroy - grin_destroy_string_value(graph, value1); - grin_destroy_string_value(graph, value2); + grin_destroy_vertex_property_value_of_string(graph, value1); + grin_destroy_vertex_property_value_of_string(graph, value2); } // check getting value of invalid property diff --git a/demo_storage/test/test_topology.cc b/demo_storage/test/test_topology.cc index f5a39e3..17bc290 100644 --- a/demo_storage/test/test_topology.cc +++ b/demo_storage/test/test_topology.cc @@ -31,10 +31,13 @@ limitations under the License. #include "topology/structure.h" #include "topology/vertexlist.h" -void test_protobuf() { +void test_protobuf(const char* uri) { std::cout << "\n++++ test protobuf ++++" << std::endl; - std::cout << grin_get_static_storage_feature_msg() << std::endl; + auto msg = grin_get_graph_schema_msg(uri); + std::cout << msg << std::endl; + + grin_destroy_graph_schema_msg(msg); std::cout << "---- test protobuf ----" << std::endl; } @@ -236,7 +239,7 @@ int main() { delete[] uri_str; // test protobuf - test_protobuf(); + test_protobuf(uri_str); // test topology structure test_topology_structure(graph); From 2dc0945d1a1fe39476d16b24e6e9b1685d727306 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Mon, 26 Feb 2024 16:03:32 +0800 Subject: [PATCH 40/48] property --- demo_storage/src/property/property.cc | 381 ++++++---------------- demo_storage/src/property/propertylist.cc | 69 ---- 2 files changed, 94 insertions(+), 356 deletions(-) diff --git a/demo_storage/src/property/property.cc b/demo_storage/src/property/property.cc index 22d9e75..3b5f04c 100644 --- a/demo_storage/src/property/property.cc +++ b/demo_storage/src/property/property.cc @@ -15,27 +15,38 @@ limitations under the License. #include "common/error.h" #include "property/property.h" -#define __grin_check_vertex_property(v, vp, x) \ - grin_error_code = NO_ERROR; \ - auto vtype0 = DEMO_STORAGE_NAMESPACE::get_type_id_from_gid(v); \ - auto vtype1 = DEMO_STORAGE_NAMESPACE::get_type_id_from_gid(vp); \ - if (vtype0 != vtype1) { \ - grin_error_code = INVALID_VALUE; \ - return x; \ - } +#if !defined(GRIN_ENABLE_SCHEMA) && defined(GRIN_WITH_VERTEX_PROPERTY) +GRIN_VERTEX_PROPERTY_LIST grin_get_vertex_property_list(GRIN_GRAPH, + GRIN_VERTEX); + +const char* grin_get_vertex_property_name(GRIN_GRAPH, GRIN_VERTEX, + GRIN_VERTEX_PROPERTY); -#define __grin_check_edge_property(e, ep, x) \ - grin_error_code = NO_ERROR; \ - auto etype0 = DEMO_STORAGE_NAMESPACE::get_type_id_from_gid(e); \ - auto etype1 = DEMO_STORAGE_NAMESPACE::get_type_id_from_gid(ep); \ - if (etype0 != etype1) { \ - grin_error_code = INVALID_VALUE; \ - return x; \ +GRIN_VERTEX_PROPERTY grin_get_vertex_property_by_name(GRIN_GRAPH, GRIN_VERTEX, + const char* name); +#endif + +#if defined(GRIN_ENABLE_SCHEMA) && defined(GRIN_WITH_VERTEX_PROPERTY) +GRIN_VERTEX_PROPERTY_LIST grin_get_vertex_property_list_by_type( + GRIN_GRAPH g, GRIN_VERTEX_TYPE vtype) { + auto _g = static_cast(g); + if (vtype >= _g->GetVertexTypeNum()) + return GRIN_NULL_VERTEX_PROPERTY_LIST; + auto vpl = new GRIN_VERTEX_PROPERTY_LIST_T(); + auto n = _g->GetVertexPropertyNum(vtype); + for (auto i = 0; i < n; ++i) { + auto vp = + DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id(vtype, i); + vpl->push_back(vp); } + return vpl; +} -void grin_destroy_string_value(GRIN_GRAPH g, const char* value) { return; } +GRIN_VERTEX_TYPE grin_get_vertex_type_from_property(GRIN_GRAPH g, + GRIN_VERTEX_PROPERTY vp) { + return DEMO_STORAGE_NAMESPACE::get_type_id_from_gid(vp); +} -#ifdef GRIN_WITH_VERTEX_PROPERTY_NAME const char* grin_get_vertex_property_name(GRIN_GRAPH g, GRIN_VERTEX_TYPE vtype, GRIN_VERTEX_PROPERTY vp) { auto _g = static_cast(g); @@ -73,9 +84,51 @@ GRIN_VERTEX_PROPERTY_LIST grin_get_vertex_properties_by_name(GRIN_GRAPH g, } return vpl; } + +GRIN_VERTEX_PROPERTY grin_get_vertex_property_by_id( + GRIN_GRAPH g, GRIN_VERTEX_TYPE vtype, GRIN_VERTEX_PROPERTY_ID id) { + auto _g = static_cast(g); + if (vtype >= 0 & vtype < _g->GetVertexTypeNum() && id >= 0 && + id < _g->GetVertexPropertyNum(vtype)) { + return DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id(vtype, id); + } else { + return GRIN_NULL_VERTEX_PROPERTY; + } +} + +GRIN_VERTEX_PROPERTY_ID grin_get_vertex_property_id(GRIN_GRAPH g, + GRIN_VERTEX_TYPE vtype, + GRIN_VERTEX_PROPERTY vp) { + return DEMO_STORAGE_NAMESPACE::get_id_from_gid(vp); +} +#endif + +#if !defined(GRIN_ENABLE_SCHEMA) && defined(GRIN_WITH_EDGE_PROPERTY) +GRIN_EDGE_PROPERTY_LIST grin_get_edge_property_list(GRIN_GRAPH, GRIN_EDGE); + +const char* grin_get_edge_property_name(GRIN_GRAPH, GRIN_EDGE, + GRIN_EDGE_PROPERTY); + +GRIN_EDGE_PROPERTY grin_get_edge_property_by_name(GRIN_GRAPH, GRIN_EDGE, + const char* name); #endif -#ifdef GRIN_WITH_EDGE_PROPERTY_NAME +#if defined(GRIN_ENABLE_SCHEMA) && defined(GRIN_WITH_EDGE_PROPERTY) +GRIN_EDGE_PROPERTY_LIST grin_get_edge_property_list_by_type( + GRIN_GRAPH g, GRIN_EDGE_TYPE etype) { + auto _g = static_cast(g); + if (etype >= _g->GetEdgeTypeNum()) + return GRIN_NULL_VERTEX_PROPERTY_LIST; + auto epl = new GRIN_EDGE_PROPERTY_LIST_T(); + auto n = _g->GetEdgePropertyNum(etype); + for (auto i = 0; i < n; ++i) { + auto ep = + DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id(etype, i); + epl->push_back(ep); + } + return epl; +} + const char* grin_get_edge_property_name(GRIN_GRAPH g, GRIN_EDGE_TYPE etype, GRIN_EDGE_PROPERTY ep) { auto _g = static_cast(g); @@ -113,6 +166,29 @@ GRIN_EDGE_PROPERTY_LIST grin_get_edge_properties_by_name(GRIN_GRAPH g, } return epl; } + +GRIN_EDGE_TYPE grin_get_edge_type_from_property(GRIN_GRAPH g, + GRIN_EDGE_PROPERTY ep) { + return DEMO_STORAGE_NAMESPACE::get_type_id_from_gid(ep); +} + +GRIN_EDGE_PROPERTY grin_get_edge_property_by_id(GRIN_GRAPH g, + GRIN_EDGE_TYPE etype, + GRIN_EDGE_PROPERTY_ID id) { + auto _g = static_cast(g); + if (etype >= 0 && etype < _g->GetEdgeTypeNum() && id >= 0 && + id < _g->GetEdgePropertyNum(etype)) { + return DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id(etype, id); + } else { + return GRIN_NULL_EDGE_PROPERTY; + } +} + +GRIN_EDGE_PROPERTY_ID grin_get_edge_property_id(GRIN_GRAPH g, + GRIN_EDGE_TYPE etype, + GRIN_EDGE_PROPERTY ep) { + return DEMO_STORAGE_NAMESPACE::get_id_from_gid(ep); +} #endif #ifdef GRIN_WITH_VERTEX_PROPERTY @@ -131,141 +207,6 @@ GRIN_DATATYPE grin_get_vertex_property_datatype(GRIN_GRAPH g, auto& property = _g->GetVertexProperty(vp); return property.datatype_; } - -int grin_get_vertex_property_value_of_int32(GRIN_GRAPH g, GRIN_VERTEX v, - GRIN_VERTEX_PROPERTY vp) { - __grin_check_vertex_property(v, vp, 0); - auto _g = static_cast(g); - auto& property = _g->GetVertexProperty(vp); - auto& _v = _g->GetVertex(v); - return _v.GetProperty(property.name_); -} - -unsigned int grin_get_vertex_property_value_of_uint32(GRIN_GRAPH g, // NOLINT - GRIN_VERTEX v, - GRIN_VERTEX_PROPERTY vp) { - __grin_check_vertex_property(v, vp, 0); - auto _g = static_cast(g); - auto& property = _g->GetVertexProperty(vp); - auto& _v = _g->GetVertex(v); - return _v.GetProperty(property.name_); -} - -long long int grin_get_vertex_property_value_of_int64(GRIN_GRAPH g, // NOLINT - GRIN_VERTEX v, - GRIN_VERTEX_PROPERTY vp) { - __grin_check_vertex_property(v, vp, 0); - auto _g = static_cast(g); - auto& property = _g->GetVertexProperty(vp); - auto& _v = _g->GetVertex(v); - return _v.GetProperty(property.name_); -} - -unsigned long long int grin_get_vertex_property_value_of_uint64( // NOLINT - GRIN_GRAPH g, GRIN_VERTEX v, GRIN_VERTEX_PROPERTY vp) { - __grin_check_vertex_property(v, vp, 0); - auto _g = static_cast(g); - auto& property = _g->GetVertexProperty(vp); - auto& _v = _g->GetVertex(v); - return _v.GetProperty(property.name_); -} - -float grin_get_vertex_property_value_of_float(GRIN_GRAPH g, GRIN_VERTEX v, - GRIN_VERTEX_PROPERTY vp) { - __grin_check_vertex_property(v, vp, 0); - auto _g = static_cast(g); - auto& property = _g->GetVertexProperty(vp); - auto& _v = _g->GetVertex(v); - return _v.GetProperty(property.name_); -} - -double grin_get_vertex_property_value_of_double(GRIN_GRAPH g, GRIN_VERTEX v, - GRIN_VERTEX_PROPERTY vp) { - __grin_check_vertex_property(v, vp, 0); - auto _g = static_cast(g); - auto& property = _g->GetVertexProperty(vp); - auto& _v = _g->GetVertex(v); - return _v.GetProperty(property.name_); -} - -const char* grin_get_vertex_property_value_of_string(GRIN_GRAPH g, - GRIN_VERTEX v, - GRIN_VERTEX_PROPERTY vp) { - __grin_check_vertex_property(v, vp, NULL); - auto _g = static_cast(g); - auto& property = _g->GetVertexProperty(vp); - auto& _v = _g->GetVertex(v); - return _v.GetProperty(property.name_).c_str(); -} - -int grin_get_vertex_property_value_of_date32(GRIN_GRAPH g, GRIN_VERTEX v, - GRIN_VERTEX_PROPERTY vp) { - __grin_check_vertex_property(v, vp, 0); - auto _g = static_cast(g); - auto& property = _g->GetVertexProperty(vp); - auto& _v = _g->GetVertex(v); - return _v.GetProperty(property.name_); -} - -int grin_get_vertex_property_value_of_time32(GRIN_GRAPH g, GRIN_VERTEX v, - GRIN_VERTEX_PROPERTY vp) { - __grin_check_vertex_property(v, vp, 0); - auto _g = static_cast(g); - auto& property = _g->GetVertexProperty(vp); - auto& _v = _g->GetVertex(v); - return _v.GetProperty(property.name_); -} - -long long int grin_get_vertex_property_value_of_timestamp64( // NOLINT - GRIN_GRAPH g, GRIN_VERTEX v, GRIN_VERTEX_PROPERTY vp) { - __grin_check_vertex_property(v, vp, 0); - auto _g = static_cast(g); - auto& property = _g->GetVertexProperty(vp); - auto& _v = _g->GetVertex(v); - return _v.GetProperty(property.name_); -} - -GRIN_VERTEX_TYPE grin_get_vertex_type_from_property(GRIN_GRAPH g, - GRIN_VERTEX_PROPERTY vp) { - return DEMO_STORAGE_NAMESPACE::get_type_id_from_gid(vp); -} -#endif - -#if defined(GRIN_WITH_VERTEX_PROPERTY) && defined(GRIN_TRAIT_CONST_VALUE_PTR) -const void* grin_get_vertex_property_value(GRIN_GRAPH g, GRIN_VERTEX v, - GRIN_VERTEX_PROPERTY vp) { - auto _g = static_cast(g); - __grin_check_vertex_property(v, vp, NULL); - auto& _v = _g->GetVertex(v); - auto& property = _g->GetVertexProperty(vp); - auto& name = property.name_; - auto& type = property.datatype_; - switch (type) { - case GRIN_DATATYPE::Int32: - return &_v.GetProperty(name); - case GRIN_DATATYPE::UInt32: - return &_v.GetProperty(name); - case GRIN_DATATYPE::Int64: - return &_v.GetProperty(name); - case GRIN_DATATYPE::UInt64: - return &_v.GetProperty(name); - case GRIN_DATATYPE::Float: - return &_v.GetProperty(name); - case GRIN_DATATYPE::Double: - return &_v.GetProperty(name); - case GRIN_DATATYPE::String: - return _v.GetProperty(name).c_str(); - case GRIN_DATATYPE::Date32: - return &_v.GetProperty(name); - case GRIN_DATATYPE::Time32: - return &_v.GetProperty(name); - case GRIN_DATATYPE::Timestamp64: - return &_v.GetProperty(name); - default: - return NULL; - } - return NULL; -} #endif #ifdef GRIN_WITH_EDGE_PROPERTY @@ -282,138 +223,4 @@ GRIN_DATATYPE grin_get_edge_property_datatype(GRIN_GRAPH g, auto& property = _g->GetEdgeProperty(ep); return property.datatype_; } - -int grin_get_edge_property_value_of_int32(GRIN_GRAPH g, GRIN_EDGE e, - GRIN_EDGE_PROPERTY ep) { - __grin_check_edge_property(e, ep, 0); - auto _g = static_cast(g); - auto& property = _g->GetEdgeProperty(ep); - auto& _e = _g->GetEdge(e); - return _e.GetProperty(property.name_); -} - -unsigned int grin_get_edge_property_value_of_uint32(GRIN_GRAPH g, // NOLINT - GRIN_EDGE e, - GRIN_EDGE_PROPERTY ep) { - __grin_check_edge_property(e, ep, 0); - auto _g = static_cast(g); - auto& property = _g->GetEdgeProperty(ep); - auto& _e = _g->GetEdge(e); - return _e.GetProperty(property.name_); -} - -long long int grin_get_edge_property_value_of_int64(GRIN_GRAPH g, // NOLINT - GRIN_EDGE e, - GRIN_EDGE_PROPERTY ep) { - __grin_check_edge_property(e, ep, 0); - auto _g = static_cast(g); - auto& property = _g->GetEdgeProperty(ep); - auto& _e = _g->GetEdge(e); - return _e.GetProperty(property.name_); -} - -unsigned long long int grin_get_edge_property_value_of_uint64( // NOLINT - GRIN_GRAPH g, GRIN_EDGE e, GRIN_EDGE_PROPERTY ep) { - __grin_check_edge_property(e, ep, 0); - auto _g = static_cast(g); - auto& property = _g->GetEdgeProperty(ep); - auto& _e = _g->GetEdge(e); - return _e.GetProperty(property.name_); -} - -float grin_get_edge_property_value_of_float(GRIN_GRAPH g, GRIN_EDGE e, - GRIN_EDGE_PROPERTY ep) { - __grin_check_edge_property(e, ep, 0); - auto _g = static_cast(g); - auto& property = _g->GetEdgeProperty(ep); - auto& _e = _g->GetEdge(e); - return _e.GetProperty(property.name_); -} - -double grin_get_edge_property_value_of_double(GRIN_GRAPH g, GRIN_EDGE e, - GRIN_EDGE_PROPERTY ep) { - __grin_check_edge_property(e, ep, 0); - auto _g = static_cast(g); - auto& property = _g->GetEdgeProperty(ep); - auto& _e = _g->GetEdge(e); - return _e.GetProperty(property.name_); -} - -const char* grin_get_edge_property_value_of_string(GRIN_GRAPH g, GRIN_EDGE e, - GRIN_EDGE_PROPERTY ep) { - __grin_check_edge_property(e, ep, 0); - auto _g = static_cast(g); - auto& property = _g->GetEdgeProperty(ep); - auto& _e = _g->GetEdge(e); - return _e.GetProperty(property.name_).c_str(); -} - -int grin_get_edge_property_value_of_date32(GRIN_GRAPH g, GRIN_EDGE e, - GRIN_EDGE_PROPERTY ep) { - __grin_check_edge_property(e, ep, 0); - auto _g = static_cast(g); - auto& property = _g->GetEdgeProperty(ep); - auto& _e = _g->GetEdge(e); - return _e.GetProperty(property.name_); -} - -int grin_get_edge_property_value_of_time32(GRIN_GRAPH g, GRIN_EDGE e, - GRIN_EDGE_PROPERTY ep) { - __grin_check_edge_property(e, ep, 0); - auto _g = static_cast(g); - auto& property = _g->GetEdgeProperty(ep); - auto& _e = _g->GetEdge(e); - return _e.GetProperty(property.name_); -} - -long long int grin_get_edge_property_value_of_timestamp64( // NOLINT - GRIN_GRAPH g, GRIN_EDGE e, GRIN_EDGE_PROPERTY ep) { - __grin_check_edge_property(e, ep, 0); - auto _g = static_cast(g); - auto& property = _g->GetEdgeProperty(ep); - auto& _e = _g->GetEdge(e); - return _e.GetProperty(property.name_); -} - -GRIN_EDGE_TYPE grin_get_edge_type_from_property(GRIN_GRAPH g, - GRIN_EDGE_PROPERTY ep) { - return DEMO_STORAGE_NAMESPACE::get_type_id_from_gid(ep); -} -#endif - -#if defined(GRIN_WITH_EDGE_PROPERTY) && defined(GRIN_TRAIT_CONST_VALUE_PTR) -const void* grin_get_edge_property_value(GRIN_GRAPH g, GRIN_EDGE e, - GRIN_EDGE_PROPERTY ep) { - auto _g = static_cast(g); - __grin_check_edge_property(e, ep, NULL); - auto& _e = _g->GetEdge(e); - auto& property = _g->GetEdgeProperty(ep); - auto& name = property.name_; - auto& type = property.datatype_; - switch (type) { - case GRIN_DATATYPE::Int32: - return &_e.GetProperty(name); - case GRIN_DATATYPE::UInt32: - return &_e.GetProperty(name); - case GRIN_DATATYPE::Int64: - return &_e.GetProperty(name); - case GRIN_DATATYPE::UInt64: - return &_e.GetProperty(name); - case GRIN_DATATYPE::Float: - return &_e.GetProperty(name); - case GRIN_DATATYPE::Double: - return &_e.GetProperty(name); - case GRIN_DATATYPE::String: - return _e.GetProperty(name).c_str(); - case GRIN_DATATYPE::Date32: - return &_e.GetProperty(name); - case GRIN_DATATYPE::Time32: - return &_e.GetProperty(name); - case GRIN_DATATYPE::Timestamp64: - return &_e.GetProperty(name); - default: - return NULL; - } - return NULL; -} #endif diff --git a/demo_storage/src/property/propertylist.cc b/demo_storage/src/property/propertylist.cc index bc76e4a..c6e386c 100644 --- a/demo_storage/src/property/propertylist.cc +++ b/demo_storage/src/property/propertylist.cc @@ -15,21 +15,6 @@ limitations under the License. #include "property/propertylist.h" #ifdef GRIN_WITH_VERTEX_PROPERTY -GRIN_VERTEX_PROPERTY_LIST grin_get_vertex_property_list_by_type( - GRIN_GRAPH g, GRIN_VERTEX_TYPE vtype) { - auto _g = static_cast(g); - if (vtype >= _g->GetVertexTypeNum()) - return GRIN_NULL_VERTEX_PROPERTY_LIST; - auto vpl = new GRIN_VERTEX_PROPERTY_LIST_T(); - auto n = _g->GetVertexPropertyNum(vtype); - for (auto i = 0; i < n; ++i) { - auto vp = - DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id(vtype, i); - vpl->push_back(vp); - } - return vpl; -} - size_t grin_get_vertex_property_list_size(GRIN_GRAPH g, GRIN_VERTEX_PROPERTY_LIST vpl) { auto _vpl = static_cast(vpl); @@ -63,41 +48,7 @@ bool grin_insert_vertex_property_to_list(GRIN_GRAPH g, } #endif -#ifdef GRIN_TRAIT_NATURAL_ID_FOR_VERTEX_PROPERTY -GRIN_VERTEX_PROPERTY grin_get_vertex_property_by_id( - GRIN_GRAPH g, GRIN_VERTEX_TYPE vtype, GRIN_VERTEX_PROPERTY_ID id) { - auto _g = static_cast(g); - if (vtype >= 0 & vtype < _g->GetVertexTypeNum() && id >= 0 && - id < _g->GetVertexPropertyNum(vtype)) { - return DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id(vtype, id); - } else { - return GRIN_NULL_VERTEX_PROPERTY; - } -} - -GRIN_VERTEX_PROPERTY_ID grin_get_vertex_property_id(GRIN_GRAPH g, - GRIN_VERTEX_TYPE vtype, - GRIN_VERTEX_PROPERTY vp) { - return DEMO_STORAGE_NAMESPACE::get_id_from_gid(vp); -} -#endif - #ifdef GRIN_WITH_EDGE_PROPERTY -GRIN_EDGE_PROPERTY_LIST grin_get_edge_property_list_by_type( - GRIN_GRAPH g, GRIN_EDGE_TYPE etype) { - auto _g = static_cast(g); - if (etype >= _g->GetEdgeTypeNum()) - return GRIN_NULL_VERTEX_PROPERTY_LIST; - auto epl = new GRIN_EDGE_PROPERTY_LIST_T(); - auto n = _g->GetEdgePropertyNum(etype); - for (auto i = 0; i < n; ++i) { - auto ep = - DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id(etype, i); - epl->push_back(ep); - } - return epl; -} - size_t grin_get_edge_property_list_size(GRIN_GRAPH g, GRIN_EDGE_PROPERTY_LIST epl) { auto _epl = static_cast(epl); @@ -131,23 +82,3 @@ bool grin_insert_edge_property_to_list(GRIN_GRAPH g, return true; } #endif - -#ifdef GRIN_TRAIT_NATURAL_ID_FOR_EDGE_PROPERTY -GRIN_EDGE_PROPERTY grin_get_edge_property_by_id(GRIN_GRAPH g, - GRIN_EDGE_TYPE etype, - GRIN_EDGE_PROPERTY_ID id) { - auto _g = static_cast(g); - if (etype >= 0 && etype < _g->GetEdgeTypeNum() && id >= 0 && - id < _g->GetEdgePropertyNum(etype)) { - return DEMO_STORAGE_NAMESPACE::generate_gid_from_type_id_and_id(etype, id); - } else { - return GRIN_NULL_EDGE_PROPERTY; - } -} - -GRIN_EDGE_PROPERTY_ID grin_get_edge_property_id(GRIN_GRAPH g, - GRIN_EDGE_TYPE etype, - GRIN_EDGE_PROPERTY ep) { - return DEMO_STORAGE_NAMESPACE::get_id_from_gid(ep); -} -#endif From b93afb17bb2eade777537ea737beba7987450804 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Mon, 26 Feb 2024 16:08:00 +0800 Subject: [PATCH 41/48] fix --- demo_storage/test/test_topology.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo_storage/test/test_topology.cc b/demo_storage/test/test_topology.cc index 17bc290..6a36faf 100644 --- a/demo_storage/test/test_topology.cc +++ b/demo_storage/test/test_topology.cc @@ -236,10 +236,10 @@ int main() { char* uri_str = new char[uri.size() + 1]; snprintf(uri_str, uri.size() + 1, "%s", uri.c_str()); GRIN_GRAPH graph = grin_get_graph_from_storage(uri_str); - delete[] uri_str; // test protobuf test_protobuf(uri_str); + delete[] uri_str; // test topology structure test_topology_structure(graph); From 66f874bb7b7b055d725c05afcc40eac9a4404f73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Mon, 26 Feb 2024 16:08:09 +0800 Subject: [PATCH 42/48] implement value --- demo_storage/src/property/value.cc | 328 +++++++++++++++++++++++++++++ 1 file changed, 328 insertions(+) create mode 100644 demo_storage/src/property/value.cc diff --git a/demo_storage/src/property/value.cc b/demo_storage/src/property/value.cc new file mode 100644 index 0000000..56f95d9 --- /dev/null +++ b/demo_storage/src/property/value.cc @@ -0,0 +1,328 @@ +/** Copyright 2020 Alibaba Group Holding Limited. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "src/predefine.h" +// GRIN headers +#include "common/error.h" +#include "property/value.h" + +#define __grin_check_vertex_property(v, vp, x) \ + grin_error_code = NO_ERROR; \ + auto vtype0 = DEMO_STORAGE_NAMESPACE::get_type_id_from_gid(v); \ + auto vtype1 = DEMO_STORAGE_NAMESPACE::get_type_id_from_gid(vp); \ + if (vtype0 != vtype1) { \ + grin_error_code = INVALID_VALUE; \ + return x; \ + } + +#define __grin_check_edge_property(e, ep, x) \ + grin_error_code = NO_ERROR; \ + auto etype0 = DEMO_STORAGE_NAMESPACE::get_type_id_from_gid(e); \ + auto etype1 = DEMO_STORAGE_NAMESPACE::get_type_id_from_gid(ep); \ + if (etype0 != etype1) { \ + grin_error_code = INVALID_VALUE; \ + return x; \ + } + +#if defined(GRIN_WITH_VERTEX_PROPERTY) && \ + defined(GRIN_TRAIT_PROPERTY_VALUE_OF_FLOAT_ARRAY) +void grin_destroy_vertex_property_value_of_float_array(GRIN_GRAPH, const float*, + size_t); + +const float* grin_get_vertex_property_value_of_float_array(GRIN_GRAPH, + GRIN_VERTEX, + GRIN_VERTEX_PROPERTY, + size_t*); +#endif + +#ifdef GRIN_WITH_VERTEX_PROPERTY +void grin_destroy_vertex_property_value_of_string(GRIN_GRAPH v, + const char* value) { + return; +} + +int grin_get_vertex_property_value_of_int32(GRIN_GRAPH g, GRIN_VERTEX v, + GRIN_VERTEX_PROPERTY vp) { + __grin_check_vertex_property(v, vp, 0); + auto _g = static_cast(g); + auto& property = _g->GetVertexProperty(vp); + auto& _v = _g->GetVertex(v); + return _v.GetProperty(property.name_); +} + +unsigned int grin_get_vertex_property_value_of_uint32(GRIN_GRAPH g, // NOLINT + GRIN_VERTEX v, + GRIN_VERTEX_PROPERTY vp) { + __grin_check_vertex_property(v, vp, 0); + auto _g = static_cast(g); + auto& property = _g->GetVertexProperty(vp); + auto& _v = _g->GetVertex(v); + return _v.GetProperty(property.name_); +} + +long long int grin_get_vertex_property_value_of_int64(GRIN_GRAPH g, // NOLINT + GRIN_VERTEX v, + GRIN_VERTEX_PROPERTY vp) { + __grin_check_vertex_property(v, vp, 0); + auto _g = static_cast(g); + auto& property = _g->GetVertexProperty(vp); + auto& _v = _g->GetVertex(v); + return _v.GetProperty(property.name_); +} + +unsigned long long int grin_get_vertex_property_value_of_uint64( // NOLINT + GRIN_GRAPH g, GRIN_VERTEX v, GRIN_VERTEX_PROPERTY vp) { + __grin_check_vertex_property(v, vp, 0); + auto _g = static_cast(g); + auto& property = _g->GetVertexProperty(vp); + auto& _v = _g->GetVertex(v); + return _v.GetProperty(property.name_); +} + +float grin_get_vertex_property_value_of_float(GRIN_GRAPH g, GRIN_VERTEX v, + GRIN_VERTEX_PROPERTY vp) { + __grin_check_vertex_property(v, vp, 0); + auto _g = static_cast(g); + auto& property = _g->GetVertexProperty(vp); + auto& _v = _g->GetVertex(v); + return _v.GetProperty(property.name_); +} + +double grin_get_vertex_property_value_of_double(GRIN_GRAPH g, GRIN_VERTEX v, + GRIN_VERTEX_PROPERTY vp) { + __grin_check_vertex_property(v, vp, 0); + auto _g = static_cast(g); + auto& property = _g->GetVertexProperty(vp); + auto& _v = _g->GetVertex(v); + return _v.GetProperty(property.name_); +} + +const char* grin_get_vertex_property_value_of_string(GRIN_GRAPH g, + GRIN_VERTEX v, + GRIN_VERTEX_PROPERTY vp) { + __grin_check_vertex_property(v, vp, NULL); + auto _g = static_cast(g); + auto& property = _g->GetVertexProperty(vp); + auto& _v = _g->GetVertex(v); + return _v.GetProperty(property.name_).c_str(); +} + +int grin_get_vertex_property_value_of_date32(GRIN_GRAPH g, GRIN_VERTEX v, + GRIN_VERTEX_PROPERTY vp) { + __grin_check_vertex_property(v, vp, 0); + auto _g = static_cast(g); + auto& property = _g->GetVertexProperty(vp); + auto& _v = _g->GetVertex(v); + return _v.GetProperty(property.name_); +} + +int grin_get_vertex_property_value_of_time32(GRIN_GRAPH g, GRIN_VERTEX v, + GRIN_VERTEX_PROPERTY vp) { + __grin_check_vertex_property(v, vp, 0); + auto _g = static_cast(g); + auto& property = _g->GetVertexProperty(vp); + auto& _v = _g->GetVertex(v); + return _v.GetProperty(property.name_); +} + +long long int grin_get_vertex_property_value_of_timestamp64( // NOLINT + GRIN_GRAPH g, GRIN_VERTEX v, GRIN_VERTEX_PROPERTY vp) { + __grin_check_vertex_property(v, vp, 0); + auto _g = static_cast(g); + auto& property = _g->GetVertexProperty(vp); + auto& _v = _g->GetVertex(v); + return _v.GetProperty(property.name_); +} +#endif + +#if defined(GRIN_WITH_VERTEX_PROPERTY) && defined(GRIN_TRAIT_CONST_VALUE_PTR) +const void* grin_get_vertex_property_value(GRIN_GRAPH g, GRIN_VERTEX v, + GRIN_VERTEX_PROPERTY vp) { + auto _g = static_cast(g); + __grin_check_vertex_property(v, vp, NULL); + auto& _v = _g->GetVertex(v); + auto& property = _g->GetVertexProperty(vp); + auto& name = property.name_; + auto& type = property.datatype_; + switch (type) { + case GRIN_DATATYPE::Int32: + return &_v.GetProperty(name); + case GRIN_DATATYPE::UInt32: + return &_v.GetProperty(name); + case GRIN_DATATYPE::Int64: + return &_v.GetProperty(name); + case GRIN_DATATYPE::UInt64: + return &_v.GetProperty(name); + case GRIN_DATATYPE::Float: + return &_v.GetProperty(name); + case GRIN_DATATYPE::Double: + return &_v.GetProperty(name); + case GRIN_DATATYPE::String: + return _v.GetProperty(name).c_str(); + case GRIN_DATATYPE::Date32: + return &_v.GetProperty(name); + case GRIN_DATATYPE::Time32: + return &_v.GetProperty(name); + case GRIN_DATATYPE::Timestamp64: + return &_v.GetProperty(name); + default: + return NULL; + } + return NULL; +} +#endif + +#if defined(GRIN_WITH_EDGE_PROPERTY) && \ + defined(GRIN_TRAIT_PROPERTY_VALUE_OF_FLOAT_ARRAY) +void grin_destroy_edge_property_value_of_float_array(GRIN_GRAPH, const float*, + size_t); + +const float* grin_get_edge_property_value_of_float_array(GRIN_GRAPH, GRIN_EDGE, + GRIN_EDGE_PROPERTY, + size_t*); +#endif + +#ifdef GRIN_WITH_EDGE_PROPERTY +void grin_destroy_edge_property_value_of_string(GRIN_GRAPH g, + const char* value) { + return; +} + +int grin_get_edge_property_value_of_int32(GRIN_GRAPH g, GRIN_EDGE e, + GRIN_EDGE_PROPERTY ep) { + __grin_check_edge_property(e, ep, 0); + auto _g = static_cast(g); + auto& property = _g->GetEdgeProperty(ep); + auto& _e = _g->GetEdge(e); + return _e.GetProperty(property.name_); +} + +unsigned int grin_get_edge_property_value_of_uint32(GRIN_GRAPH g, // NOLINT + GRIN_EDGE e, + GRIN_EDGE_PROPERTY ep) { + __grin_check_edge_property(e, ep, 0); + auto _g = static_cast(g); + auto& property = _g->GetEdgeProperty(ep); + auto& _e = _g->GetEdge(e); + return _e.GetProperty(property.name_); +} + +long long int grin_get_edge_property_value_of_int64(GRIN_GRAPH g, // NOLINT + GRIN_EDGE e, + GRIN_EDGE_PROPERTY ep) { + __grin_check_edge_property(e, ep, 0); + auto _g = static_cast(g); + auto& property = _g->GetEdgeProperty(ep); + auto& _e = _g->GetEdge(e); + return _e.GetProperty(property.name_); +} + +unsigned long long int grin_get_edge_property_value_of_uint64( // NOLINT + GRIN_GRAPH g, GRIN_EDGE e, GRIN_EDGE_PROPERTY ep) { + __grin_check_edge_property(e, ep, 0); + auto _g = static_cast(g); + auto& property = _g->GetEdgeProperty(ep); + auto& _e = _g->GetEdge(e); + return _e.GetProperty(property.name_); +} + +float grin_get_edge_property_value_of_float(GRIN_GRAPH g, GRIN_EDGE e, + GRIN_EDGE_PROPERTY ep) { + __grin_check_edge_property(e, ep, 0); + auto _g = static_cast(g); + auto& property = _g->GetEdgeProperty(ep); + auto& _e = _g->GetEdge(e); + return _e.GetProperty(property.name_); +} + +double grin_get_edge_property_value_of_double(GRIN_GRAPH g, GRIN_EDGE e, + GRIN_EDGE_PROPERTY ep) { + __grin_check_edge_property(e, ep, 0); + auto _g = static_cast(g); + auto& property = _g->GetEdgeProperty(ep); + auto& _e = _g->GetEdge(e); + return _e.GetProperty(property.name_); +} + +const char* grin_get_edge_property_value_of_string(GRIN_GRAPH g, GRIN_EDGE e, + GRIN_EDGE_PROPERTY ep) { + __grin_check_edge_property(e, ep, 0); + auto _g = static_cast(g); + auto& property = _g->GetEdgeProperty(ep); + auto& _e = _g->GetEdge(e); + return _e.GetProperty(property.name_).c_str(); +} + +int grin_get_edge_property_value_of_date32(GRIN_GRAPH g, GRIN_EDGE e, + GRIN_EDGE_PROPERTY ep) { + __grin_check_edge_property(e, ep, 0); + auto _g = static_cast(g); + auto& property = _g->GetEdgeProperty(ep); + auto& _e = _g->GetEdge(e); + return _e.GetProperty(property.name_); +} + +int grin_get_edge_property_value_of_time32(GRIN_GRAPH g, GRIN_EDGE e, + GRIN_EDGE_PROPERTY ep) { + __grin_check_edge_property(e, ep, 0); + auto _g = static_cast(g); + auto& property = _g->GetEdgeProperty(ep); + auto& _e = _g->GetEdge(e); + return _e.GetProperty(property.name_); +} + +long long int grin_get_edge_property_value_of_timestamp64( // NOLINT + GRIN_GRAPH g, GRIN_EDGE e, GRIN_EDGE_PROPERTY ep) { + __grin_check_edge_property(e, ep, 0); + auto _g = static_cast(g); + auto& property = _g->GetEdgeProperty(ep); + auto& _e = _g->GetEdge(e); + return _e.GetProperty(property.name_); +} +#endif + +#if defined(GRIN_WITH_EDGE_PROPERTY) && defined(GRIN_TRAIT_CONST_VALUE_PTR) +const void* grin_get_edge_property_value(GRIN_GRAPH g, GRIN_EDGE e, + GRIN_EDGE_PROPERTY ep) { + auto _g = static_cast(g); + __grin_check_edge_property(e, ep, NULL); + auto& _e = _g->GetEdge(e); + auto& property = _g->GetEdgeProperty(ep); + auto& name = property.name_; + auto& type = property.datatype_; + switch (type) { + case GRIN_DATATYPE::Int32: + return &_e.GetProperty(name); + case GRIN_DATATYPE::UInt32: + return &_e.GetProperty(name); + case GRIN_DATATYPE::Int64: + return &_e.GetProperty(name); + case GRIN_DATATYPE::UInt64: + return &_e.GetProperty(name); + case GRIN_DATATYPE::Float: + return &_e.GetProperty(name); + case GRIN_DATATYPE::Double: + return &_e.GetProperty(name); + case GRIN_DATATYPE::String: + return _e.GetProperty(name).c_str(); + case GRIN_DATATYPE::Date32: + return &_e.GetProperty(name); + case GRIN_DATATYPE::Time32: + return &_e.GetProperty(name); + case GRIN_DATATYPE::Timestamp64: + return &_e.GetProperty(name); + default: + return NULL; + } + return NULL; +} +#endif From fd30deb18fbd617b86ee2b9f6ec39d224ecb41b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Mon, 26 Feb 2024 16:39:32 +0800 Subject: [PATCH 43/48] type to labels --- demo_storage/src/property/label.cc | 6 ++---- demo_storage/storage/storage.cc | 2 ++ demo_storage/storage/storage.h | 10 ++++++++++ 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/demo_storage/src/property/label.cc b/demo_storage/src/property/label.cc index 7e73d6b..90b0410 100644 --- a/demo_storage/src/property/label.cc +++ b/demo_storage/src/property/label.cc @@ -88,8 +88,7 @@ GRIN_LABEL_LIST grin_get_label_list_by_vertex_type(GRIN_GRAPH g, auto ll = new GRIN_LABEL_LIST_T(); auto n = _g->GetVertexLabelNum(); for (auto i = 0; i < n; ++i) { - auto& vtypes = _g->GetVertexTypesByLabel(i); - if (vtypes.find(vtype) != vtypes.end()) { + if (_g->VertexTypeHasLabel(vtype, i)) { ll->push_back(i); } } @@ -128,8 +127,7 @@ GRIN_LABEL_LIST grin_get_label_list_by_edge_type(GRIN_GRAPH g, auto ll = new GRIN_LABEL_LIST_T(); auto n = _g->GetEdgeLabelNum(); for (auto i = 0; i < n; ++i) { - auto& etypes = _g->GetEdgeTypesByLabel(i); - if (etypes.find(etype) != etypes.end()) { + if (_g->EdgeTypeHasLabel(etype, i)) { ll->push_back(i + _g->GetVertexLabelNum()); } } diff --git a/demo_storage/storage/storage.cc b/demo_storage/storage/storage.cc index ee8e67d..e2992b4 100644 --- a/demo_storage/storage/storage.cc +++ b/demo_storage/storage/storage.cc @@ -58,6 +58,7 @@ void Graph::AddVertex(Vertex& vertex) noexcept { // NOLINT AddVertexLabel(label); auto label_id = vertex_label_2_id_[label]; vertex_label_2_type_id_[label_id].insert(type_id); + vertex_type_has_label_.insert(std::make_pair(type_id, label_id)); vertex_pos_in_type_and_label_[std::make_tuple(type_id, label_id, gid)] = label_vertex_ids_[std::make_pair(type_id, label_id)].size(); label_vertex_ids_[std::make_pair(type_id, label_id)].push_back(gid); @@ -105,6 +106,7 @@ void Graph::AddEdge(Edge& edge) noexcept { // NOLINT for (auto& label : labels) { AddEdgeLabel(label); edge_label_2_type_id_[edge_label_2_id_[label]].insert(type_id); + edge_type_has_label_.insert(std::make_pair(type_id, edge_label_2_id_[label])); label_edge_ids_[std::make_pair(type_id, edge_label_2_id_[label])].push_back( edge.GetGid()); } diff --git a/demo_storage/storage/storage.h b/demo_storage/storage/storage.h index f60e232..324000c 100644 --- a/demo_storage/storage/storage.h +++ b/demo_storage/storage/storage.h @@ -351,6 +351,14 @@ class Graph { noexcept { return edge_label_2_type_id_[label_id]; } + bool VertexTypeHasLabel(uint32_t type_id, uint32_t label_id) const noexcept { + return vertex_type_has_label_.find(std::make_pair(type_id, label_id)) != + vertex_type_has_label_.end(); + } + bool EdgeTypeHasLabel(uint32_t type_id, uint32_t label_id) const noexcept { + return edge_type_has_label_.find(std::make_pair(type_id, label_id)) != + edge_type_has_label_.end(); + } // get vertex & edge number size_t GetVertexNum(uint32_t type_id) const noexcept { @@ -622,6 +630,8 @@ class Graph { std::map vertex_label_2_id_, edge_label_2_id_; std::vector> vertex_label_2_type_id_, edge_label_2_type_id_; + std::set> vertex_type_has_label_, + edge_type_has_label_; // label indices: // label_vertex_ids_[label][partition_id] = vector of global vid std::map, std::vector> From 66bcf4846ab523943d2d29c999f05d23ea7a4fd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Mon, 26 Feb 2024 16:45:57 +0800 Subject: [PATCH 44/48] update rust --- rust/Cargo.toml | 9 +++---- rust/grin.rs | 19 ++++++------- rust/grin_demo_storage.rs | 56 ++++++--------------------------------- 3 files changed, 20 insertions(+), 64 deletions(-) diff --git a/rust/Cargo.toml b/rust/Cargo.toml index d806a78..a126c04 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -56,8 +56,7 @@ grin_enable_vertex_external_id_of_int64 = [] grin_enable_vertex_external_id_of_string = [] grin_enable_vertex_pk_index = [] grin_enable_edge_pk_index = [] -grin_trait_loose_schema = [] -grin_features_enable_v6d = ['grin_assume_has_directed_graph', 'grin_assume_has_undirected_graph', 'grin_assume_has_multi_edge_graph', 'grin_enable_vertex_list', 'grin_enable_vertex_list_array', 'grin_enable_vertex_list_iterator', 'grin_enable_adjacent_list', 'grin_enable_adjacent_list_array', 'grin_enable_adjacent_list_iterator', 'grin_enable_graph_partition', 'grin_trait_natural_id_for_partition', 'grin_enable_vertex_ref', 'grin_trait_fast_vertex_ref', 'grin_trait_select_master_for_vertex_list', 'grin_enable_row', 'grin_with_vertex_property', 'grin_with_vertex_property_name', 'grin_with_vertex_type_name', 'grin_trait_natural_id_for_vertex_type', 'grin_trait_natural_id_for_vertex_property', 'grin_with_edge_property', 'grin_with_edge_property_name', 'grin_with_edge_type_name', 'grin_trait_natural_id_for_edge_type', 'grin_trait_natural_id_for_edge_property', 'grin_enable_vertex_primary_keys', 'grin_enable_vertex_internal_id_index', 'grin_enable_vertex_pk_index', 'grin_enable_vertex_external_id_of_int64'] -grin_features_enable_gart = ['grin_assume_has_directed_graph', 'grin_assume_has_undirected_graph', 'grin_assume_has_multi_edge_graph', 'grin_enable_vertex_list', 'grin_enable_vertex_list_iterator', 'grin_enable_adjacent_list', 'grin_enable_adjacent_list_iterator', 'grin_enable_graph_partition', 'grin_trait_natural_id_for_partition', 'grin_enable_vertex_ref', 'grin_trait_fast_vertex_ref', 'grin_trait_select_master_for_vertex_list', 'grin_enable_row', 'grin_with_vertex_property', 'grin_with_vertex_property_name', 'grin_with_vertex_type_name', 'grin_trait_natural_id_for_vertex_type', 'grin_trait_natural_id_for_vertex_property', 'grin_with_edge_property', 'grin_with_edge_property_name', 'grin_with_edge_type_name', 'grin_trait_natural_id_for_edge_type', 'grin_trait_natural_id_for_edge_property', 'grin_enable_vertex_internal_id_index'] -grin_features_enable_GraphAr = ['grin_assume_has_directed_graph', 'grin_assume_has_multi_edge_graph', 'grin_enable_vertex_list', 'grin_enable_vertex_list_array', 'grin_enable_vertex_list_iterator', 'grin_enable_edge_list', 'grin_enable_edge_list_iterator', 'grin_enable_adjacent_list', 'grin_enable_adjacent_list_iterator', 'grin_enable_graph_partition', 'grin_trait_natural_id_for_partition', 'grin_enable_vertex_ref', 'grin_trait_fast_vertex_ref', 'grin_assume_all_replicate_partition', 'grin_assume_replicate_master_mirror_partition_for_vertex_data', 'grin_assume_replicate_master_mirror_partition_for_edge_data', 'grin_trait_master_vertex_mirror_partition_list', 'grin_trait_mirror_vertex_mirror_partition_list', 'grin_trait_select_master_for_vertex_list', 'grin_trait_select_partition_for_vertex_list', 'grin_enable_row', 'grin_with_vertex_property', 'grin_with_vertex_property_name', 'grin_with_vertex_type_name', 'grin_trait_natural_id_for_vertex_type', 'grin_enable_vertex_primary_keys', 'grin_trait_natural_id_for_vertex_property', 'grin_with_edge_property', 'grin_with_edge_property_name', 'grin_with_edge_type_name', 'grin_trait_natural_id_for_edge_type', 'grin_trait_natural_id_for_edge_property', 'grin_assume_replicate_master_mirror_partition_for_vertex_property', 'grin_assume_replicate_master_mirror_partition_for_edge_property', 'grin_assume_all_vertex_list_sorted', 'grin_enable_vertex_internal_id_index'] -grin_features_enable_demo_storage = ['grin_assume_has_directed_graph', 'grin_assume_has_undirected_graph', 'grin_assume_has_multi_edge_graph', 'grin_with_vertex_data', 'grin_with_edge_data', 'grin_enable_vertex_list', 'grin_enable_vertex_list_array', 'grin_enable_vertex_list_iterator', 'grin_enable_edge_list', 'grin_enable_edge_list_array', 'grin_enable_edge_list_iterator', 'grin_enable_adjacent_list', 'grin_enable_adjacent_list_array', 'grin_enable_adjacent_list_iterator', 'grin_enable_graph_partition', 'grin_trait_natural_id_for_partition', 'grin_enable_vertex_ref', 'grin_trait_fast_vertex_ref', 'grin_enable_edge_ref', 'grin_trait_master_vertex_mirror_partition_list', 'grin_trait_mirror_vertex_mirror_partition_list', 'grin_trait_master_edge_mirror_partition_list', 'grin_trait_mirror_edge_mirror_partition_list', 'grin_trait_select_master_for_vertex_list', 'grin_trait_select_partition_for_vertex_list', 'grin_trait_select_master_for_edge_list', 'grin_trait_select_partition_for_edge_list', 'grin_trait_select_master_neighbor_for_adjacent_list', 'grin_trait_select_neighbor_partition_for_adjacent_list', 'grin_enable_row', 'grin_trait_const_value_ptr', 'grin_with_vertex_property', 'grin_with_vertex_property_name', 'grin_with_vertex_type_name', 'grin_trait_natural_id_for_vertex_type', 'grin_enable_vertex_primary_keys', 'grin_trait_natural_id_for_vertex_property', 'grin_with_edge_property', 'grin_with_edge_property_name', 'grin_with_edge_type_name', 'grin_trait_natural_id_for_edge_type', 'grin_enable_edge_primary_keys', 'grin_trait_natural_id_for_edge_property', 'grin_assume_all_vertex_list_sorted', 'grin_enable_vertex_internal_id_index', 'grin_enable_vertex_external_id_of_int64', 'grin_enable_vertex_external_id_of_string', 'grin_enable_vertex_pk_index', 'grin_enable_edge_pk_index', 'grin_trait_loose_schema'] +grin_features_enable_v6d = ['grin_assume_has_directed_graph', 'grin_assume_has_undirected_graph', 'grin_assume_has_multi_edge_graph', 'grin_enable_vertex_list', 'grin_enable_vertex_list_array', 'grin_enable_vertex_list_iterator', 'grin_enable_adjacent_list', 'grin_enable_adjacent_list_array', 'grin_enable_adjacent_list_iterator', 'grin_enable_graph_partition', 'grin_assume_edge_cut_partition', 'grin_trait_natural_id_for_partition', 'grin_enable_vertex_ref', 'grin_trait_fast_vertex_ref', 'grin_trait_select_master_for_vertex_list', 'grin_enable_row', 'grin_enable_schema', 'grin_trait_property_value_of_float_array', 'grin_with_vertex_property', 'grin_enable_vertex_primary_keys', 'grin_with_edge_property', 'grin_enable_vertex_internal_id_index', 'grin_enable_vertex_external_id_of_int64', 'grin_enable_vertex_pk_index'] +grin_features_enable_gart = ['grin_assume_has_undirected_graph', 'grin_assume_has_multi_edge_graph', 'grin_enable_vertex_list', 'grin_enable_vertex_list_iterator', 'grin_enable_adjacent_list', 'grin_enable_adjacent_list_iterator', 'grin_enable_graph_partition', 'grin_assume_edge_cut_partition', 'grin_trait_natural_id_for_partition', 'grin_enable_vertex_ref', 'grin_trait_fast_vertex_ref', 'grin_trait_select_master_for_vertex_list', 'grin_enable_row', 'grin_trait_const_value_ptr', 'grin_enable_schema', 'grin_trait_property_value_of_float_array', 'grin_with_vertex_property', 'grin_with_edge_property', 'grin_enable_vertex_internal_id_index', 'grin_enable_vertex_external_id_of_int64'] +grin_features_enable_graphar = ['grin_assume_has_multi_edge_graph', 'grin_enable_vertex_list', 'grin_enable_vertex_list_array', 'grin_enable_vertex_list_iterator', 'grin_enable_edge_list', 'grin_enable_edge_list_iterator', 'grin_enable_adjacent_list', 'grin_enable_adjacent_list_iterator', 'grin_enable_graph_partition', 'grin_trait_natural_id_for_partition', 'grin_enable_vertex_ref', 'grin_trait_fast_vertex_ref', 'grin_trait_master_vertex_mirror_partition_list', 'grin_trait_mirror_vertex_mirror_partition_list', 'grin_trait_select_master_for_vertex_list', 'grin_trait_select_partition_for_vertex_list', 'grin_enable_row', 'grin_enable_schema', 'grin_with_vertex_property', 'grin_enable_vertex_primary_keys', 'grin_with_edge_property', 'grin_trait_property_value_of_float_array', 'grin_assume_all_vertex_list_sorted', 'grin_enable_vertex_internal_id_index', 'grin_enable_vertex_external_id_of_int64'] +grin_features_enable_demo_storage = ['grin_assume_has_undirected_graph', 'grin_assume_has_multi_edge_graph', 'grin_with_vertex_data', 'grin_with_edge_data', 'grin_enable_vertex_list', 'grin_enable_vertex_list_array', 'grin_enable_vertex_list_iterator', 'grin_enable_edge_list', 'grin_enable_edge_list_array', 'grin_enable_edge_list_iterator', 'grin_enable_adjacent_list', 'grin_enable_adjacent_list_array', 'grin_enable_adjacent_list_iterator', 'grin_enable_graph_partition', 'grin_trait_natural_id_for_partition', 'grin_enable_vertex_ref', 'grin_trait_fast_vertex_ref', 'grin_enable_edge_ref', 'grin_trait_master_vertex_mirror_partition_list', 'grin_trait_mirror_vertex_mirror_partition_list', 'grin_trait_master_edge_mirror_partition_list', 'grin_trait_mirror_edge_mirror_partition_list', 'grin_trait_select_master_for_vertex_list', 'grin_trait_select_partition_for_vertex_list', 'grin_trait_select_master_for_edge_list', 'grin_trait_select_partition_for_edge_list', 'grin_trait_select_master_neighbor_for_adjacent_list', 'grin_trait_select_neighbor_partition_for_adjacent_list', 'grin_enable_row', 'grin_trait_const_value_ptr', 'grin_enable_schema', 'grin_with_vertex_property', 'grin_enable_vertex_primary_keys', 'grin_with_edge_property', 'grin_enable_edge_primary_keys', 'grin_with_vertex_label', 'grin_with_edge_label', 'grin_assume_all_vertex_list_sorted', 'grin_enable_vertex_internal_id_index', 'grin_enable_vertex_external_id_of_int64', 'grin_enable_vertex_external_id_of_string', 'grin_enable_vertex_pk_index', 'grin_enable_edge_pk_index'] diff --git a/rust/grin.rs b/rust/grin.rs index e761cb5..936262c 100644 --- a/rust/grin.rs +++ b/rust/grin.rs @@ -248,19 +248,21 @@ cfg_if::cfg_if! { pub type GrinPartitionId = u32; pub type GrinVertexRef = i64; pub type GrinEdgeRef = i64; - pub type GrinVertexType = u32; - pub type GrinVertexTypeList = *mut ::std::os::raw::c_void; pub type GrinVertexProperty = u32; pub type GrinVertexPropertyList = *mut ::std::os::raw::c_void; - pub type GrinVertexTypeId = u32; - pub type GrinVertexPropertyId = u32; - pub type GrinEdgeType = u32; - pub type GrinEdgeTypeList = *mut ::std::os::raw::c_void; pub type GrinEdgeProperty = u32; pub type GrinEdgePropertyList = *mut ::std::os::raw::c_void; + pub type GrinVertexType = u32; + pub type GrinVertexTypeList = *mut ::std::os::raw::c_void; + pub type GrinVertexTypeId = u32; + pub type GrinVertexPropertyId = u32; pub type GrinEdgeTypeId = u32; pub type GrinEdgePropertyId = u32; + pub type GrinEdgeType = u32; + pub type GrinEdgeTypeList = *mut ::std::os::raw::c_void; pub type GrinRow = *mut ::std::os::raw::c_void; + pub type GrinLabel = u32; + pub type GrinLabelList = *mut ::std::os::raw::c_void; pub const GRIN_NULL_DATATYPE: GrinDatatype = GRIN_DATATYPE_UNDEFINED; pub const GRIN_NULL_GRAPH: GrinGraph = std::ptr::null_mut(); pub const GRIN_NULL_VERTEX: GrinVertex = -1; @@ -1889,11 +1891,6 @@ extern "C" { arg3: GrinLabel, ) -> GrinEdgeList; - #[doc = " @brief get all the edge types that might have the label\n @param GrinGraph the graph\n @param GrinLabel the label\n @return the edge type list"] - #[cfg(all(feature = "grin_with_edge_label", feature = "grin_with_edge_property"))] - #[allow(unused)] - pub fn grin_get_edge_types_by_label(arg1: GrinGraph, arg2: GrinLabel) -> GrinEdgeTypeList; - #[cfg(feature = "grin_assume_all_vertex_list_sorted")] #[allow(unused)] pub fn grin_smaller_vertex(arg1: GrinGraph, arg2: GrinVertex, arg3: GrinVertex) -> bool; diff --git a/rust/grin_demo_storage.rs b/rust/grin_demo_storage.rs index 633186c..61e91cb 100644 --- a/rust/grin_demo_storage.rs +++ b/rust/grin_demo_storage.rs @@ -9,48 +9,6 @@ pub const GRIN_NULL_VERTEX_REF: i32 = -1; pub const GRIN_NULL_EDGE_REF: i32 = -1; pub type wchar_t = ::std::os::raw::c_int; pub type max_align_t = u128; -#[doc = "< incoming"] -pub const GRIN_DIRECTION_IN: GRIN_DIRECTION = 0; -#[doc = "< outgoing"] -pub const GRIN_DIRECTION_OUT: GRIN_DIRECTION = 1; -#[doc = "< incoming & outgoing"] -pub const GRIN_DIRECTION_BOTH: GRIN_DIRECTION = 2; -#[doc = " Enumerates the directions of edges with respect to a certain vertex"] -pub type GRIN_DIRECTION = ::std::os::raw::c_uint; -#[doc = "< other unknown types"] -pub const GRIN_DATATYPE_Undefined: GRIN_DATATYPE = 0; -#[doc = "< int"] -pub const GRIN_DATATYPE_Int32: GRIN_DATATYPE = 1; -#[doc = "< unsigned int"] -pub const GRIN_DATATYPE_UInt32: GRIN_DATATYPE = 2; -#[doc = "< long int"] -pub const GRIN_DATATYPE_Int64: GRIN_DATATYPE = 3; -#[doc = "< unsigned long int"] -pub const GRIN_DATATYPE_UInt64: GRIN_DATATYPE = 4; -#[doc = "< float"] -pub const GRIN_DATATYPE_Float: GRIN_DATATYPE = 5; -#[doc = "< double"] -pub const GRIN_DATATYPE_Double: GRIN_DATATYPE = 6; -#[doc = "< string"] -pub const GRIN_DATATYPE_String: GRIN_DATATYPE = 7; -#[doc = "< date"] -pub const GRIN_DATATYPE_Date32: GRIN_DATATYPE = 8; -#[doc = "< Time32"] -pub const GRIN_DATATYPE_Time32: GRIN_DATATYPE = 9; -#[doc = "< Timestamp"] -pub const GRIN_DATATYPE_Timestamp64: GRIN_DATATYPE = 10; -#[doc = " Enumerates the datatype supported in the storage"] -pub type GRIN_DATATYPE = ::std::os::raw::c_uint; -#[doc = "< success"] -pub const GRIN_ERROR_CODE_NO_ERROR: GRIN_ERROR_CODE = 0; -#[doc = "< unknown error"] -pub const GRIN_ERROR_CODE_UNKNOWN_ERROR: GRIN_ERROR_CODE = 1; -#[doc = "< invalid value"] -pub const GRIN_ERROR_CODE_INVALID_VALUE: GRIN_ERROR_CODE = 2; -#[doc = "< unknown datatype"] -pub const GRIN_ERROR_CODE_UNKNOWN_DATATYPE: GRIN_ERROR_CODE = 3; -#[doc = " Enumerates the error codes of grin"] -pub type GRIN_ERROR_CODE = ::std::os::raw::c_uint; pub type GRIN_GRAPH = *mut ::std::os::raw::c_void; pub type GRIN_VERTEX = ::std::os::raw::c_longlong; pub type GRIN_EDGE = ::std::os::raw::c_longlong; @@ -68,19 +26,21 @@ pub type GRIN_PARTITION_LIST = *mut ::std::os::raw::c_void; pub type GRIN_PARTITION_ID = ::std::os::raw::c_uint; pub type GRIN_VERTEX_REF = ::std::os::raw::c_longlong; pub type GRIN_EDGE_REF = ::std::os::raw::c_longlong; -pub type GRIN_VERTEX_TYPE = ::std::os::raw::c_uint; -pub type GRIN_VERTEX_TYPE_LIST = *mut ::std::os::raw::c_void; pub type GRIN_VERTEX_PROPERTY = ::std::os::raw::c_uint; pub type GRIN_VERTEX_PROPERTY_LIST = *mut ::std::os::raw::c_void; -pub type GRIN_VERTEX_TYPE_ID = ::std::os::raw::c_uint; -pub type GRIN_VERTEX_PROPERTY_ID = ::std::os::raw::c_uint; -pub type GRIN_EDGE_TYPE = ::std::os::raw::c_uint; -pub type GRIN_EDGE_TYPE_LIST = *mut ::std::os::raw::c_void; pub type GRIN_EDGE_PROPERTY = ::std::os::raw::c_uint; pub type GRIN_EDGE_PROPERTY_LIST = *mut ::std::os::raw::c_void; +pub type GRIN_VERTEX_TYPE = ::std::os::raw::c_uint; +pub type GRIN_VERTEX_TYPE_LIST = *mut ::std::os::raw::c_void; +pub type GRIN_VERTEX_TYPE_ID = ::std::os::raw::c_uint; +pub type GRIN_VERTEX_PROPERTY_ID = ::std::os::raw::c_uint; pub type GRIN_EDGE_TYPE_ID = ::std::os::raw::c_uint; pub type GRIN_EDGE_PROPERTY_ID = ::std::os::raw::c_uint; +pub type GRIN_EDGE_TYPE = ::std::os::raw::c_uint; +pub type GRIN_EDGE_TYPE_LIST = *mut ::std::os::raw::c_void; pub type GRIN_ROW = *mut ::std::os::raw::c_void; +pub type GRIN_LABEL = ::std::os::raw::c_uint; +pub type GRIN_LABEL_LIST = *mut ::std::os::raw::c_void; extern "C" { #[doc = " GRIN_FEATURES_ENABLE_DEMOSTORAGE\n RUST_KEEP pub const GRIN_NULL_DATATYPE: GrinDatatype = GRIN_DATATYPE_UNDEFINED;\n RUST_KEEP pub const GRIN_NULL_GRAPH: GrinGraph = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_VERTEX: GrinVertex = -1;\n RUST_KEEP pub const GRIN_NULL_EDGE: GrinEdge = -1;\n RUST_KEEP pub const GRIN_NULL_VERTEX_DATA: GrinVertexData = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_VERTEX_LIST: GrinVertexList = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_VERTEX_LIST_ITERATOR: GrinVertexListIterator = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_ADJACENT_LIST: GrinAdjacentList = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_ADJACENT_LIST_ITERATOR: GrinAdjacentListIterator = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_EDGE_DATA: GrinEdgeData = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_EDGE_LIST: GrinEdgeList = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_EDGE_LIST_ITERATOR: GrinEdgeListIterator = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_PARTITIONED_GRAPH: GrinPartitionedGraph = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_PARTITION: GrinPartition = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_PARTITION_LIST: GrinPartitionList = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_PARTITION_ID: GrinPartitionId = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_VERTEX_REF: GrinVertexRef = -1;\n RUST_KEEP pub const GRIN_NULL_EDGE_REF: GrinEdgeRef = -1;\n RUST_KEEP pub const GRIN_NULL_VERTEX_TYPE: GrinVertexType = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_VERTEX_TYPE_LIST: GrinVertexTypeList = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_VERTEX_PROPERTY: GrinVertexProperty = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_VERTEX_PROPERTY_LIST: GrinVertexPropertyList = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_VERTEX_TYPE_ID: GrinVertexTypeId = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_VERTEX_PROPERTY_ID: GrinVertexPropertyId = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_EDGE_TYPE: GrinEdgeType = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_EDGE_TYPE_LIST: GrinEdgeTypeList = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_EDGE_PROPERTY: GrinEdgeProperty = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_EDGE_PROPERTY_LIST: GrinEdgePropertyList = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_EDGE_TYPE_ID: GrinEdgeTypeId = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_EDGE_PROPERTY_ID: GrinEdgePropertyId = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_EDGE_LABEL: GrinLabel = u32::MAX;\n RUST_KEEP pub const GRIN_NULL_EDGE_LABEL_LIST: GrinLabelList = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_ROW: GrinRow = std::ptr::null_mut();\n RUST_KEEP pub const GRIN_NULL_SIZE: u32 = u32::MAX;"] pub static mut __rust_keep_grin_null: ::std::os::raw::c_int; From af0bd9507a0e37a33f044d1818392e3a4094de4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Mon, 26 Feb 2024 17:31:14 +0800 Subject: [PATCH 45/48] message --- demo_storage/predefine.h | 2 +- demo_storage/src/common/message.cc | 152 +++++++++++++++++++++++++++- demo_storage/storage/storage.cc | 3 +- demo_storage/test/test_partition.cc | 15 +++ demo_storage/test/test_topology.cc | 15 --- 5 files changed, 168 insertions(+), 19 deletions(-) diff --git a/demo_storage/predefine.h b/demo_storage/predefine.h index 2ed7da0..d1c45c7 100644 --- a/demo_storage/predefine.h +++ b/demo_storage/predefine.h @@ -68,7 +68,7 @@ extern "C" { #define GRIN_ENABLE_ROW #define GRIN_TRAIT_CONST_VALUE_PTR #define GRIN_ENABLE_SCHEMA -// #define GRIN_TRAIT_PROPERTY_VALUE_OF_FLOAT_ARRAY +#define GRIN_TRAIT_PROPERTY_VALUE_OF_FLOAT_ARRAY #define GRIN_WITH_VERTEX_PROPERTY #define GRIN_ENABLE_VERTEX_PRIMARY_KEYS #define GRIN_WITH_EDGE_PROPERTY diff --git a/demo_storage/src/common/message.cc b/demo_storage/src/common/message.cc index 7ed55fd..fe52b28 100644 --- a/demo_storage/src/common/message.cc +++ b/demo_storage/src/common/message.cc @@ -25,9 +25,157 @@ limitations under the License. void grin_destroy_graph_schema_msg(const char* s) { delete[] s; } +void _set_storage_data_type(grin::StorageDataType* sdt, GRIN_DATATYPE dt) { + switch (dt) { + case GRIN_DATATYPE::Undefined: + sdt->set_datatype(grin::DataType::DT_ANY); + break; + case GRIN_DATATYPE::Int32: + sdt->set_datatype(grin::DataType::DT_SIGNED_INT32); + break; + case GRIN_DATATYPE::UInt32: + sdt->set_datatype(grin::DataType::DT_UNSIGNED_INT32); + break; + case GRIN_DATATYPE::Int64: + sdt->set_datatype(grin::DataType::DT_SIGNED_INT64); + break; + case GRIN_DATATYPE::UInt64: + sdt->set_datatype(grin::DataType::DT_UNSIGNED_INT64); + break; + case GRIN_DATATYPE::Float: + sdt->set_datatype(grin::DataType::DT_FLOAT); + break; + case GRIN_DATATYPE::Double: + sdt->set_datatype(grin::DataType::DT_DOUBLE); + break; + case GRIN_DATATYPE::String: + sdt->set_datatype(grin::DataType::DT_STRING); + break; + case GRIN_DATATYPE::Date32: + sdt->set_datatype(grin::DataType::DT_SIGNED_INT32); + break; + case GRIN_DATATYPE::Time32: + sdt->set_datatype(grin::DataType::DT_SIGNED_INT32); + break; + case GRIN_DATATYPE::Timestamp64: + sdt->set_datatype(grin::DataType::DT_SIGNED_INT64); + break; + case GRIN_DATATYPE::FloatArray: + sdt->set_datatype(grin::DataType::DT_FLOAT_ARRAY); + break; + } +} + const char* grin_get_graph_schema_msg(const char* uri) { - // to implement the function - std::string msg = "demo storage: " + std::string(uri); + GRIN_PARTITIONED_GRAPH pg = grin_get_partitioned_graph_from_storage(uri); + GRIN_PARTITION_LIST local_partitions = grin_get_local_partition_list(pg); + GRIN_PARTITION partition = + grin_get_partition_from_list(pg, local_partitions, 0); + GRIN_GRAPH g = grin_get_local_graph_by_partition(pg, partition); + grin_destroy_partition(pg, partition); + grin_destroy_partition_list(pg, local_partitions); + grin_destroy_partitioned_graph(pg); + + grin::Graph s; + s.set_uri(uri); + auto schema = s.mutable_schema(); + + GRIN_VERTEX_TYPE_LIST vtl = grin_get_vertex_type_list(g); + size_t vtl_sz = grin_get_vertex_type_list_size(g, vtl); + + for (size_t i = 0; i < vtl_sz; ++i) { + GRIN_VERTEX_TYPE vt = grin_get_vertex_type_from_list(g, vtl, i); + auto svt = schema->add_vertex_types(); + svt->set_type_id(i); + svt->set_type_name(grin_get_vertex_type_name(g, vt)); + + GRIN_VERTEX_PROPERTY_LIST vpl = + grin_get_vertex_property_list_by_type(g, vt); + size_t vpl_sz = grin_get_vertex_property_list_size(g, vpl); + for (size_t j = 0; j < vpl_sz; ++j) { + GRIN_VERTEX_PROPERTY vp = grin_get_vertex_property_from_list(g, vpl, j); + auto svp = svt->add_properties(); + svp->set_property_id(j); + svp->set_property_name(grin_get_vertex_property_name(g, vt, vp)); + auto svpdt = svp->mutable_property_type(); + _set_storage_data_type(svpdt, grin_get_vertex_property_datatype(g, vp)); + grin_destroy_vertex_property(g, vp); + } + grin_destroy_vertex_property_list(g, vpl); + + GRIN_VERTEX_PROPERTY_LIST pks = grin_get_primary_keys_by_vertex_type(g, vt); + size_t pks_sz = grin_get_vertex_property_list_size(g, vpl); + for (size_t j = 0; j < pks_sz; ++j) { + GRIN_VERTEX_PROPERTY vp = grin_get_vertex_property_from_list(g, pks, j); + svt->add_primary_key_ids(grin_get_vertex_property_id(g, vt, vp)); + grin_destroy_vertex_property(g, vp); + } + grin_destroy_vertex_property_list(g, pks); + grin_destroy_vertex_type(g, vt); + } + grin_destroy_vertex_type_list(g, vtl); + + GRIN_EDGE_TYPE_LIST etl = grin_get_edge_type_list(g); + size_t etl_sz = grin_get_edge_type_list_size(g, etl); + + for (size_t i = 0; i < etl_sz; ++i) { + GRIN_EDGE_TYPE et = grin_get_edge_type_from_list(g, etl, i); + auto set = schema->add_edge_types(); + set->set_type_id(i); + set->set_type_name(grin_get_edge_type_name(g, et)); + + GRIN_EDGE_PROPERTY_LIST epl = grin_get_edge_property_list_by_type(g, et); + size_t epl_sz = grin_get_edge_property_list_size(g, epl); + for (size_t j = 0; j < epl_sz; ++j) { + GRIN_EDGE_PROPERTY ep = grin_get_edge_property_from_list(g, epl, j); + auto sep = set->add_properties(); + sep->set_property_id(j); + sep->set_property_name(grin_get_edge_property_name(g, et, ep)); + auto sepdt = sep->mutable_property_type(); + _set_storage_data_type(sepdt, grin_get_edge_property_datatype(g, ep)); + grin_destroy_edge_property(g, ep); + } + grin_destroy_edge_property_list(g, epl); + + GRIN_VERTEX_TYPE_LIST src_vtl = grin_get_src_types_by_edge_type(g, et); + GRIN_VERTEX_TYPE_LIST dst_vtl = grin_get_dst_types_by_edge_type(g, et); + size_t vtl_sz = grin_get_vertex_type_list_size(g, src_vtl); + for (size_t j = 0; j < vtl_sz; ++j) { + auto srel = set->add_vertex_type_pair_relations(); + GRIN_VERTEX_TYPE src_vt = grin_get_vertex_type_from_list(g, src_vtl, j); + GRIN_VERTEX_TYPE dst_vt = grin_get_vertex_type_from_list(g, dst_vtl, j); + srel->set_src_type_id(grin_get_vertex_type_id(g, src_vt)); + srel->set_dst_type_id(grin_get_vertex_type_id(g, dst_vt)); + grin_destroy_vertex_type(g, src_vt); + grin_destroy_vertex_type(g, dst_vt); + } + grin_destroy_vertex_type_list(g, src_vtl); + grin_destroy_vertex_type_list(g, dst_vtl); + grin_destroy_edge_type(g, et); + } + grin_destroy_edge_type_list(g, etl); + + auto sp = s.mutable_partition(); + auto sps = sp->add_partition_strategies(); + auto spse = sps->mutable_edge_cut(); + auto spsed = spse->mutable_directed_cut_edge_placement_strategies(); + spsed->add_cut_edge_placement_strategies( + grin:: + PartitionStrategy_EdgeCut_DirectedEdgePlacementStrategy_DEPS_TO_SRC); + spsed->add_cut_edge_placement_strategies( + grin:: + PartitionStrategy_EdgeCut_DirectedEdgePlacementStrategy_DEPS_TO_DST); + + sp->add_vertex_property_placement_strategies(grin::PPS_ON_MASTER); + sp->add_vertex_property_placement_strategies(grin::PPS_ON_MIRROR); + sp->add_edge_property_placement_strategies(grin::PPS_ON_MASTER); + sp->add_edge_property_placement_strategies(grin::PPS_ON_MIRROR); + + sp->add_master_vertices_sparse_index_strategies(grin::SIS_CSR); + sp->add_master_vertices_sparse_index_strategies(grin::SIS_CSC); + + std::string msg; + google::protobuf::util::MessageToJsonString(s, &msg); int len = msg.length() + 1; char* out = new char[len]; diff --git a/demo_storage/storage/storage.cc b/demo_storage/storage/storage.cc index e2992b4..b8f7185 100644 --- a/demo_storage/storage/storage.cc +++ b/demo_storage/storage/storage.cc @@ -106,7 +106,8 @@ void Graph::AddEdge(Edge& edge) noexcept { // NOLINT for (auto& label : labels) { AddEdgeLabel(label); edge_label_2_type_id_[edge_label_2_id_[label]].insert(type_id); - edge_type_has_label_.insert(std::make_pair(type_id, edge_label_2_id_[label])); + edge_type_has_label_.insert( + std::make_pair(type_id, edge_label_2_id_[label])); label_edge_ids_[std::make_pair(type_id, edge_label_2_id_[label])].push_back( edge.GetGid()); } diff --git a/demo_storage/test/test_partition.cc b/demo_storage/test/test_partition.cc index e8a9f0a..ba8b2a4 100644 --- a/demo_storage/test/test_partition.cc +++ b/demo_storage/test/test_partition.cc @@ -22,9 +22,21 @@ limitations under the License. // test config headers #include "test/config.h" // GRIN headers +#include "common/message.h" #include "partition/partition.h" #include "topology/structure.h" +void test_protobuf(const char* uri) { + std::cout << "\n++++ test protobuf ++++" << std::endl; + + auto msg = grin_get_graph_schema_msg(uri); + std::cout << msg << std::endl; + + grin_destroy_graph_schema_msg(msg); + + std::cout << "---- test protobuf ----" << std::endl; +} + void test_partition_partition(GRIN_PARTITIONED_GRAPH pg, unsigned n) { std::cout << "\n++++ test partition: partition ++++" << std::endl; @@ -108,6 +120,9 @@ int main() { char* uri_str = new char[uri.size() + 1]; snprintf(uri_str, uri.size() + 1, "%s", uri.c_str()); GRIN_PARTITIONED_GRAPH pg = grin_get_partitioned_graph_from_storage(uri_str); + + // test protobuf + test_protobuf(uri_str); delete[] uri_str; // test partitioned graph diff --git a/demo_storage/test/test_topology.cc b/demo_storage/test/test_topology.cc index 6a36faf..6a6af64 100644 --- a/demo_storage/test/test_topology.cc +++ b/demo_storage/test/test_topology.cc @@ -23,7 +23,6 @@ limitations under the License. // test config headers #include "test/config.h" // GRIN headers -#include "common/message.h" #include "property/topology.h" #include "property/type.h" #include "topology/adjacentlist.h" @@ -31,17 +30,6 @@ limitations under the License. #include "topology/structure.h" #include "topology/vertexlist.h" -void test_protobuf(const char* uri) { - std::cout << "\n++++ test protobuf ++++" << std::endl; - - auto msg = grin_get_graph_schema_msg(uri); - std::cout << msg << std::endl; - - grin_destroy_graph_schema_msg(msg); - - std::cout << "---- test protobuf ----" << std::endl; -} - void test_topology_structure(GRIN_GRAPH graph) { std::cout << "\n++++ test topology: structure ++++" << std::endl; @@ -236,9 +224,6 @@ int main() { char* uri_str = new char[uri.size() + 1]; snprintf(uri_str, uri.size() + 1, "%s", uri.c_str()); GRIN_GRAPH graph = grin_get_graph_from_storage(uri_str); - - // test protobuf - test_protobuf(uri_str); delete[] uri_str; // test topology structure From 74d01648cc7edf3124b20a8190e1c5cf36c5dbc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Mon, 26 Feb 2024 17:44:56 +0800 Subject: [PATCH 46/48] universal --- demo_storage/predefine.h | 2 +- demo_storage/src/partition/topology.cc | 18 ++++++++++++--- demo_storage/test/test_partition_topology.cc | 23 ++++++++++++++++++++ 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/demo_storage/predefine.h b/demo_storage/predefine.h index d1c45c7..006d4c6 100644 --- a/demo_storage/predefine.h +++ b/demo_storage/predefine.h @@ -49,7 +49,7 @@ extern "C" { #define GRIN_ENABLE_ADJACENT_LIST_ITERATOR // Partition #define GRIN_ENABLE_GRAPH_PARTITION -// #define GRIN_ASSUME_WITH_UNIVERSAL_VERTICES +#define GRIN_ASSUME_WITH_UNIVERSAL_VERTICES #define GRIN_TRAIT_NATURAL_ID_FOR_PARTITION #define GRIN_ENABLE_VERTEX_REF #define GRIN_TRAIT_FAST_VERTEX_REF diff --git a/demo_storage/src/partition/topology.cc b/demo_storage/src/partition/topology.cc index 61a73a1..f7b472e 100644 --- a/demo_storage/src/partition/topology.cc +++ b/demo_storage/src/partition/topology.cc @@ -154,12 +154,24 @@ grin_get_adjacent_list_by_edge_type_select_partition_neighbor( #endif #if defined(GRIN_ASSUME_WITH_UNIVERSAL_VERTICES) && defined(GRIN_ENABLE_SCHEMA) -GRIN_VERTEX_TYPE_LIST grin_get_vertex_type_list_select_universal(GRIN_GRAPH); +GRIN_VERTEX_TYPE_LIST grin_get_vertex_type_list_select_universal(GRIN_GRAPH g) { + auto _g = static_cast(g); + auto vtl = new GRIN_VERTEX_TYPE_LIST_T(); + auto num = _g->GetVertexTypeNum(); + for (auto i = 0; i < num; i++) + vtl->push_back(i); + return vtl; +} GRIN_VERTEX_TYPE_LIST grin_get_vertex_type_list_select_non_universal( - GRIN_GRAPH); + GRIN_GRAPH g) { + auto vtl = new GRIN_VERTEX_TYPE_LIST_T(); + return vtl; +} -bool grin_is_vertex_type_unisversal(GRIN_GRAPH, GRIN_VERTEX_TYPE); +bool grin_is_vertex_type_unisversal(GRIN_GRAPH g, GRIN_VERTEX_TYPE vt) { + return true; +} #endif #if defined(GRIN_ASSUME_WITH_UNIVERSAL_VERTICES) && \ diff --git a/demo_storage/test/test_partition_topology.cc b/demo_storage/test/test_partition_topology.cc index 47bad3f..38461ee 100644 --- a/demo_storage/test/test_partition_topology.cc +++ b/demo_storage/test/test_partition_topology.cc @@ -288,6 +288,28 @@ void test_adjacency_list(GRIN_PARTITIONED_GRAPH pg, GRIN_GRAPH graph, grin_destroy_edge_type(graph, edge_type); } +void test_universal_vertex(GRIN_PARTITIONED_GRAPH pg, GRIN_GRAPH graph) { + std::cout << "\n== test universal vertex ==" << std::endl; + auto vtl = grin_get_vertex_type_list_select_universal(graph); + auto vtl_size = grin_get_vertex_type_list_size(graph, vtl); + std::cout << "universal vertex type list size = " << vtl_size << std::endl; + for (auto i = 0; i < vtl_size; ++i) { + auto vtype = grin_get_vertex_type_from_list(graph, vtl, i); + ASSERT(grin_is_vertex_type_unisversal(graph, vtype) == true); + grin_destroy_vertex_type(graph, vtype); + } + + auto vtl_2 = grin_get_vertex_type_list_select_non_universal(graph); + auto vtl_size_2 = grin_get_vertex_type_list_size(graph, vtl_2); + std::cout << "non-universal vertex type list size = " << vtl_size_2 + << std::endl; + ASSERT(vtl_size_2 == 0); + + // destroy + grin_destroy_vertex_type_list(graph, vtl); + grin_destroy_vertex_type_list(graph, vtl_2); +} + void test_partition_topology(GRIN_PARTITIONED_GRAPH pg, unsigned n) { std::cout << "\n++++ test partition: topology ++++" << std::endl; @@ -320,6 +342,7 @@ void test_partition_topology(GRIN_PARTITIONED_GRAPH pg, unsigned n) { test_adjacency_list(pg, graph, vertex, GRIN_DIRECTION::IN); test_adjacency_list(pg, graph, vertex, GRIN_DIRECTION::OUT); test_adjacency_list(pg, graph, vertex, GRIN_DIRECTION::BOTH); + test_universal_vertex(pg, graph); // destroy grin_destroy_vertex_type(graph, vtype); From da6f0096988c8e5c69049e4985988fcb3fbc3390 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Mon, 26 Feb 2024 18:57:21 +0800 Subject: [PATCH 47/48] row of float array --- demo_storage/src/property/row.cc | 24 ++++++++++++++++++++---- demo_storage/test/test_property_value.cc | 14 ++++++++++++++ 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/demo_storage/src/property/row.cc b/demo_storage/src/property/row.cc index 1532178..7d614e1 100644 --- a/demo_storage/src/property/row.cc +++ b/demo_storage/src/property/row.cc @@ -10,6 +10,8 @@ See the License for the specific language governing permissions and limitations under the License. */ +#include + #include "src/predefine.h" // GRIN headers #include "common/error.h" @@ -24,12 +26,26 @@ limitations under the License. #if defined(GRIN_ENABLE_ROW) && \ defined(GRIN_TRAIT_PROPERTY_VALUE_OF_FLOAT_ARRAY) -void grin_destroy_row_value_of_float_array(GRIN_GRAPH, const float*, size_t); +void grin_destroy_row_value_of_float_array(GRIN_GRAPH g, const float* value, + size_t length) { + return; +} -const float* grin_get_float_array_from_row(GRIN_GRAPH, GRIN_ROW, size_t, - size_t*); +const float* grin_get_float_array_from_row(GRIN_GRAPH g, GRIN_ROW r, size_t idx, + size_t* length) { + auto _r = static_cast(r); + __grin_check_row(_r, NULL); + *length = any_cast&>(_r->at(idx)).size(); + return any_cast&>(_r->at(idx)).data(); +} -bool grin_insert_float_array_to_row(GRIN_GRAPH, GRIN_ROW, const float*, size_t); +bool grin_insert_float_array_to_row(GRIN_GRAPH g, GRIN_ROW r, + const float* value, size_t length) { + auto _r = static_cast(r); + std::vector v(value, value + length); + _r->push_back(v); + return true; +} #endif #ifdef GRIN_ENABLE_ROW diff --git a/demo_storage/test/test_property_value.cc b/demo_storage/test/test_property_value.cc index 8ca6afc..02300ad 100644 --- a/demo_storage/test/test_property_value.cc +++ b/demo_storage/test/test_property_value.cc @@ -45,6 +45,7 @@ void test_property_row(GRIN_GRAPH graph) { const char* value1 = "Test String"; uint64_t value2 = 2; double value3 = 3.3; + float* value4 = new float[3]{4.4, 5.5, 6.6}; std::cout << "put value0: " << value0 << std::endl; std::cout << "put value1: " << value1 << std::endl; @@ -58,6 +59,8 @@ void test_property_row(GRIN_GRAPH graph) { ASSERT(status == true); status = grin_insert_double_to_row(graph, row, value3); ASSERT(status == true); + status = grin_insert_float_array_to_row(graph, row, value4, 3); + ASSERT(status == true); // get value from row auto value0_ = grin_get_int32_from_row(graph, row, 0); @@ -69,6 +72,11 @@ void test_property_row(GRIN_GRAPH graph) { auto value3_ = grin_get_double_from_row(graph, row, 3); ASSERT(grin_get_last_error_code() == NO_ERROR); + size_t length = 0; + auto value4_ = grin_get_float_array_from_row(graph, row, 4, &length); + ASSERT(grin_get_last_error_code() == NO_ERROR); + ASSERT(length == 3); + // check value std::cout << "get value0: " << value0_ << std::endl; std::cout << "get value1: " << value1_ << std::endl; @@ -79,6 +87,11 @@ void test_property_row(GRIN_GRAPH graph) { ASSERT(value2_ == value2); ASSERT(value3_ == value3); + for (size_t i = 0; i < length; i++) { + std::cout << "get value4[" << i << "]: " << value4_[i] << std::endl; + ASSERT(value4_[i] == value4[i]); + } + // get const value ptr from row auto value0_ptr = grin_get_value_from_row(graph, row, GRIN_DATATYPE::Int32, 0); @@ -97,6 +110,7 @@ void test_property_row(GRIN_GRAPH graph) { // destroy grin_destroy_row_value_of_string(graph, value1_); grin_destroy_row(graph, row); + grin_destroy_row_value_of_float_array(graph, value4_, 3); std::cout << "---- test property: row completed ----" << std::endl; } From d980b064f2cd99e5cc89b98b75c23c8f69c7af6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E7=90=86?= Date: Mon, 26 Feb 2024 19:13:04 +0800 Subject: [PATCH 48/48] float --- demo_storage/src/property/value.cc | 41 +++++++++++++++++------- demo_storage/storage/storage.cc | 4 +++ demo_storage/test/test_property_value.cc | 28 +++++++++++++++- 3 files changed, 61 insertions(+), 12 deletions(-) diff --git a/demo_storage/src/property/value.cc b/demo_storage/src/property/value.cc index 56f95d9..d3a240f 100644 --- a/demo_storage/src/property/value.cc +++ b/demo_storage/src/property/value.cc @@ -35,13 +35,21 @@ limitations under the License. #if defined(GRIN_WITH_VERTEX_PROPERTY) && \ defined(GRIN_TRAIT_PROPERTY_VALUE_OF_FLOAT_ARRAY) -void grin_destroy_vertex_property_value_of_float_array(GRIN_GRAPH, const float*, - size_t); +void grin_destroy_vertex_property_value_of_float_array(GRIN_GRAPH g, + const float* value, + size_t length) { + return; +} -const float* grin_get_vertex_property_value_of_float_array(GRIN_GRAPH, - GRIN_VERTEX, - GRIN_VERTEX_PROPERTY, - size_t*); +const float* grin_get_vertex_property_value_of_float_array( + GRIN_GRAPH g, GRIN_VERTEX v, GRIN_VERTEX_PROPERTY vp, size_t* length) { + __grin_check_vertex_property(v, vp, NULL); + auto _g = static_cast(g); + auto& property = _g->GetVertexProperty(vp); + auto& _v = _g->GetVertex(v); + *length = _v.GetProperty&>(property.name_).size(); + return _v.GetProperty&>(property.name_).data(); +} #endif #ifdef GRIN_WITH_VERTEX_PROPERTY @@ -183,12 +191,23 @@ const void* grin_get_vertex_property_value(GRIN_GRAPH g, GRIN_VERTEX v, #if defined(GRIN_WITH_EDGE_PROPERTY) && \ defined(GRIN_TRAIT_PROPERTY_VALUE_OF_FLOAT_ARRAY) -void grin_destroy_edge_property_value_of_float_array(GRIN_GRAPH, const float*, - size_t); +void grin_destroy_edge_property_value_of_float_array(GRIN_GRAPH g, + const float* value, + size_t length) { + return; +} -const float* grin_get_edge_property_value_of_float_array(GRIN_GRAPH, GRIN_EDGE, - GRIN_EDGE_PROPERTY, - size_t*); +const float* grin_get_edge_property_value_of_float_array(GRIN_GRAPH g, + GRIN_EDGE e, + GRIN_EDGE_PROPERTY ep, + size_t* length) { + __grin_check_edge_property(e, ep, NULL); + auto _g = static_cast(g); + auto& property = _g->GetEdgeProperty(ep); + auto& _e = _g->GetEdge(e); + *length = _e.GetProperty&>(property.name_).size(); + return _e.GetProperty&>(property.name_).data(); +} #endif #ifdef GRIN_WITH_EDGE_PROPERTY diff --git a/demo_storage/storage/storage.cc b/demo_storage/storage/storage.cc index b8f7185..f9f16de 100644 --- a/demo_storage/storage/storage.cc +++ b/demo_storage/storage/storage.cc @@ -132,9 +132,11 @@ Graph* DemoStorage::load_modern_graph(const std::string& name, Property vp_0_0("id", GRIN_DATATYPE::Int64, true); Property vp_0_1("name", GRIN_DATATYPE::String, false); Property vp_0_2("age", GRIN_DATATYPE::Int64, false); + Property vp_0_3("float_data", GRIN_DATATYPE::FloatArray, false); graph->AddVertexProperty("person", vp_0_0); graph->AddVertexProperty("person", vp_0_1); graph->AddVertexProperty("person", vp_0_2); + graph->AddVertexProperty("person", vp_0_3); Property vp_1_0("id", GRIN_DATATYPE::Int64, true); Property vp_1_1("name", GRIN_DATATYPE::String, false); Property vp_1_2("lang", GRIN_DATATYPE::String, false); @@ -154,12 +156,14 @@ Graph* DemoStorage::load_modern_graph(const std::string& name, std::vector v_1_id = {3, 5}; std::vector v_1_name = {"lop", "ripple"}; std::vector v_1_lang = {"java", "java"}; + std::vector float_array_data = {3.3, 4.4, 5.5}; for (int64_t i = 0; i < 4; i++) { Vertex v(0, GRIN_DATATYPE::Int64, v_0_id[i], i); v.SetVData(GRIN_DATATYPE::Int64, v_0_id[i]); v.AddProperty("id", v_0_id[i]); v.AddProperty("name", v_0_name[i]); v.AddProperty("age", v_0_age[i]); + v.AddProperty("float_data", float_array_data); v.AddLabel("person_label"); if (i % 2 == 0) v.AddLabel("v_label_0"); diff --git a/demo_storage/test/test_property_value.cc b/demo_storage/test/test_property_value.cc index 02300ad..be403ff 100644 --- a/demo_storage/test/test_property_value.cc +++ b/demo_storage/test/test_property_value.cc @@ -191,6 +191,32 @@ void test_property_vertex(GRIN_GRAPH graph) { grin_destroy_vertex_property_value_of_string(graph, value2); } + // check value from row and from property (float array) + if (data_type == GRIN_DATATYPE::FloatArray) { + size_t length1, length2; + auto value1 = + grin_get_float_array_from_row(graph, r, property_id, &length1); + auto value2 = grin_get_vertex_property_value_of_float_array( + graph, vertex, property, &length2); + ASSERT(grin_get_last_error_code() == NO_ERROR); + ASSERT(length1 == length2); + ASSERT(length1 == 3); + + // check values + for (size_t i = 0; i < length1; i++) { + ASSERT(value1[i] == value2[i]); + std::cout << "value of property \"" << name + << "\" for vertex 0 of vertex type " << i << ": " + << value1[i] << std::endl; + } + + // destroy + grin_destroy_vertex_property_value_of_float_array(graph, value2, + length2); + grin_destroy_vertex_property_value_of_float_array(graph, value1, + length1); + } + // check getting value of invalid property auto invalid_value = grin_get_vertex_property_value( graph, vertex, GRIN_NULL_VERTEX_PROPERTY); @@ -263,7 +289,7 @@ void test_property_edge(GRIN_GRAPH graph) { auto value = grin_get_edge_property_value(graph, edge, property); ASSERT(grin_get_last_error_code() == NO_ERROR); - // check value from row and from property (int64) + // check value from row and from property (double) if (data_type == GRIN_DATATYPE::Double) { auto value1 = grin_get_double_from_row(graph, r, property_id); auto value2 =