Import upstream version 0.2.2+git20190529.1.ca1bf4b
Debian Janitor
6 months ago
0 | ############################################################################### | |
1 | # Set default behavior to automatically normalize line endings. | |
2 | ############################################################################### | |
3 | * text=auto | |
4 | ||
5 | ############################################################################### | |
6 | # Set default behavior for command prompt diff. | |
7 | # | |
8 | # This is need for earlier builds of msysgit that does not have it on by | |
9 | # default for csharp files. | |
10 | # Note: This is only used by command line | |
11 | ############################################################################### | |
12 | #*.cs diff=csharp | |
13 | ||
14 | ############################################################################### | |
15 | # Set the merge driver for project and solution files | |
16 | # | |
17 | # Merging from the command prompt will add diff markers to the files if there | |
18 | # are conflicts (Merging from VS is not affected by the settings below, in VS | |
19 | # the diff markers are never inserted). Diff markers may cause the following | |
20 | # file extensions to fail to load in VS. An alternative would be to treat | |
21 | # these files as binary and thus will always conflict and require user | |
22 | # intervention with every merge. To do so, just uncomment the entries below | |
23 | ############################################################################### | |
24 | #*.sln merge=binary | |
25 | #*.csproj merge=binary | |
26 | #*.vbproj merge=binary | |
27 | #*.vcxproj merge=binary | |
28 | #*.vcproj merge=binary | |
29 | #*.dbproj merge=binary | |
30 | #*.fsproj merge=binary | |
31 | #*.lsproj merge=binary | |
32 | #*.wixproj merge=binary | |
33 | #*.modelproj merge=binary | |
34 | #*.sqlproj merge=binary | |
35 | #*.wwaproj merge=binary | |
36 | ||
37 | ############################################################################### | |
38 | # behavior for image files | |
39 | # | |
40 | # image files are treated as binary by default. | |
41 | ############################################################################### | |
42 | #*.jpg binary | |
43 | #*.png binary | |
44 | #*.gif binary | |
45 | ||
46 | ############################################################################### | |
47 | # diff behavior for common document formats | |
48 | # | |
49 | # Convert binary document formats to text before diffing them. This feature | |
50 | # is only available from the command line. Turn it on by uncommenting the | |
51 | # entries below. | |
52 | ############################################################################### | |
53 | #*.doc diff=astextplain | |
54 | #*.DOC diff=astextplain | |
55 | #*.docx diff=astextplain | |
56 | #*.DOCX diff=astextplain | |
57 | #*.dot diff=astextplain | |
58 | #*.DOT diff=astextplain | |
59 | #*.pdf diff=astextplain | |
60 | #*.PDF diff=astextplain | |
61 | #*.rtf diff=astextplain | |
62 | #*.RTF diff=astextplain |
0 | *.o | |
1 | *.so | |
2 | *.a | |
3 | *.dll | |
4 | *.DLL | |
5 | test | |
6 | testmain | |
7 | VisualStudio/*.user | |
8 | VisualStudio/Debug/ | |
9 | VisualStudio/Release/ | |
10 | *.opensdf | |
11 | *.sdf | |
12 | *.suo | |
13 | bin/ | |
14 | libs/ | |
15 | gen/ | |
16 | obj/ | |
17 | *.apk | |
18 | *.ap_ | |
19 | *.dex | |
20 | *.class | |
21 | local.properties | |
22 | *.pydevproject | |
23 | .project | |
24 | .metadata | |
25 | bin/** | |
26 | tmp/** | |
27 | tmp/**/* | |
28 | *.tmp | |
29 | *.bak | |
30 | *.swp | |
31 | *~.nib | |
32 | local.properties | |
33 | .classpath | |
34 | .settings/ | |
35 | .loadpath | |
36 | .externalToolBuilders/ | |
37 | *.launch | |
38 | .cproject | |
39 | .buildpath |
0 | sudo: required | |
1 | language: cpp | |
2 | dist: trusty | |
3 | ||
4 | matrix: | |
5 | include: | |
6 | ||
7 | - os: linux | |
8 | addons: | |
9 | apt: | |
10 | sources: | |
11 | - ubuntu-toolchain-r-test | |
12 | packages: | |
13 | - g++-8 | |
14 | env: | |
15 | - MATRIX_EVAL="CC=gcc-8 && CXX=g++-8" | |
16 | ||
17 | - os: osx | |
18 | osx_image: xcode9.2 | |
19 | compiler: clang | |
20 | ||
21 | before_install: | |
22 | # Make sure we set correct env for platform | |
23 | - eval "$(MATRIX_EVAL)" | |
24 | ||
25 | # Workaround for Travis CI macOS bug (https://github.com/travis-ci/travis-ci/issues/6307) | |
26 | # See https://github.com/searchivarius/nmslib/pull/259 | |
27 | - | | |
28 | if [ "${TRAVIS_OS_NAME}" == "osx" ]; then | |
29 | command curl -sSL https://rvm.io/mpapis.asc | gpg --import -; | |
30 | rvm get head || true | |
31 | fi | |
32 | ||
33 | script: | |
34 | - export CHECKOUT_PATH=`pwd`; | |
35 | - echo "ROOT_PATH= $ROOT_PATH" | |
36 | - echo "CHECKOUT_PATH= $CHECKOUT_PATH" | |
37 | ||
38 | ####################################################################################### | |
39 | # Install a recent CMake (unless already installed on OS X) | |
40 | ####################################################################################### | |
41 | - | | |
42 | if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then | |
43 | CMAKE_URL="http://www.cmake.org/files/v3.10/cmake-3.10.2-Linux-x86_64.tar.gz" | |
44 | mkdir cmake && travis_retry wget --no-check-certificate --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake | |
45 | export PATH=${DEPS_DIR}/cmake/bin:${PATH} | |
46 | else | |
47 | brew upgrade cmake || echo "suppress failures in order to ignore warnings" | |
48 | brew link --overwrite cmake | |
49 | fi | |
50 | - cmake --version | |
51 | ||
52 | - | | |
53 | if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then | |
54 | sudo apt-get install uuid-dev | |
55 | fi | |
56 | ####################################################################################### | |
57 | # Build the library | |
58 | ####################################################################################### | |
59 | - | | |
60 | cd "${CHECKOUT_PATH}" | |
61 | mkdir build | |
62 | cd build | |
63 | cmake .. -DCMAKE_BUILD_TYPE="Debug" | |
64 | sudo make install | |
65 | ####################################################################################### | |
66 | # Run the tests | |
67 | ####################################################################################### | |
68 | - ./crossguid-test |
0 | cmake_minimum_required(VERSION 3.5.1) | |
1 | project(CrossGuid VERSION 0.2.3) | |
2 | ||
3 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake") | |
4 | ||
5 | option(CROSSGUID_TESTS "Build test runner" ON) | |
6 | ||
7 | set(CMAKE_CXX_STANDARD 17) | |
8 | set(CMAKE_CXX_EXTENSIONS OFF) | |
9 | set(CMAKE_DEBUG_POSTFIX "-dgb") | |
10 | ||
11 | # Set the build type if not set | |
12 | if(NOT CMAKE_BUILD_TYPE) | |
13 | set(CMAKE_BUILD_TYPE "Release") | |
14 | endif() | |
15 | ||
16 | add_library(crossguid ${CMAKE_CURRENT_SOURCE_DIR}/src/guid.cpp) | |
17 | set_property(TARGET crossguid PROPERTY POSITION_INDEPENDENT_CODE ON) | |
18 | target_include_directories(crossguid PUBLIC | |
19 | $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> | |
20 | $<INSTALL_INTERFACE:include>) | |
21 | ||
22 | if(WIN32) | |
23 | target_compile_definitions(crossguid PRIVATE GUID_WINDOWS) | |
24 | elseif(APPLE) | |
25 | find_library(CFLIB CoreFoundation) | |
26 | target_link_libraries(crossguid ${CFLIB}) | |
27 | target_compile_definitions(crossguid PRIVATE GUID_CFUUID) | |
28 | elseif(ANDROID) | |
29 | # GUID_ANDROID is used in the headers, so make PUBLIC | |
30 | target_compile_definitions(crossguid PUBLIC GUID_ANDROID) | |
31 | else() | |
32 | find_package(Libuuid REQUIRED) | |
33 | if (NOT LIBUUID_FOUND) | |
34 | message(FATAL_ERROR | |
35 | "You might need to run 'sudo apt-get install uuid-dev' or similar") | |
36 | endif() | |
37 | target_include_directories(crossguid PRIVATE ${LIBUUID_INCLUDE_DIR}) | |
38 | target_link_libraries(crossguid ${LIBUUID_LIBRARY}) | |
39 | target_compile_definitions(crossguid PRIVATE GUID_LIBUUID) | |
40 | endif() | |
41 | ||
42 | if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") | |
43 | set(WARNINGS "-Werror" "-Wall") | |
44 | elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") | |
45 | set(WARNINGS "-Werror" "-Wall") | |
46 | elseif(MSVC) | |
47 | set(WARNINGS "/WX" "/W4") | |
48 | endif() | |
49 | target_compile_options(crossguid PRIVATE ${WARNINGS}) | |
50 | ||
51 | set_target_properties(crossguid | |
52 | PROPERTIES | |
53 | VERSION ${PROJECT_VERSION} | |
54 | SOVERSION ${PROJECT_VERSION_MAJOR} | |
55 | DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) | |
56 | ||
57 | if (${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) | |
58 | include(GNUInstallDirs) | |
59 | ||
60 | set(CROSSGUID_INC_INSTALL_DIR "${CMAKE_INSTALL_INCLUDEDIR}") | |
61 | set(CROSSGUID_RUNTIME_INSTALL_DIR "${CMAKE_INSTALL_BINDIR}") | |
62 | set(CROSSGUID_LIBRARY_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}") | |
63 | set(CROSSGUID_ARCHIVE_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}") | |
64 | set(CROSSGUID_FRAMEWORK_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}") | |
65 | ||
66 | set(CROSSGUID_CMAKE_CONFIG_INSTALL_DIR "${CMAKE_INSTALL_DATADIR}/crossguid/cmake") | |
67 | set(CROSSGUID_ADDITIONAL_FILES_INSTALL_DIR "${CMAKE_INSTALL_DATADIR}/crossguid") | |
68 | ||
69 | # Install target | |
70 | install(TARGETS crossguid EXPORT crossguidTargets | |
71 | RUNTIME DESTINATION ${CROSSGUID_RUNTIME_INSTALL_DIR} | |
72 | LIBRARY DESTINATION ${CROSSGUID_LIBRARY_INSTALL_DIR} | |
73 | ARCHIVE DESTINATION ${CROSSGUID_ARCHIVE_INSTALL_DIR} | |
74 | FRAMEWORK DESTINATION ${CROSSGUID_FRAMEWORK_INSTALL_DIR}) | |
75 | ||
76 | # Install headers | |
77 | install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/" | |
78 | DESTINATION ${CROSSGUID_INC_INSTALL_DIR}) | |
79 | ||
80 | # Make cmake config files for all targets | |
81 | install(EXPORT crossguidTargets | |
82 | DESTINATION ${CROSSGUID_CMAKE_CONFIG_INSTALL_DIR} | |
83 | FILE crossguid-config.cmake) | |
84 | ||
85 | # Install readme and license | |
86 | install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE" "${CMAKE_CURRENT_SOURCE_DIR}/README.md" | |
87 | DESTINATION ${CROSSGUID_ADDITIONAL_FILES_INSTALL_DIR}) | |
88 | ||
89 | configure_file(crossguid.pc.in ${PROJECT_BINARY_DIR}/crossguid.pc @ONLY) | |
90 | install(FILES ${PROJECT_BINARY_DIR}/crossguid.pc DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}/pkgconfig) | |
91 | endif() | |
92 | ||
93 | if (CROSSGUID_TESTS) | |
94 | add_executable(crossguid-test test/TestMain.cpp test/Test.cpp) | |
95 | target_link_libraries(crossguid-test crossguid) | |
96 | endif() |
0 | # CrossGuid | |
0 | # CrossGuid [](https://travis-ci.org/graeme-hill/crossguid) | |
1 | 1 | |
2 | 2 | CrossGuid is a minimal, cross platform, C++ GUID library. It uses the best |
3 | native GUID/UUID generator on the given platform and had a generic class for | |
4 | parsing, stringifying, and comparing IDs. The intention is that anyone who | |
5 | uses this code can simply copy `guid.h` and `guid.cpp` into their project and | |
6 | define one of the following preprocessor flags to control the implementation: | |
7 | ||
8 | * `GUID_LIBUUID` - Uses `libuuid` which is normally used on linux but possibly | |
9 | usable elsewhere as well. | |
10 | * `GUID_CFUUID` - Uses `CFCreateUUID` from Apple's `CoreFoundation` framework. | |
11 | This works on both Mac OSX and iOS. | |
12 | * `GUID_WINDOWS` - Uses the built in `CoCreateGuid` function in Windows. | |
13 | * `GUID_ANDROID` - Uses JNI to invoke Java functions from Android SDK. | |
14 | ||
15 | I recommend taking the time to actually look at the `guid.h` and `guid.cpp` so | |
16 | that you can see how simple they are. It should be pretty trivial to modify | |
17 | the code to match your naming conventions or drop it into a namespace so that it | |
18 | fits in nicely with your code base. | |
3 | native GUID/UUID generator on the given platform and has a generic class for | |
4 | parsing, stringifying, and comparing IDs. The guid generation technique is | |
5 | determined by your platform: | |
6 | ||
7 | ## Linux | |
8 | ||
9 | On linux you can use `libuuid` which is pretty standard. On distros like Ubuntu | |
10 | it is available by default but to use it you need the header files so you have | |
11 | to do: | |
12 | ||
13 | sudo apt-get install uuid-dev | |
14 | ||
15 | ## Mac/iOS | |
16 | ||
17 | On Mac or iOS you can use `CFUUIDCreate` from `CoreFoundation`. Since it's a | |
18 | plain C function you don't even need to compile as Objective-C++. | |
19 | ||
20 | ## Windows | |
21 | ||
22 | On Windows we just use the the built-in function `CoCreateGuid`. CMake can | |
23 | generate a Visual Studio project if that's your thing. | |
24 | ||
25 | ## Android | |
26 | ||
27 | The Android version uses a handle to a `JNIEnv` object to invoke the | |
28 | `randomUUID()` function on `java.util.UUID` from C++. The Android specific code | |
29 | is all in the `android/` subdirectory. If you have an emulator already running, | |
30 | then you can run the `android.sh` script in the root directory. It has the | |
31 | following requirements: | |
32 | ||
33 | - Android emulator is already running (or you have physical device connected). | |
34 | - You're using bash. | |
35 | - adb is in your path. | |
36 | - You have an Android sdk setup including `ANDROID_HOME` environment variable. | |
37 | ||
38 | ## Versions | |
39 | ||
40 | This is version 0.2 of CrossGuid. If you all already using CrossGuid and your code | |
41 | uses `GuidGenerator` then you are using version 0.1. Differences in version 0.2: | |
42 | ||
43 | - Put everything inside the namespace `xg` instead of using the global | |
44 | namespace. | |
45 | - Removed `GuidGenerator` class and replaced with the free function | |
46 | `xg::newGuid`. This is the way I originally wanted it to work but since Android | |
47 | is a special snowflake requiring state (`JNIEnv *`) I introduced the | |
48 | `GuidGenerator` class specifically so that there would be somewhere to store | |
49 | the `JNIEnv *` when running on Android. However, this basically meant | |
50 | complicating the library for the sake of one platform. In version 0.2 the goal is | |
51 | to design for the normal platforms and let Android be weird. In Android you just | |
52 | need to run `xg::initJni(JNIEnv *)` before you create any guids. The `JNIEnv *` | |
53 | is just stored as a global variable. | |
54 | - Added CMake build system. Instead of different scripts for each platform you | |
55 | can just run cmake and it should handle each platform (except Android which | |
56 | again is special). | |
57 | - Actual guid bytes are stored in `std::array<unsigned char, 16>` instead of | |
58 | `std::vector<unsigned char>`. | |
59 | - More error checking (like if you try to create a guid with invalid number of | |
60 | bytes). | |
61 | ||
62 | If you're happily using version 0.1 then there's not really any reason to | |
63 | change. | |
64 | ||
65 | ## Compiling | |
66 | ||
67 | Just do the normal cmake thing: | |
68 | ||
69 | ``` | |
70 | mkdir build | |
71 | cd build | |
72 | cmake .. | |
73 | make install | |
74 | ``` | |
75 | ||
76 | ## Running tests | |
77 | ||
78 | After compiling as described above you should get two files: `libcrossguid.a` (the | |
79 | static library) and `crossguid-test` (the test runner). So to run the tests just do: | |
80 | ||
81 | ``` | |
82 | ./crossguid-test | |
83 | ``` | |
19 | 84 | |
20 | 85 | ## Basic usage |
21 | 86 | |
22 | ### Tests | |
23 | ||
24 | The tests are a simple way to figure out how the library works. There is a file | |
25 | in the root of the repository called `test.cpp` that runs a simple set of tests | |
26 | and outputs a few guid strings for a sanity check. This file does not have a | |
27 | `main()` function entry point there, it is intended to be called from somewhere | |
28 | else, and it takes a `GuidGenerator` as input. All platforms except for Android | |
29 | use `testmain.cpp` to construct a `GuidGenerator` and run the tests. In Android | |
30 | there is a special file called `android/jni/jnitest.cpp` which invokes the | |
31 | tests. | |
32 | ||
33 | ### Creating a guid generator | |
34 | ||
35 | Creation of a guid generator is not exactly the same in every platform, but | |
36 | this is an intentional feature. In Android the guid generation function has to | |
37 | have access to a `JNIEnv` handle, but that handle is not necessarily the same | |
38 | all the time. Therefore, there is a `GuidGenerator` class whose construction is | |
39 | different depending on the platform, but client code can pass around a | |
40 | `GuidGenerator` object and then use it the same on every platform. On every | |
41 | platform except Android, you can create a guid generator like this: | |
42 | ||
43 | GuidGenerator generator; | |
44 | ||
45 | But on Android you need to pass a `JNIEnv *`: | |
46 | ||
47 | GuidGenerator generator(env); | |
48 | ||
49 | 87 | ### Creating guids |
50 | 88 | |
51 | On every platform guid creation is the same: | |
52 | ||
53 | void doGuidStuff(GuidGenerator generator) | |
54 | { | |
55 | auto myGuid = generator.newGuid(); | |
56 | } | |
89 | Create a new random guid: | |
90 | ||
91 | ```cpp | |
92 | #include <crossguid/guid.hpp> | |
93 | ... | |
94 | auto g = xg::newGuid(); | |
95 | ``` | |
96 | ||
97 | **NOTE:** On Android you need to call `xg::initJni(JNIEnv *)` first so that it | |
98 | is possible for `xg::newGuid()` to call back into java libraries. `initJni` | |
99 | only needs to be called once when the process starts. | |
100 | ||
101 | Create a new zero guid: | |
102 | ||
103 | ```cpp | |
104 | xg::Guid g; | |
105 | ``` | |
106 | ||
107 | Create from a string: | |
108 | ||
109 | ```cpp | |
110 | xg::Guid g("c405c66c-ccbb-4ffd-9b62-c286c0fd7a3b"); | |
111 | ``` | |
112 | ||
113 | ### Checking validity | |
114 | ||
115 | If you have some string value and you need to check whether it is a valid guid | |
116 | then you can simply attempt to construct the guid: | |
117 | ||
118 | ```cpp | |
119 | xg::Guid g("bad-guid-string"); | |
120 | if (!g.isValid()) | |
121 | { | |
122 | // do stuff | |
123 | } | |
124 | ``` | |
125 | ||
126 | If the guid string is not valid then all bytes are set to zero and `isValid()` | |
127 | returns `false`. | |
57 | 128 | |
58 | 129 | ### Converting guid to string |
59 | 130 | |
64 | 135 | utilize strings because the `<<` operator is overloaded. To print a guid to |
65 | 136 | `std::cout`: |
66 | 137 | |
67 | ||
68 | void doGuidStuff(GuidGenerator generator) | |
69 | { | |
70 | auto myGuid = generator.newGuid(); | |
71 | std::cout << "Here is a guid: " << myGuid << std::endl; | |
72 | } | |
138 | ```cpp | |
139 | void doGuidStuff() | |
140 | { | |
141 | auto myGuid = xg::newGuid(); | |
142 | std::cout << "Here is a guid: " << myGuid << std::endl; | |
143 | } | |
144 | ``` | |
73 | 145 | |
74 | 146 | Or to store a guid in a `std::string`: |
75 | 147 | |
76 | void doGuidStuff(GuidGenerator generator) | |
77 | { | |
78 | auto myGuid = generator.newGuid(); | |
79 | std::stringstring stream; | |
80 | stream << myGuid; | |
81 | auto guidString = stream.str(); | |
82 | } | |
83 | ||
84 | ### Parsing a string into a guid | |
85 | ||
86 | There is a constructor that can be used to create a guid from a string without | |
87 | needing any reference to a `GuidGenerator`: | |
88 | ||
89 | void doGuidStuff() | |
90 | { | |
91 | Guid guid("e63e03a8-f3e5-4e0f-99bb-a3fc402d4fc8"); | |
92 | } | |
148 | ```cpp | |
149 | void doGuidStuff() | |
150 | { | |
151 | auto myGuid = xg::newGuid(); | |
152 | std::stringstream stream; | |
153 | stream << myGuid; | |
154 | auto guidString = stream.str(); | |
155 | } | |
156 | ``` | |
157 | ||
158 | There is also a `str()` function that returns a `std::string`: | |
159 | ||
160 | ```cpp | |
161 | std::string guidStr = xg::newGuid().str(); | |
162 | ``` | |
93 | 163 | |
94 | 164 | ### Creating a guid from raw bytes |
95 | 165 | |
97 | 167 | internally to construct a `Guid` object from the raw data given by the system's |
98 | 168 | built-in guid generation function. There are two key constructors for this: |
99 | 169 | |
100 | Guid(const vector<unsigned char> &bytes); | |
170 | ```cpp | |
171 | Guid(std::array<unsigned char, 16> &bytes); | |
172 | ``` | |
101 | 173 | |
102 | 174 | and |
103 | 175 | |
104 | Guid(const unsigned char *bytes); | |
105 | ||
106 | In both cases the constructor expects to receive exactly 16 bytes. | |
176 | ```cpp | |
177 | Guid(const unsigned char * bytes); | |
178 | ``` | |
179 | ||
180 | When possible prefer the `std::array` constructor because it is safer. If you | |
181 | pass in an incorrectly sized C array then bad things will happen. | |
107 | 182 | |
108 | 183 | ### Comparing guids |
109 | 184 | |
110 | 185 | `==` and `!=` are implemented, so the following works as expected: |
111 | 186 | |
112 | void doGuidStuff(GuidGenerator generator) | |
113 | { | |
114 | auto guid1 = generator.newGuid(); | |
115 | auto guid2 = generator.newGuid(); | |
116 | ||
117 | auto guidsAreEqual = guid1 == guid2; | |
118 | auto guidsAreNotEqual = guid1 != guid2; | |
119 | } | |
120 | ||
121 | ## Linux | |
122 | ||
123 | **The Linux version uses the proprocessor flag `GUID_LIBUUID`** | |
124 | ||
125 | On linux you can use libuuid which is pretty standard. On distros like Ubuntu | |
126 | it is available by default but to use it you need the header files so you have | |
127 | to do: | |
128 | ||
129 | sudo apt-get install uuid-dev | |
130 | ||
131 | Then you can compile and run tests with: | |
132 | ||
133 | ./linux.sh | |
134 | ||
135 | ## Mac/iOS | |
136 | ||
137 | **The Mac and iOS versions use the preprocessor flag `GUID_CFUUID`** | |
138 | ||
139 | On Mac or iOS you can use `CFUUIDCreate` from `CoreFoundation`. Since it's a | |
140 | plain C function you don't even need to compile as Objective-C++. If you have | |
141 | the command line tools that come with Xcode installed, then you can compile and | |
142 | run the tests like this: | |
143 | ||
144 | ./mac.sh | |
145 | ||
146 | ## Windows | |
147 | ||
148 | **The Windows version uses the preprocessor flag `GUID_WINDOWS`** | |
149 | ||
150 | On Windows we just the the built-in function `CoCreateGuid`. There is a Visual | |
151 | Studio 2013 solution in the `VisualStudio` directory which you can use to | |
152 | compile and run tests. | |
153 | ||
154 | ## Android | |
155 | ||
156 | **The Android version uses the preprocessor flag `GUID_ANDROID`** | |
157 | ||
158 | The Android version uses a handle to a `JNIEnv` object to invoke the | |
159 | `randomUUID()` function on `java.util.UUID` from C++. The Android specific code | |
160 | is all in the `android/` subdirectory. If you have an emulator already running, | |
161 | then you can run the `android.sh` script in the root directory. It has the | |
162 | following requirements: | |
163 | ||
164 | * Android emulator is already running (or you have physical device connected). | |
165 | * You're using bash. | |
166 | * adb is in your path. | |
167 | * ndk-build and other ndk cross-compile tools are in your path. | |
168 | * You have a jdk setup including `JAVA_HOME` environment variable. | |
187 | ```cpp | |
188 | void doGuidStuff() | |
189 | { | |
190 | auto guid1 = xg::newGuid(); | |
191 | auto guid2 = xg::newGuid(); | |
192 | ||
193 | auto guidsAreEqual = guid1 == guid2; | |
194 | auto guidsAreNotEqual = guid1 != guid2; | |
195 | } | |
196 | ``` | |
197 | ||
198 | ### Hashing guids | |
199 | ||
200 | Guids can be used directly in containers requireing `std::hash` such as `std::map,`std::unordered_map` etc. | |
169 | 201 | |
170 | 202 | ## License |
171 | 203 |
0 | <?xml version="1.0" encoding="utf-8"?> | |
1 | <Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |
2 | <ItemGroup Label="ProjectConfigurations"> | |
3 | <ProjectConfiguration Include="Debug|Win32"> | |
4 | <Configuration>Debug</Configuration> | |
5 | <Platform>Win32</Platform> | |
6 | </ProjectConfiguration> | |
7 | <ProjectConfiguration Include="Release|Win32"> | |
8 | <Configuration>Release</Configuration> | |
9 | <Platform>Win32</Platform> | |
10 | </ProjectConfiguration> | |
11 | </ItemGroup> | |
12 | <PropertyGroup Label="Globals"> | |
13 | <ProjectGuid>{C8233271-F319-4531-AEF6-3BD6420B55CD}</ProjectGuid> | |
14 | <Keyword>Win32Proj</Keyword> | |
15 | <RootNamespace>CrossGuid</RootNamespace> | |
16 | <ProjectName>CrossGuid-Test</ProjectName> | |
17 | </PropertyGroup> | |
18 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> | |
19 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> | |
20 | <ConfigurationType>Application</ConfigurationType> | |
21 | <UseDebugLibraries>true</UseDebugLibraries> | |
22 | <PlatformToolset>v120</PlatformToolset> | |
23 | <CharacterSet>Unicode</CharacterSet> | |
24 | </PropertyGroup> | |
25 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> | |
26 | <ConfigurationType>Application</ConfigurationType> | |
27 | <UseDebugLibraries>false</UseDebugLibraries> | |
28 | <PlatformToolset>v120</PlatformToolset> | |
29 | <WholeProgramOptimization>true</WholeProgramOptimization> | |
30 | <CharacterSet>Unicode</CharacterSet> | |
31 | </PropertyGroup> | |
32 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> | |
33 | <ImportGroup Label="ExtensionSettings"> | |
34 | </ImportGroup> | |
35 | <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> | |
36 | <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> | |
37 | </ImportGroup> | |
38 | <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> | |
39 | <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> | |
40 | </ImportGroup> | |
41 | <PropertyGroup Label="UserMacros" /> | |
42 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> | |
43 | <LinkIncremental>true</LinkIncremental> | |
44 | </PropertyGroup> | |
45 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> | |
46 | <LinkIncremental>false</LinkIncremental> | |
47 | </PropertyGroup> | |
48 | <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> | |
49 | <ClCompile> | |
50 | <PrecompiledHeader> | |
51 | </PrecompiledHeader> | |
52 | <WarningLevel>Level3</WarningLevel> | |
53 | <Optimization>Disabled</Optimization> | |
54 | <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;GUID_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions> | |
55 | </ClCompile> | |
56 | <Link> | |
57 | <SubSystem>Console</SubSystem> | |
58 | <GenerateDebugInformation>true</GenerateDebugInformation> | |
59 | <AdditionalDependencies>CrossGuidd.lib;%(AdditionalDependencies)</AdditionalDependencies> | |
60 | <AdditionalLibraryDirectories>$(SolutionDir)$(Configuration)</AdditionalLibraryDirectories> | |
61 | </Link> | |
62 | </ItemDefinitionGroup> | |
63 | <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> | |
64 | <ClCompile> | |
65 | <WarningLevel>Level3</WarningLevel> | |
66 | <PrecompiledHeader> | |
67 | </PrecompiledHeader> | |
68 | <Optimization>MaxSpeed</Optimization> | |
69 | <FunctionLevelLinking>true</FunctionLevelLinking> | |
70 | <IntrinsicFunctions>true</IntrinsicFunctions> | |
71 | <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;GUID_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions> | |
72 | </ClCompile> | |
73 | <Link> | |
74 | <SubSystem>Console</SubSystem> | |
75 | <GenerateDebugInformation>true</GenerateDebugInformation> | |
76 | <EnableCOMDATFolding>true</EnableCOMDATFolding> | |
77 | <OptimizeReferences>true</OptimizeReferences> | |
78 | <AdditionalDependencies>CrossGuid.lib;%(AdditionalDependencies)</AdditionalDependencies> | |
79 | <AdditionalLibraryDirectories>$(SolutionDir)$(Configuration)</AdditionalLibraryDirectories> | |
80 | </Link> | |
81 | </ItemDefinitionGroup> | |
82 | <ItemGroup> | |
83 | <ClInclude Include="..\test.h" /> | |
84 | </ItemGroup> | |
85 | <ItemGroup> | |
86 | <ClCompile Include="..\test.cpp" /> | |
87 | <ClCompile Include="..\testmain.cpp" /> | |
88 | </ItemGroup> | |
89 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> | |
90 | <ImportGroup Label="ExtensionTargets"> | |
91 | </ImportGroup> | |
92 | </Project>⏎ |
0 | <?xml version="1.0" encoding="utf-8"?> | |
1 | <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |
2 | <ItemGroup> | |
3 | <Filter Include="Source Files"> | |
4 | <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> | |
5 | <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> | |
6 | </Filter> | |
7 | <Filter Include="Header Files"> | |
8 | <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> | |
9 | <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions> | |
10 | </Filter> | |
11 | <Filter Include="Resource Files"> | |
12 | <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> | |
13 | <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> | |
14 | </Filter> | |
15 | </ItemGroup> | |
16 | <ItemGroup> | |
17 | <ClCompile Include="..\test.cpp"> | |
18 | <Filter>Source Files</Filter> | |
19 | </ClCompile> | |
20 | <ClCompile Include="..\testmain.cpp"> | |
21 | <Filter>Source Files</Filter> | |
22 | </ClCompile> | |
23 | </ItemGroup> | |
24 | <ItemGroup> | |
25 | <ClInclude Include="..\test.h"> | |
26 | <Filter>Header Files</Filter> | |
27 | </ClInclude> | |
28 | </ItemGroup> | |
29 | </Project>⏎ |
0 | | |
1 | Microsoft Visual Studio Solution File, Format Version 12.00 | |
2 | # Visual Studio Express 2013 for Windows Desktop | |
3 | VisualStudioVersion = 12.0.40629.0 | |
4 | MinimumVisualStudioVersion = 10.0.40219.1 | |
5 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CrossGuid-Test", "CrossGuid-Test.vcxproj", "{C8233271-F319-4531-AEF6-3BD6420B55CD}" | |
6 | ProjectSection(ProjectDependencies) = postProject | |
7 | {AF365E5F-E35D-40A6-958A-C7B6988C994D} = {AF365E5F-E35D-40A6-958A-C7B6988C994D} | |
8 | EndProjectSection | |
9 | EndProject | |
10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CrossGuid", "CrossGuid.vcxproj", "{AF365E5F-E35D-40A6-958A-C7B6988C994D}" | |
11 | EndProject | |
12 | Global | |
13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution | |
14 | Debug|Win32 = Debug|Win32 | |
15 | Release|Win32 = Release|Win32 | |
16 | EndGlobalSection | |
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution | |
18 | {C8233271-F319-4531-AEF6-3BD6420B55CD}.Debug|Win32.ActiveCfg = Debug|Win32 | |
19 | {C8233271-F319-4531-AEF6-3BD6420B55CD}.Debug|Win32.Build.0 = Debug|Win32 | |
20 | {C8233271-F319-4531-AEF6-3BD6420B55CD}.Release|Win32.ActiveCfg = Release|Win32 | |
21 | {C8233271-F319-4531-AEF6-3BD6420B55CD}.Release|Win32.Build.0 = Release|Win32 | |
22 | {AF365E5F-E35D-40A6-958A-C7B6988C994D}.Debug|Win32.ActiveCfg = Debug|Win32 | |
23 | {AF365E5F-E35D-40A6-958A-C7B6988C994D}.Debug|Win32.Build.0 = Debug|Win32 | |
24 | {AF365E5F-E35D-40A6-958A-C7B6988C994D}.Release|Win32.ActiveCfg = Release|Win32 | |
25 | {AF365E5F-E35D-40A6-958A-C7B6988C994D}.Release|Win32.Build.0 = Release|Win32 | |
26 | EndGlobalSection | |
27 | GlobalSection(SolutionProperties) = preSolution | |
28 | HideSolutionNode = FALSE | |
29 | EndGlobalSection | |
30 | EndGlobal |
0 | <?xml version="1.0" encoding="utf-8"?> | |
1 | <Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |
2 | <ItemGroup Label="ProjectConfigurations"> | |
3 | <ProjectConfiguration Include="Debug|Win32"> | |
4 | <Configuration>Debug</Configuration> | |
5 | <Platform>Win32</Platform> | |
6 | </ProjectConfiguration> | |
7 | <ProjectConfiguration Include="Release|Win32"> | |
8 | <Configuration>Release</Configuration> | |
9 | <Platform>Win32</Platform> | |
10 | </ProjectConfiguration> | |
11 | </ItemGroup> | |
12 | <ItemGroup> | |
13 | <ClCompile Include="..\guid.cpp" /> | |
14 | </ItemGroup> | |
15 | <ItemGroup> | |
16 | <ClInclude Include="..\guid.h" /> | |
17 | </ItemGroup> | |
18 | <PropertyGroup Label="Globals"> | |
19 | <ProjectGuid>{AF365E5F-E35D-40A6-958A-C7B6988C994D}</ProjectGuid> | |
20 | <RootNamespace>CrossGuid</RootNamespace> | |
21 | </PropertyGroup> | |
22 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> | |
23 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> | |
24 | <ConfigurationType>StaticLibrary</ConfigurationType> | |
25 | <UseDebugLibraries>true</UseDebugLibraries> | |
26 | <PlatformToolset>v120</PlatformToolset> | |
27 | <CharacterSet>Unicode</CharacterSet> | |
28 | </PropertyGroup> | |
29 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> | |
30 | <ConfigurationType>StaticLibrary</ConfigurationType> | |
31 | <UseDebugLibraries>false</UseDebugLibraries> | |
32 | <PlatformToolset>v120</PlatformToolset> | |
33 | <WholeProgramOptimization>true</WholeProgramOptimization> | |
34 | <CharacterSet>Unicode</CharacterSet> | |
35 | </PropertyGroup> | |
36 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> | |
37 | <ImportGroup Label="ExtensionSettings"> | |
38 | </ImportGroup> | |
39 | <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> | |
40 | <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> | |
41 | </ImportGroup> | |
42 | <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> | |
43 | <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> | |
44 | </ImportGroup> | |
45 | <PropertyGroup Label="UserMacros" /> | |
46 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> | |
47 | <TargetName>$(ProjectName)d</TargetName> | |
48 | </PropertyGroup> | |
49 | <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> | |
50 | <ClCompile> | |
51 | <WarningLevel>Level3</WarningLevel> | |
52 | <Optimization>Disabled</Optimization> | |
53 | <SDLCheck>false</SDLCheck> | |
54 | <PreprocessorDefinitions>_MBCS;GUID_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions> | |
55 | </ClCompile> | |
56 | <Link> | |
57 | <GenerateDebugInformation>true</GenerateDebugInformation> | |
58 | </Link> | |
59 | </ItemDefinitionGroup> | |
60 | <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> | |
61 | <ClCompile> | |
62 | <WarningLevel>Level3</WarningLevel> | |
63 | <Optimization>MaxSpeed</Optimization> | |
64 | <FunctionLevelLinking>true</FunctionLevelLinking> | |
65 | <IntrinsicFunctions>true</IntrinsicFunctions> | |
66 | <SDLCheck>true</SDLCheck> | |
67 | <PreprocessorDefinitions>_MBCS;GUID_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions> | |
68 | </ClCompile> | |
69 | <Link> | |
70 | <GenerateDebugInformation>true</GenerateDebugInformation> | |
71 | <EnableCOMDATFolding>true</EnableCOMDATFolding> | |
72 | <OptimizeReferences>true</OptimizeReferences> | |
73 | </Link> | |
74 | </ItemDefinitionGroup> | |
75 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> | |
76 | <ImportGroup Label="ExtensionTargets"> | |
77 | </ImportGroup> | |
78 | </Project>⏎ |
0 | <?xml version="1.0" encoding="utf-8"?> | |
1 | <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |
2 | <ItemGroup> | |
3 | <Filter Include="Source Files"> | |
4 | <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> | |
5 | <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> | |
6 | </Filter> | |
7 | <Filter Include="Header Files"> | |
8 | <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> | |
9 | <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions> | |
10 | </Filter> | |
11 | <Filter Include="Resource Files"> | |
12 | <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> | |
13 | <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> | |
14 | </Filter> | |
15 | </ItemGroup> | |
16 | <ItemGroup> | |
17 | <ClCompile Include="..\guid.cpp"> | |
18 | <Filter>Source Files</Filter> | |
19 | </ClCompile> | |
20 | </ItemGroup> | |
21 | <ItemGroup> | |
22 | <ClInclude Include="..\guid.h"> | |
23 | <Filter>Header Files</Filter> | |
24 | </ClInclude> | |
25 | </ItemGroup> | |
26 | </Project>⏎ |
0 | *.iml | |
1 | .gradle | |
2 | /local.properties | |
3 | /.idea/workspace.xml | |
4 | /.idea/libraries | |
5 | .DS_Store | |
6 | /build | |
7 | /captures | |
8 | .externalNativeBuild | |
9 | .idea |
0 | <?xml version="1.0" encoding="utf-8"?> | |
1 | <manifest xmlns:android="http://schemas.android.com/apk/res/android" | |
2 | package="ca.graemehill.crossguid.testapp" | |
3 | android:versionCode="1" | |
4 | android:versionName="1.0"> | |
5 | <application android:label="@string/app_name" android:icon="@drawable/ic_launcher"> | |
6 | <activity android:name="MainActivity" | |
7 | android:label="@string/app_name"> | |
8 | <intent-filter> | |
9 | <action android:name="android.intent.action.MAIN" /> | |
10 | <category android:name="android.intent.category.LAUNCHER" /> | |
11 | </intent-filter> | |
12 | </activity> | |
13 | </application> | |
14 | </manifest> |
0 | /build |
0 | cmake_minimum_required(VERSION 3.4.1) | |
1 | ||
2 | set(LIB_NAME crossguidtest) | |
3 | set(XG_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) | |
4 | set(XG_TEST_DIR ${XG_DIR}/test) | |
5 | ||
6 | add_library(${LIB_NAME} SHARED src/main/cpp/jnitest.cpp ${XG_TEST_DIR}/Test.cpp) | |
7 | ||
8 | target_include_directories(${LIB_NAME} PRIVATE | |
9 | ${XG_DIR} | |
10 | ${XG_TEST_DIR}) | |
11 | ||
12 | target_compile_definitions(${LIB_NAME} PRIVATE GUID_ANDROID) | |
13 | ||
14 | set(XG_TESTS OFF CACHE BOOL "disable tests") | |
15 | add_subdirectory(${XG_DIR} ${XG_DIR}/cmake_build) | |
16 | ||
17 | target_link_libraries(${LIB_NAME} xg)⏎ |
0 | apply plugin: 'com.android.application' | |
1 | ||
2 | android { | |
3 | compileSdkVersion 25 | |
4 | buildToolsVersion "26.0.0" | |
5 | defaultConfig { | |
6 | applicationId "ca.graemehill.crossguid.testapp" | |
7 | minSdkVersion 14 | |
8 | targetSdkVersion 25 | |
9 | versionCode 1 | |
10 | versionName "1.0" | |
11 | externalNativeBuild { | |
12 | cmake { | |
13 | cppFlags "-std=c++11 -frtti -fexceptions" | |
14 | arguments "-DANDROID_TOOLCHAIN=clang" | |
15 | } | |
16 | } | |
17 | } | |
18 | buildTypes { | |
19 | release { | |
20 | minifyEnabled false | |
21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' | |
22 | } | |
23 | } | |
24 | externalNativeBuild { | |
25 | cmake { | |
26 | path "CMakeLists.txt" | |
27 | } | |
28 | } | |
29 | } | |
30 | ||
31 | dependencies { | |
32 | implementation fileTree(dir: 'libs', include: ['*.jar']) | |
33 | androidTestImplementation('com.android.support.test.espresso:espresso-core:3.0.0', { | |
34 | exclude group: 'com.android.support', module: 'support-annotations' | |
35 | }) | |
36 | implementation 'com.android.support:appcompat-v7:25.4.0' | |
37 | testImplementation 'junit:junit:4.12' | |
38 | } |
0 | # Add project specific ProGuard rules here. | |
1 | # By default, the flags in this file are appended to flags specified | |
2 | # in /usr/local/Cellar/android-sdk/24.4.1_1/tools/proguard/proguard-android.txt | |
3 | # You can edit the include path and order by changing the proguardFiles | |
4 | # directive in build.gradle. | |
5 | # | |
6 | # For more details, see | |
7 | # http://developer.android.com/guide/developing/tools/proguard.html | |
8 | ||
9 | # Add any project specific keep options here: | |
10 | ||
11 | # If your project uses WebView with JS, uncomment the following | |
12 | # and specify the fully qualified class name to the JavaScript interface | |
13 | # class: | |
14 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { | |
15 | # public *; | |
16 | #} | |
17 | ||
18 | # Uncomment this to preserve the line number information for | |
19 | # debugging stack traces. | |
20 | #-keepattributes SourceFile,LineNumberTable | |
21 | ||
22 | # If you keep the line number information, uncomment this to | |
23 | # hide the original source file name. | |
24 | #-renamesourcefileattribute SourceFile |
0 | <manifest xmlns:android="http://schemas.android.com/apk/res/android" | |
1 | package="ca.graemehill.crossguid.testapp"> | |
2 | ||
3 | <application | |
4 | android:allowBackup="true" | |
5 | android:icon="@mipmap/ic_launcher" | |
6 | android:label="@string/app_name" | |
7 | android:roundIcon="@mipmap/ic_launcher_round" | |
8 | android:supportsRtl="true" | |
9 | android:theme="@style/AppTheme"> | |
10 | <activity android:name="MainActivity" | |
11 | android:label="@string/app_name"> | |
12 | <intent-filter> | |
13 | <action android:name="android.intent.action.MAIN" /> | |
14 | <category android:name="android.intent.category.LAUNCHER" /> | |
15 | </intent-filter> | |
16 | </activity> | |
17 | </application> | |
18 | </manifest> |
0 | #include <string> | |
1 | #include <sstream> | |
2 | #include <atomic> | |
3 | #include <iostream> | |
4 | #include <crossguid/guid.hpp | |
5 | #include <jni.h> | |
6 | ||
7 | #include "Test.hpp" | |
8 | ||
9 | JavaVM *&javaVM() { | |
10 | static JavaVM *jvm; | |
11 | return jvm; | |
12 | } | |
13 | ||
14 | extern "C" | |
15 | { | |
16 | ||
17 | JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void * /* reserved */) { | |
18 | javaVM() = jvm; | |
19 | return JNI_VERSION_1_6; | |
20 | } | |
21 | ||
22 | JNIEXPORT jstring JNICALL | |
23 | Java_ca_graemehill_crossguid_testapp_MainActivity_test( | |
24 | JNIEnv *env, jobject /*thiz*/) | |
25 | { | |
26 | std::stringstream resultStream; | |
27 | xg::initJni(env); | |
28 | test(resultStream); | |
29 | return env->NewStringUTF(resultStream.str().c_str()); | |
30 | } | |
31 | ||
32 | JNIEXPORT jstring JNICALL | |
33 | Java_ca_graemehill_crossguid_testapp_MainActivity_newGuid( | |
34 | JNIEnv *env, jobject /*thiz*/) { | |
35 | return env->NewStringUTF(xg::newGuid(env).str().c_str()); | |
36 | } | |
37 | ||
38 | JNIEXPORT jstring JNICALL | |
39 | Java_ca_graemehill_crossguid_testapp_MainActivity_createGuidFromNativeThread( | |
40 | JNIEnv *env, jobject /*thiz*/) { | |
41 | ||
42 | // there is no promise<> in armeabi of ndk | |
43 | // so ugly atomic_bool wait solution | |
44 | std::atomic_bool ready { false }; | |
45 | std::string guid; | |
46 | ||
47 | std::thread([&ready, &guid](){ | |
48 | JNIEnv *threadEnv; | |
49 | javaVM()->AttachCurrentThread(&threadEnv, NULL); | |
50 | guid = xg::newGuid(threadEnv); | |
51 | javaVM()->DetachCurrentThread(); | |
52 | ||
53 | ready = true; | |
54 | }).detach(); | |
55 | ||
56 | while (!ready); | |
57 | return env->NewStringUTF(guid.c_str()); | |
58 | } | |
59 | ||
60 | } |
0 | package ca.graemehill.crossguid.testapp; | |
1 | ||
2 | import android.app.Activity; | |
3 | import android.os.Bundle; | |
4 | import android.widget.TextView; | |
5 | ||
6 | import java.util.concurrent.CountDownLatch; | |
7 | ||
8 | public class MainActivity extends Activity { | |
9 | ||
10 | @Override | |
11 | public void onCreate(Bundle savedInstanceState) { | |
12 | super.onCreate(savedInstanceState); | |
13 | setContentView(R.layout.main); | |
14 | ||
15 | final TextView textView = (TextView)findViewById(R.id.mainTextView); | |
16 | textView.setText(test()); | |
17 | ||
18 | final TextView javaThreadView = (TextView)findViewById(R.id.javaThreadView); | |
19 | javaThreadView.setText(createGuidFromJavaThread()); | |
20 | ||
21 | final TextView nativeThreadView = (TextView)findViewById(R.id.nativeThreadView); | |
22 | nativeThreadView.setText(createGuidFromNativeThread()); | |
23 | } | |
24 | ||
25 | public native String test(); | |
26 | ||
27 | private static class StringCapture { | |
28 | private String value; | |
29 | ||
30 | public String getValue() { | |
31 | return value; | |
32 | } | |
33 | ||
34 | public void setValue(String value) { | |
35 | this.value = value; | |
36 | } | |
37 | } | |
38 | ||
39 | public String createGuidFromJavaThread() { | |
40 | final CountDownLatch created = new CountDownLatch(1); | |
41 | final StringCapture result = new StringCapture(); | |
42 | new Thread(new Runnable() { | |
43 | @Override | |
44 | public void run() { | |
45 | result.setValue(newGuid()); | |
46 | created.countDown(); | |
47 | } | |
48 | }).start(); | |
49 | try { | |
50 | created.await(); | |
51 | } catch (InterruptedException e) { | |
52 | return "Could not get value: " + e.getMessage(); | |
53 | } | |
54 | return result.getValue(); | |
55 | } | |
56 | ||
57 | public native String newGuid(); | |
58 | ||
59 | public native String createGuidFromNativeThread(); | |
60 | static { | |
61 | System.loadLibrary("crossguidtest"); | |
62 | } | |
63 | } |
0 | <?xml version="1.0" encoding="utf-8"?> | |
1 | <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
2 | android:orientation="vertical" | |
3 | android:layout_width="fill_parent" | |
4 | android:layout_height="fill_parent" | |
5 | > | |
6 | <TextView | |
7 | android:layout_width="match_parent" | |
8 | android:layout_height="wrap_content" | |
9 | android:text="@string/test_results_label" | |
10 | android:textStyle="bold"/> | |
11 | <TextView | |
12 | android:id="@+id/mainTextView" | |
13 | android:layout_width="match_parent" | |
14 | android:layout_height="wrap_content" /> | |
15 | <TextView | |
16 | android:layout_width="match_parent" | |
17 | android:layout_height="wrap_content" | |
18 | android:text="@string/java_thread_label" | |
19 | android:textStyle="bold"/> | |
20 | <TextView | |
21 | android:layout_width="match_parent" | |
22 | android:layout_height="wrap_content" | |
23 | android:id="@+id/javaThreadView"/> | |
24 | <TextView | |
25 | android:layout_width="match_parent" | |
26 | android:layout_height="wrap_content" | |
27 | android:text="@string/native_thread_label" | |
28 | android:textStyle="bold"/> | |
29 | <TextView | |
30 | android:layout_width="match_parent" | |
31 | android:layout_height="wrap_content" | |
32 | android:id="@+id/nativeThreadView"/> | |
33 | </LinearLayout> | |
34 |
Binary diff not shown
Binary diff not shown
Binary diff not shown
Binary diff not shown
Binary diff not shown
Binary diff not shown
Binary diff not shown
Binary diff not shown
Binary diff not shown
Binary diff not shown
0 | <?xml version="1.0" encoding="utf-8"?> | |
1 | <resources> | |
2 | <color name="colorPrimary">#3F51B5</color> | |
3 | <color name="colorPrimaryDark">#303F9F</color> | |
4 | <color name="colorAccent">#FF4081</color> | |
5 | </resources> |
0 | <resources> | |
1 | <string name="app_name">TestApp</string> | |
2 | <string name="native_thread_label">GUID created from Native Thread</string> | |
3 | <string name="java_thread_label">GUID created from Java Thread</string> | |
4 | <string name="test_results_label">Test results</string> | |
5 | </resources> |
0 | <resources> | |
1 | ||
2 | <!-- Base application theme. --> | |
3 | <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> | |
4 | <!-- Customize your theme here. --> | |
5 | <item name="colorPrimary">@color/colorPrimary</item> | |
6 | <item name="colorPrimaryDark">@color/colorPrimaryDark</item> | |
7 | <item name="colorAccent">@color/colorAccent</item> | |
8 | </style> | |
9 | ||
10 | </resources> |
0 | // Top-level build file where you can add configuration options common to all sub-projects/modules. | |
1 | ||
2 | buildscript { | |
3 | ||
4 | repositories { | |
5 | maven { url 'https://maven.google.com' } | |
6 | jcenter() | |
7 | } | |
8 | dependencies { | |
9 | classpath 'com.android.tools.build:gradle:3.0.0-alpha3' | |
10 | ||
11 | // NOTE: Do not place your application dependencies here; they belong | |
12 | // in the individual module build.gradle files | |
13 | } | |
14 | } | |
15 | ||
16 | allprojects { | |
17 | repositories { | |
18 | maven { url 'https://maven.google.com' } | |
19 | jcenter() | |
20 | } | |
21 | } | |
22 | ||
23 | task clean(type: Delete) { | |
24 | delete rootProject.buildDir | |
25 | } |
Binary diff not shown
0 | #Thu Aug 03 09:39:40 MSK 2017 | |
1 | distributionBase=GRADLE_USER_HOME | |
2 | distributionPath=wrapper/dists | |
3 | zipStoreBase=GRADLE_USER_HOME | |
4 | zipStorePath=wrapper/dists | |
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-milestone-1-all.zip |
0 | # Project-wide Gradle settings. | |
1 | ||
2 | # IDE (e.g. Android Studio) users: | |
3 | # Gradle settings configured through the IDE *will override* | |
4 | # any settings specified in this file. | |
5 | ||
6 | # For more details on how to configure your build environment visit | |
7 | # http://www.gradle.org/docs/current/userguide/build_environment.html | |
8 | ||
9 | # Specifies the JVM arguments used for the daemon process. | |
10 | # The setting is particularly useful for tweaking memory settings. | |
11 | org.gradle.jvmargs=-Xmx1536m | |
12 | ||
13 | # When configured, Gradle will run in incubating parallel mode. | |
14 | # This option should only be used with decoupled projects. More details, visit | |
15 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects | |
16 | # org.gradle.parallel=true | |
17 | android.enableAapt2=false |
0 | #!/usr/bin/env bash | |
1 | ||
2 | ############################################################################## | |
3 | ## | |
4 | ## Gradle start up script for UN*X | |
5 | ## | |
6 | ############################################################################## | |
7 | ||
8 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | |
9 | DEFAULT_JVM_OPTS="" | |
10 | LC_NUMERIC="en_US.UTF-8" | |
11 | ||
12 | APP_NAME="Gradle" | |
13 | APP_BASE_NAME=`basename "$0"` | |
14 | ||
15 | # Use the maximum available, or set MAX_FD != -1 to use that value. | |
16 | MAX_FD="maximum" | |
17 | ||
18 | warn ( ) { | |
19 | echo "$*" | |
20 | } | |
21 | ||
22 | die ( ) { | |
23 | echo | |
24 | echo "$*" | |
25 | echo | |
26 | exit 1 | |
27 | } | |
28 | ||
29 | # OS specific support (must be 'true' or 'false'). | |
30 | cygwin=false | |
31 | msys=false | |
32 | darwin=false | |
33 | case "`uname`" in | |
34 | CYGWIN* ) | |
35 | cygwin=true | |
36 | ;; | |
37 | Darwin* ) | |
38 | darwin=true | |
39 | ;; | |
40 | MINGW* ) | |
41 | msys=true | |
42 | ;; | |
43 | esac | |
44 | ||
45 | # Attempt to set APP_HOME | |
46 | # Resolve links: $0 may be a link | |
47 | PRG="$0" | |
48 | # Need this for relative symlinks. | |
49 | while [ -h "$PRG" ] ; do | |
50 | ls=`ls -ld "$PRG"` | |
51 | link=`expr "$ls" : '.*-> \(.*\)$'` | |
52 | if expr "$link" : '/.*' > /dev/null; then | |
53 | PRG="$link" | |
54 | else | |
55 | PRG=`dirname "$PRG"`"/$link" | |
56 | fi | |
57 | done | |
58 | SAVED="`pwd`" | |
59 | cd "`dirname \"$PRG\"`/" >/dev/null | |
60 | APP_HOME="`pwd -P`" | |
61 | cd "$SAVED" >/dev/null | |
62 | ||
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar | |
64 | ||
65 | # Determine the Java command to use to start the JVM. | |
66 | if [ -n "$JAVA_HOME" ] ; then | |
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then | |
68 | # IBM's JDK on AIX uses strange locations for the executables | |
69 | JAVACMD="$JAVA_HOME/jre/sh/java" | |
70 | else | |
71 | JAVACMD="$JAVA_HOME/bin/java" | |
72 | fi | |
73 | if [ ! -x "$JAVACMD" ] ; then | |
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME | |
75 | ||
76 | Please set the JAVA_HOME variable in your environment to match the | |
77 | location of your Java installation." | |
78 | fi | |
79 | else | |
80 | JAVACMD="java" | |
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | |
82 | ||
83 | Please set the JAVA_HOME variable in your environment to match the | |
84 | location of your Java installation." | |
85 | fi | |
86 | ||
87 | # Increase the maximum file descriptors if we can. | |
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then | |
89 | MAX_FD_LIMIT=`ulimit -H -n` | |
90 | if [ $? -eq 0 ] ; then | |
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then | |
92 | MAX_FD="$MAX_FD_LIMIT" | |
93 | fi | |
94 | ulimit -n $MAX_FD | |
95 | if [ $? -ne 0 ] ; then | |
96 | warn "Could not set maximum file descriptor limit: $MAX_FD" | |
97 | fi | |
98 | else | |
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" | |
100 | fi | |
101 | fi | |
102 | ||
103 | # For Darwin, add options to specify how the application appears in the dock | |
104 | if $darwin; then | |
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" | |
106 | fi | |
107 | ||
108 | # For Cygwin, switch paths to Windows format before running java | |
109 | if $cygwin ; then | |
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` | |
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` | |
112 | JAVACMD=`cygpath --unix "$JAVACMD"` | |
113 | ||
114 | # We build the pattern for arguments to be converted via cygpath | |
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` | |
116 | SEP="" | |
117 | for dir in $ROOTDIRSRAW ; do | |
118 | ROOTDIRS="$ROOTDIRS$SEP$dir" | |
119 | SEP="|" | |
120 | done | |
121 | OURCYGPATTERN="(^($ROOTDIRS))" | |
122 | # Add a user-defined pattern to the cygpath arguments | |
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then | |
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" | |
125 | fi | |
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh | |
127 | i=0 | |
128 | for arg in "$@" ; do | |
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` | |
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option | |
131 | ||
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition | |
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` | |
134 | else | |
135 | eval `echo args$i`="\"$arg\"" | |
136 | fi | |
137 | i=$((i+1)) | |
138 | done | |
139 | case $i in | |
140 | (0) set -- ;; | |
141 | (1) set -- "$args0" ;; | |
142 | (2) set -- "$args0" "$args1" ;; | |
143 | (3) set -- "$args0" "$args1" "$args2" ;; | |
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; | |
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; | |
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; | |
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; | |
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; | |
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; | |
150 | esac | |
151 | fi | |
152 | ||
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules | |
154 | function splitJvmOpts() { | |
155 | JVM_OPTS=("$@") | |
156 | } | |
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS | |
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" | |
159 | ||
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" |
0 | @if "%DEBUG%" == "" @echo off | |
1 | @rem ########################################################################## | |
2 | @rem | |
3 | @rem Gradle startup script for Windows | |
4 | @rem | |
5 | @rem ########################################################################## | |
6 | ||
7 | @rem Set local scope for the variables with windows NT shell | |
8 | if "%OS%"=="Windows_NT" setlocal | |
9 | ||
10 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | |
11 | set DEFAULT_JVM_OPTS= | |
12 | ||
13 | set DIRNAME=%~dp0 | |
14 | if "%DIRNAME%" == "" set DIRNAME=. | |
15 | set APP_BASE_NAME=%~n0 | |
16 | set APP_HOME=%DIRNAME% | |
17 | ||
18 | @rem Find java.exe | |
19 | if defined JAVA_HOME goto findJavaFromJavaHome | |
20 | ||
21 | set JAVA_EXE=java.exe | |
22 | %JAVA_EXE% -version >NUL 2>&1 | |
23 | if "%ERRORLEVEL%" == "0" goto init | |
24 | ||
25 | echo. | |
26 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | |
27 | echo. | |
28 | echo Please set the JAVA_HOME variable in your environment to match the | |
29 | echo location of your Java installation. | |
30 | ||
31 | goto fail | |
32 | ||
33 | :findJavaFromJavaHome | |
34 | set JAVA_HOME=%JAVA_HOME:"=% | |
35 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe | |
36 | ||
37 | if exist "%JAVA_EXE%" goto init | |
38 | ||
39 | echo. | |
40 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% | |
41 | echo. | |
42 | echo Please set the JAVA_HOME variable in your environment to match the | |
43 | echo location of your Java installation. | |
44 | ||
45 | goto fail | |
46 | ||
47 | :init | |
48 | @rem Get command-line arguments, handling Windowz variants | |
49 | ||
50 | if not "%OS%" == "Windows_NT" goto win9xME_args | |
51 | if "%@eval[2+2]" == "4" goto 4NT_args | |
52 | ||
53 | :win9xME_args | |
54 | @rem Slurp the command line arguments. | |
55 | set CMD_LINE_ARGS= | |
56 | set _SKIP=2 | |
57 | ||
58 | :win9xME_args_slurp | |
59 | if "x%~1" == "x" goto execute | |
60 | ||
61 | set CMD_LINE_ARGS=%* | |
62 | goto execute | |
63 | ||
64 | :4NT_args | |
65 | @rem Get arguments from the 4NT Shell from JP Software | |
66 | set CMD_LINE_ARGS=%$ | |
67 | ||
68 | :execute | |
69 | @rem Setup the command line | |
70 | ||
71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar | |
72 | ||
73 | @rem Execute Gradle | |
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% | |
75 | ||
76 | :end | |
77 | @rem End local scope for the variables with windows NT shell | |
78 | if "%ERRORLEVEL%"=="0" goto mainEnd | |
79 | ||
80 | :fail | |
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of | |
82 | rem the _cmd.exe /c_ return code! | |
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 | |
84 | exit /b 1 | |
85 | ||
86 | :mainEnd | |
87 | if "%OS%"=="Windows_NT" endlocal | |
88 | ||
89 | :omega |
0 | LOCAL_PATH := $(call my-dir) | |
1 | ||
2 | include $(CLEAR_VARS) | |
3 | ||
4 | LOCAL_MODULE := crossguidtest | |
5 | LOCAL_CFLAGS := -Wall | |
6 | LOCAL_SRC_FILES := ../../guid.cpp ../../test.cpp jnitest.cpp | |
7 | LOCAL_CPP_FLAGS := -std=c++11 | |
8 | LOCAL_CPPFLAGS := -DGUID_ANDROID -Wno-c++11-extensions | |
9 | ||
10 | include $(BUILD_SHARED_LIBRARY) |
0 | APP_STL := stlport_static | |
1 | NDK_TOOLCHAIN_VERSION := clang | |
2 | LOCAL_CPP_FLAGS := -DGUID_ANDROID | |
3 | APP_ABI := all |
0 | #include <string> | |
1 | #include <sstream> | |
2 | #include <jni.h> | |
3 | #include <iostream> | |
4 | #include "../../test.h" | |
5 | #include "../../guid.h" | |
6 | ||
7 | extern "C" | |
8 | { | |
9 | ||
10 | jstring Java_ca_graemehill_crossguid_testapp_MainActivity_test(JNIEnv *env, jobject thiz) | |
11 | { | |
12 | std::stringstream resultStream; | |
13 | test(GuidGenerator(env), resultStream); | |
14 | return env->NewStringUTF(resultStream.str().c_str()); | |
15 | } | |
16 | ||
17 | } |
0 | <?xml version="1.0" encoding="utf-8"?> | |
1 | <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
2 | android:orientation="vertical" | |
3 | android:layout_width="fill_parent" | |
4 | android:layout_height="fill_parent" | |
5 | > | |
6 | <TextView | |
7 | android:id="@+id/mainTextView" | |
8 | android:layout_width="fill_parent" | |
9 | android:layout_height="wrap_content" | |
10 | android:text="Graeme says hi" | |
11 | /> | |
12 | </LinearLayout> | |
13 |
0 | <?xml version="1.0" encoding="utf-8"?> | |
1 | <resources> | |
2 | <string name="app_name">MainActivity</string> | |
3 | </resources> |
0 | include ':app' |
0 | package ca.graemehill.crossguid.testapp; | |
1 | ||
2 | import android.app.Activity; | |
3 | import android.os.Bundle; | |
4 | import android.widget.TextView; | |
5 | import java.util.UUID; | |
6 | ||
7 | public class MainActivity extends Activity { | |
8 | ||
9 | @Override | |
10 | public void onCreate(Bundle savedInstanceState) { | |
11 | super.onCreate(savedInstanceState); | |
12 | setContentView(R.layout.main); | |
13 | ||
14 | final TextView textView = (TextView)findViewById(R.id.mainTextView); | |
15 | textView.setText(test()); | |
16 | } | |
17 | ||
18 | public native String test(); | |
19 | ||
20 | static { | |
21 | System.loadLibrary("crossguidtest"); | |
22 | } | |
23 | } |
0 | 0 | #!/usr/bin/env bash |
1 | 1 | |
2 | export LC_NUMERIC="en_US.UTF-8" | |
3 | ||
2 | 4 | pushd android |
3 | ndk-build clean || { exit 1; } | |
4 | ndk-build || { exit 1; } | |
5 | ant debug || { exit 1; } | |
5 | ./gradlew clean assembleDebug | |
6 | 6 | adb uninstall ca.graemehill.crossguid.testapp || { exit 1; } |
7 | adb install bin/TestApp-debug.apk || { exit 1; } | |
7 | adb install app/build/outputs/apk/debug/app-debug.apk || { exit 1; } | |
8 | 8 | adb shell am start -n ca.graemehill.crossguid.testapp/ca.graemehill.crossguid.testapp.MainActivity |
9 | 9 | popd |
0 | find_package(PkgConfig) | |
1 | ||
2 | pkg_check_modules(PKG_LIBUUID QUIET uuid) | |
3 | ||
4 | set(LIBUUID_DEFINITIONS ${PKG_LIBUUID_CFLAGS_OTHER}) | |
5 | set(LIBUUID_VERSION ${PKG_LIBUUID_VERSION}) | |
6 | ||
7 | find_path(LIBUUID_INCLUDE_DIR | |
8 | NAMES uuid/uuid.h | |
9 | HINTS ${PKG_LIBUUID_INCLUDE_DIRS} | |
10 | ) | |
11 | find_library(LIBUUID_LIBRARY | |
12 | NAMES uuid | |
13 | HINTS ${PKG_LIBUUID_LIBRARY_DIRS} | |
14 | ) | |
15 | ||
16 | include(FindPackageHandleStandardArgs) | |
17 | find_package_handle_standard_args(LibUUID | |
18 | FOUND_VAR | |
19 | LIBUUID_FOUND | |
20 | REQUIRED_VARS | |
21 | LIBUUID_LIBRARY | |
22 | LIBUUID_INCLUDE_DIR | |
23 | VERSION_VAR | |
24 | LIBUUID_VERSION | |
25 | ) | |
26 | ||
27 | if(LIBUUID_FOUND AND NOT TARGET LibUUID::UUID) | |
28 | add_library(LibUUID::UUID UNKNOWN IMPORTED) | |
29 | set_target_properties(LibUUID::UUID PROPERTIES | |
30 | IMPORTED_LOCATION "${LIBUUID_LIBRARY}" | |
31 | INTERFACE_COMPILE_OPTIONS "${LIBUUID_DEFINITIONS}" | |
32 | INTERFACE_INCLUDE_DIRECTORIES "${LIBUUID_INCLUDE_DIR}" | |
33 | ) | |
34 | endif() | |
35 | ||
36 | mark_as_advanced(LIBUUID_INCLUDE_DIR LIBUUID_LIBRARY) | |
37 | ||
38 | include(FeatureSummary) | |
39 | set_package_properties(LIBUUID PROPERTIES | |
40 | URL "http://www.kernel.org/pub/linux/utils/util-linux/" | |
41 | DESCRIPTION "uuid library in util-linux" | |
42 | ) |
0 | prefix=@CMAKE_INSTALL_PREFIX@ | |
1 | exec_prefix=${prefix} | |
2 | includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@ | |
3 | libdir=@CMAKE_INSTALL_FULL_LIBDIR@ | |
4 | ||
5 | Name: crossguid | |
6 | Description: Lightweight cross platform C++ GUID/UUID library | |
7 | URL: https://github.com/graeme-hill/crossguid | |
8 | Version: @PROJECT_VERSION@ | |
9 | Cflags: -I${includedir} | |
10 | Libs: -L${libdir} -lcrossguid |
0 | /* | |
1 | The MIT License (MIT) | |
2 | ||
3 | Copyright (c) 2014 Graeme Hill (http://graemehill.ca) | |
4 | ||
5 | Permission is hereby granted, free of charge, to any person obtaining a copy | |
6 | of this software and associated documentation files (the "Software"), to deal | |
7 | in the Software without restriction, including without limitation the rights | |
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
9 | copies of the Software, and to permit persons to whom the Software is | |
10 | furnished to do so, subject to the following conditions: | |
11 | ||
12 | The above copyright notice and this permission notice shall be included in | |
13 | all copies or substantial portions of the Software. | |
14 | ||
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
21 | THE SOFTWARE. | |
22 | */ | |
23 | ||
24 | #include "guid.h" | |
25 | ||
26 | #ifdef GUID_LIBUUID | |
27 | #include <uuid/uuid.h> | |
28 | #endif | |
29 | ||
30 | #ifdef GUID_CFUUID | |
31 | #include <CoreFoundation/CFUUID.h> | |
32 | #endif | |
33 | ||
34 | #ifdef GUID_WINDOWS | |
35 | #include <objbase.h> | |
36 | #endif | |
37 | ||
38 | #ifdef GUID_ANDROID | |
39 | #include <jni.h> | |
40 | #endif | |
41 | ||
42 | using namespace std; | |
43 | ||
44 | // overload << so that it's easy to convert to a string | |
45 | ostream &operator<<(ostream &s, const Guid &guid) | |
46 | { | |
47 | return s << hex << setfill('0') | |
48 | << setw(2) << (int)guid._bytes[0] | |
49 | << setw(2) << (int)guid._bytes[1] | |
50 | << setw(2) << (int)guid._bytes[2] | |
51 | << setw(2) << (int)guid._bytes[3] | |
52 | << "-" | |
53 | << setw(2) << (int)guid._bytes[4] | |
54 | << setw(2) << (int)guid._bytes[5] | |
55 | << "-" | |
56 | << setw(2) << (int)guid._bytes[6] | |
57 | << setw(2) << (int)guid._bytes[7] | |
58 | << "-" | |
59 | << setw(2) << (int)guid._bytes[8] | |
60 | << setw(2) << (int)guid._bytes[9] | |
61 | << "-" | |
62 | << setw(2) << (int)guid._bytes[10] | |
63 | << setw(2) << (int)guid._bytes[11] | |
64 | << setw(2) << (int)guid._bytes[12] | |
65 | << setw(2) << (int)guid._bytes[13] | |
66 | << setw(2) << (int)guid._bytes[14] | |
67 | << setw(2) << (int)guid._bytes[15]; | |
68 | } | |
69 | ||
70 | // create a guid from vector of bytes | |
71 | Guid::Guid(const vector<unsigned char> &bytes) | |
72 | { | |
73 | _bytes = bytes; | |
74 | } | |
75 | ||
76 | // create a guid from array of bytes | |
77 | Guid::Guid(const unsigned char *bytes) | |
78 | { | |
79 | _bytes.assign(bytes, bytes + 16); | |
80 | } | |
81 | ||
82 | // converts a single hex char to a number (0 - 15) | |
83 | unsigned char hexDigitToChar(char ch) | |
84 | { | |
85 | if (ch > 47 && ch < 58) | |
86 | return ch - 48; | |
87 | ||
88 | if (ch > 96 && ch < 103) | |
89 | return ch - 87; | |
90 | ||
91 | if (ch > 64 && ch < 71) | |
92 | return ch - 55; | |
93 | ||
94 | return 0; | |
95 | } | |
96 | ||
97 | // converts the two hexadecimal characters to an unsigned char (a byte) | |
98 | unsigned char hexPairToChar(char a, char b) | |
99 | { | |
100 | return hexDigitToChar(a) * 16 + hexDigitToChar(b); | |
101 | } | |
102 | ||
103 | // create a guid from string | |
104 | Guid::Guid(const string &fromString) | |
105 | { | |
106 | _bytes.clear(); | |
107 | ||
108 | char charOne, charTwo; | |
109 | bool lookingForFirstChar = true; | |
110 | ||
111 | for (const char &ch : fromString) | |
112 | { | |
113 | if (ch == '-') | |
114 | continue; | |
115 | ||
116 | if (lookingForFirstChar) | |
117 | { | |
118 | charOne = ch; | |
119 | lookingForFirstChar = false; | |
120 | } | |
121 | else | |
122 | { | |
123 | charTwo = ch; | |
124 | auto byte = hexPairToChar(charOne, charTwo); | |
125 | _bytes.push_back(byte); | |
126 | lookingForFirstChar = true; | |
127 | } | |
128 | } | |
129 | ||
130 | } | |
131 | ||
132 | // create empty guid | |
133 | Guid::Guid() | |
134 | { | |
135 | _bytes = vector<unsigned char>(16, 0); | |
136 | } | |
137 | ||
138 | // copy constructor | |
139 | Guid::Guid(const Guid &other) | |
140 | { | |
141 | _bytes = other._bytes; | |
142 | } | |
143 | ||
144 | // overload assignment operator | |
145 | Guid &Guid::operator=(const Guid &other) | |
146 | { | |
147 | _bytes = other._bytes; | |
148 | return *this; | |
149 | } | |
150 | ||
151 | // overload equality operator | |
152 | bool Guid::operator==(const Guid &other) const | |
153 | { | |
154 | return _bytes == other._bytes; | |
155 | } | |
156 | ||
157 | // overload inequality operator | |
158 | bool Guid::operator!=(const Guid &other) const | |
159 | { | |
160 | return !((*this) == other); | |
161 | } | |
162 | ||
163 | // This is the linux friendly implementation, but it could work on other | |
164 | // systems that have libuuid available | |
165 | #ifdef GUID_LIBUUID | |
166 | Guid GuidGenerator::newGuid() | |
167 | { | |
168 | uuid_t id; | |
169 | uuid_generate(id); | |
170 | return id; | |
171 | } | |
172 | #endif | |
173 | ||
174 | // this is the mac and ios version | |
175 | #ifdef GUID_CFUUID | |
176 | Guid GuidGenerator::newGuid() | |
177 | { | |
178 | auto newId = CFUUIDCreate(NULL); | |
179 | auto bytes = CFUUIDGetUUIDBytes(newId); | |
180 | CFRelease(newId); | |
181 | ||
182 | const unsigned char byteArray[16] = | |
183 | { | |
184 | bytes.byte0, | |
185 | bytes.byte1, | |
186 | bytes.byte2, | |
187 | bytes.byte3, | |
188 | bytes.byte4, | |
189 | bytes.byte5, | |
190 | bytes.byte6, | |
191 | bytes.byte7, | |
192 | bytes.byte8, | |
193 | bytes.byte9, | |
194 | bytes.byte10, | |
195 | bytes.byte11, | |
196 | bytes.byte12, | |
197 | bytes.byte13, | |
198 | bytes.byte14, | |
199 | bytes.byte15 | |
200 | }; | |
201 | return byteArray; | |
202 | } | |
203 | #endif | |
204 | ||
205 | // obviously this is the windows version | |
206 | #ifdef GUID_WINDOWS | |
207 | Guid GuidGenerator::newGuid() | |
208 | { | |
209 | GUID newId; | |
210 | CoCreateGuid(&newId); | |
211 | ||
212 | const unsigned char bytes[16] = | |
213 | { | |
214 | (newId.Data1 >> 24) & 0xFF, | |
215 | (newId.Data1 >> 16) & 0xFF, | |
216 | (newId.Data1 >> 8) & 0xFF, | |
217 | (newId.Data1) & 0xff, | |
218 | ||
219 | (newId.Data2 >> 8) & 0xFF, | |
220 | (newId.Data2) & 0xff, | |
221 | ||
222 | (newId.Data3 >> 8) & 0xFF, | |
223 | (newId.Data3) & 0xFF, | |
224 | ||
225 | newId.Data4[0], | |
226 | newId.Data4[1], | |
227 | newId.Data4[2], | |
228 | newId.Data4[3], | |
229 | newId.Data4[4], | |
230 | newId.Data4[5], | |
231 | newId.Data4[6], | |
232 | newId.Data4[7] | |
233 | }; | |
234 | ||
235 | return bytes; | |
236 | } | |
237 | #endif | |
238 | ||
239 | // android version that uses a call to a java api | |
240 | #ifdef GUID_ANDROID | |
241 | GuidGenerator::GuidGenerator(JNIEnv *env) | |
242 | { | |
243 | _env = env; | |
244 | _uuidClass = env->FindClass("java/util/UUID"); | |
245 | _newGuidMethod = env->GetStaticMethodID(_uuidClass, "randomUUID", "()Ljava/util/UUID;"); | |
246 | _mostSignificantBitsMethod = env->GetMethodID(_uuidClass, "getMostSignificantBits", "()J"); | |
247 | _leastSignificantBitsMethod = env->GetMethodID(_uuidClass, "getLeastSignificantBits", "()J"); | |
248 | } | |
249 | ||
250 | Guid GuidGenerator::newGuid() | |
251 | { | |
252 | jobject javaUuid = _env->CallStaticObjectMethod(_uuidClass, _newGuidMethod); | |
253 | jlong mostSignificant = _env->CallLongMethod(javaUuid, _mostSignificantBitsMethod); | |
254 | jlong leastSignificant = _env->CallLongMethod(javaUuid, _leastSignificantBitsMethod); | |
255 | ||
256 | unsigned char bytes[16] = | |
257 | { | |
258 | (mostSignificant >> 56) & 0xFF, | |
259 | (mostSignificant >> 48) & 0xFF, | |
260 | (mostSignificant >> 40) & 0xFF, | |
261 | (mostSignificant >> 32) & 0xFF, | |
262 | (mostSignificant >> 24) & 0xFF, | |
263 | (mostSignificant >> 16) & 0xFF, | |
264 | (mostSignificant >> 8) & 0xFF, | |
265 | (mostSignificant) & 0xFF, | |
266 | (leastSignificant >> 56) & 0xFF, | |
267 | (leastSignificant >> 48) & 0xFF, | |
268 | (leastSignificant >> 40) & 0xFF, | |
269 | (leastSignificant >> 32) & 0xFF, | |
270 | (leastSignificant >> 24) & 0xFF, | |
271 | (leastSignificant >> 16) & 0xFF, | |
272 | (leastSignificant >> 8) & 0xFF, | |
273 | (leastSignificant) & 0xFF, | |
274 | }; | |
275 | return bytes; | |
276 | } | |
277 | #endif |
0 | /* | |
1 | The MIT License (MIT) | |
2 | ||
3 | Copyright (c) 2014 Graeme Hill (http://graemehill.ca) | |
4 | ||
5 | Permission is hereby granted, free of charge, to any person obtaining a copy | |
6 | of this software and associated documentation files (the "Software"), to deal | |
7 | in the Software without restriction, including without limitation the rights | |
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
9 | copies of the Software, and to permit persons to whom the Software is | |
10 | furnished to do so, subject to the following conditions: | |
11 | ||
12 | The above copyright notice and this permission notice shall be included in | |
13 | all copies or substantial portions of the Software. | |
14 | ||
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
21 | THE SOFTWARE. | |
22 | */ | |
23 | ||
24 | #pragma once | |
25 | ||
26 | #include <iostream> | |
27 | #include <vector> | |
28 | #include <sstream> | |
29 | #include <string> | |
30 | #include <iomanip> | |
31 | ||
32 | #ifdef GUID_ANDROID | |
33 | #include <jni.h> | |
34 | #endif | |
35 | ||
36 | // Class to represent a GUID/UUID. Each instance acts as a wrapper around a | |
37 | // 16 byte value that can be passed around by value. It also supports | |
38 | // conversion to string (via the stream operator <<) and conversion from a | |
39 | // string via constructor. | |
40 | class Guid | |
41 | { | |
42 | public: | |
43 | ||
44 | // create a guid from vector of bytes | |
45 | Guid(const std::vector<unsigned char> &bytes); | |
46 | ||
47 | // create a guid from array of bytes | |
48 | Guid(const unsigned char *bytes); | |
49 | ||
50 | // create a guid from string | |
51 | Guid(const std::string &fromString); | |
52 | ||
53 | // create empty guid | |
54 | Guid(); | |
55 | ||
56 | // copy constructor | |
57 | Guid(const Guid &other); | |
58 | ||
59 | // overload assignment operator | |
60 | Guid &operator=(const Guid &other); | |
61 | ||
62 | // overload equality and inequality operator | |
63 | bool operator==(const Guid &other) const; | |
64 | bool operator!=(const Guid &other) const; | |
65 | ||
66 | private: | |
67 | ||
68 | // actual data | |
69 | std::vector<unsigned char> _bytes; | |
70 | ||
71 | // make the << operator a friend so it can access _bytes | |
72 | friend std::ostream &operator<<(std::ostream &s, const Guid &guid); | |
73 | }; | |
74 | ||
75 | // Class that can create new guids. The only reason this exists instead of | |
76 | // just a global "newGuid" function is because some platforms will require | |
77 | // that there is some attached context. In the case of android, we need to | |
78 | // know what JNIEnv is being used to call back to Java, but the newGuid() | |
79 | // function would no longer be cross-platform if we parameterized the android | |
80 | // version. Instead, construction of the GuidGenerator may be different on | |
81 | // each platform, but the use of newGuid is uniform. | |
82 | class GuidGenerator | |
83 | { | |
84 | public: | |
85 | #ifdef GUID_ANDROID | |
86 | GuidGenerator(JNIEnv *env); | |
87 | #else | |
88 | GuidGenerator() { } | |
89 | #endif | |
90 | ||
91 | Guid newGuid(); | |
92 | ||
93 | #ifdef GUID_ANDROID | |
94 | private: | |
95 | JNIEnv *_env; | |
96 | jclass _uuidClass; | |
97 | jmethodID _newGuidMethod; | |
98 | jmethodID _mostSignificantBitsMethod; | |
99 | jmethodID _leastSignificantBitsMethod; | |
100 | #endif | |
101 | }; |
0 | /* | |
1 | The MIT License (MIT) | |
2 | ||
3 | Copyright (c) 2014 Graeme Hill (http://graemehill.ca) | |
4 | ||
5 | Permission is hereby granted, free of charge, to any person obtaining a copy | |
6 | of this software and associated documentation files (the "Software"), to deal | |
7 | in the Software without restriction, including without limitation the rights | |
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
9 | copies of the Software, and to permit persons to whom the Software is | |
10 | furnished to do so, subject to the following conditions: | |
11 | ||
12 | The above copyright notice and this permission notice shall be included in | |
13 | all copies or substantial portions of the Software. | |
14 | ||
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
21 | THE SOFTWARE. | |
22 | */ | |
23 | ||
24 | #pragma once | |
25 | ||
26 | #ifdef GUID_ANDROID | |
27 | #include <thread> | |
28 | #include <jni.h> | |
29 | #endif | |
30 | ||
31 | #include <functional> | |
32 | #include <iostream> | |
33 | #include <array> | |
34 | #include <sstream> | |
35 | #include <string_view> | |
36 | #include <utility> | |
37 | #include <iomanip> | |
38 | ||
39 | #define BEGIN_XG_NAMESPACE namespace xg { | |
40 | #define END_XG_NAMESPACE } | |
41 | ||
42 | BEGIN_XG_NAMESPACE | |
43 | ||
44 | // Class to represent a GUID/UUID. Each instance acts as a wrapper around a | |
45 | // 16 byte value that can be passed around by value. It also supports | |
46 | // conversion to string (via the stream operator <<) and conversion from a | |
47 | // string via constructor. | |
48 | class Guid | |
49 | { | |
50 | public: | |
51 | explicit Guid(const std::array<unsigned char, 16> &bytes); | |
52 | explicit Guid(std::array<unsigned char, 16> &&bytes); | |
53 | ||
54 | explicit Guid(std::string_view fromString); | |
55 | Guid(); | |
56 | ||
57 | Guid(const Guid &other) = default; | |
58 | Guid &operator=(const Guid &other) = default; | |
59 | Guid(Guid &&other) = default; | |
60 | Guid &operator=(Guid &&other) = default; | |
61 | ||
62 | bool operator==(const Guid &other) const; | |
63 | bool operator!=(const Guid &other) const; | |
64 | ||
65 | std::string str() const; | |
66 | operator std::string() const; | |
67 | const std::array<unsigned char, 16>& bytes() const; | |
68 | void swap(Guid &other); | |
69 | bool isValid() const; | |
70 | ||
71 | private: | |
72 | void zeroify(); | |
73 | ||
74 | // actual data | |
75 | std::array<unsigned char, 16> _bytes; | |
76 | ||
77 | // make the << operator a friend so it can access _bytes | |
78 | friend std::ostream &operator<<(std::ostream &s, const Guid &guid); | |
79 | friend bool operator<(const Guid &lhs, const Guid &rhs); | |
80 | }; | |
81 | ||
82 | Guid newGuid(); | |
83 | ||
84 | #ifdef GUID_ANDROID | |
85 | struct AndroidGuidInfo | |
86 | { | |
87 | static AndroidGuidInfo fromJniEnv(JNIEnv *env); | |
88 | ||
89 | JNIEnv *env; | |
90 | jclass uuidClass; | |
91 | jmethodID newGuidMethod; | |
92 | jmethodID mostSignificantBitsMethod; | |
93 | jmethodID leastSignificantBitsMethod; | |
94 | std::thread::id initThreadId; | |
95 | }; | |
96 | ||
97 | extern AndroidGuidInfo androidInfo; | |
98 | ||
99 | void initJni(JNIEnv *env); | |
100 | ||
101 | // overloading for multi-threaded calls | |
102 | Guid newGuid(JNIEnv *env); | |
103 | #endif | |
104 | ||
105 | namespace details | |
106 | { | |
107 | template <typename...> struct hash; | |
108 | ||
109 | template<typename T> | |
110 | struct hash<T> : public std::hash<T> | |
111 | { | |
112 | using std::hash<T>::hash; | |
113 | }; | |
114 | ||
115 | ||
116 | template <typename T, typename... Rest> | |
117 | struct hash<T, Rest...> | |
118 | { | |
119 | inline std::size_t operator()(const T& v, const Rest&... rest) { | |
120 | std::size_t seed = hash<Rest...>{}(rest...); | |
121 | seed ^= hash<T>{}(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2); | |
122 | return seed; | |
123 | } | |
124 | }; | |
125 | } | |
126 | ||
127 | END_XG_NAMESPACE | |
128 | ||
129 | namespace std | |
130 | { | |
131 | // Template specialization for std::swap<Guid>() -- | |
132 | // See guid.cpp for the function definition | |
133 | template <> | |
134 | void swap(xg::Guid &guid0, xg::Guid &guid1) noexcept; | |
135 | ||
136 | // Specialization for std::hash<Guid> -- this implementation | |
137 | // uses std::hash<std::string> on the stringification of the guid | |
138 | // to calculate the hash | |
139 | template <> | |
140 | struct hash<xg::Guid> | |
141 | { | |
142 | std::size_t operator()(xg::Guid const &guid) const | |
143 | { | |
144 | const uint64_t* p = reinterpret_cast<const uint64_t*>(guid.bytes().data()); | |
145 | return xg::details::hash<uint64_t, uint64_t>{}(p[0], p[1]); | |
146 | } | |
147 | }; | |
148 | } |
0 | #!/usr/bin/env bash | |
1 | ||
2 | ./clean.sh | |
3 | ||
4 | g++ -c guid.cpp -o guid.o -Wall -std=c++11 -DGUID_LIBUUID | |
5 | g++ -c test.cpp -o test.o -Wall -std=c++11 | |
6 | g++ -c testmain.cpp -o testmain.o -Wall | |
7 | g++ test.o guid.o testmain.o -o test -luuid | |
8 | chmod +x test | |
9 | ./test |
0 | #!/usr/bin/env bash | |
1 | ||
2 | ./clean.sh | |
3 | ||
4 | clang++ -c guid.cpp -o guid.o -Wall -std=c++11 -DGUID_CFUUID | |
5 | clang++ -c test.cpp -o test.o -Wall -std=c++11 | |
6 | clang++ -c testmain.cpp -o testmain.o -Wall -std=c++11 | |
7 | clang++ test.o guid.o testmain.o -o test -framework CoreFoundation | |
8 | chmod +x test | |
9 | ./test |
0 | /* | |
1 | The MIT License (MIT) | |
2 | ||
3 | Copyright (c) 2014 Graeme Hill (http://graemehill.ca) | |
4 | ||
5 | Permission is hereby granted, free of charge, to any person obtaining a copy | |
6 | of this software and associated documentation files (the "Software"), to deal | |
7 | in the Software without restriction, including without limitation the rights | |
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
9 | copies of the Software, and to permit persons to whom the Software is | |
10 | furnished to do so, subject to the following conditions: | |
11 | ||
12 | The above copyright notice and this permission notice shall be included in | |
13 | all copies or substantial portions of the Software. | |
14 | ||
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
21 | THE SOFTWARE. | |
22 | */ | |
23 | ||
24 | #include <cstring> | |
25 | #include "crossguid/guid.hpp" | |
26 | ||
27 | #ifdef GUID_LIBUUID | |
28 | #include <uuid/uuid.h> | |
29 | #endif | |
30 | ||
31 | #ifdef GUID_CFUUID | |
32 | #include <CoreFoundation/CFUUID.h> | |
33 | #endif | |
34 | ||
35 | #ifdef GUID_WINDOWS | |
36 | #include <objbase.h> | |
37 | #endif | |
38 | ||
39 | #ifdef GUID_ANDROID | |
40 | #include <jni.h> | |
41 | #include <cassert> | |
42 | #endif | |
43 | ||
44 | BEGIN_XG_NAMESPACE | |
45 | ||
46 | #ifdef GUID_ANDROID | |
47 | AndroidGuidInfo androidInfo; | |
48 | ||
49 | AndroidGuidInfo AndroidGuidInfo::fromJniEnv(JNIEnv *env) | |
50 | { | |
51 | AndroidGuidInfo info; | |
52 | info.env = env; | |
53 | auto localUuidClass = env->FindClass("java/util/UUID"); | |
54 | info.uuidClass = (jclass)env->NewGlobalRef(localUuidClass); | |
55 | env->DeleteLocalRef(localUuidClass); | |
56 | info.newGuidMethod = env->GetStaticMethodID( | |
57 | info.uuidClass, "randomUUID", "()Ljava/util/UUID;"); | |
58 | info.mostSignificantBitsMethod = env->GetMethodID( | |
59 | info.uuidClass, "getMostSignificantBits", "()J"); | |
60 | info.leastSignificantBitsMethod = env->GetMethodID( | |
61 | info.uuidClass, "getLeastSignificantBits", "()J"); | |
62 | info.initThreadId = std::this_thread::get_id(); | |
63 | return info; | |
64 | } | |
65 | ||
66 | void initJni(JNIEnv *env) | |
67 | { | |
68 | androidInfo = AndroidGuidInfo::fromJniEnv(env); | |
69 | } | |
70 | #endif | |
71 | ||
72 | // overload << so that it's easy to convert to a string | |
73 | std::ostream &operator<<(std::ostream &s, const Guid &guid) | |
74 | { | |
75 | std::ios_base::fmtflags f(s.flags()); // politely don't leave the ostream in hex mode | |
76 | s << std::hex << std::setfill('0') | |
77 | << std::setw(2) << (int)guid._bytes[0] | |
78 | << std::setw(2) << (int)guid._bytes[1] | |
79 | << std::setw(2) << (int)guid._bytes[2] | |
80 | << std::setw(2) << (int)guid._bytes[3] | |
81 | << "-" | |
82 | << std::setw(2) << (int)guid._bytes[4] | |
83 | << std::setw(2) << (int)guid._bytes[5] | |
84 | << "-" | |
85 | << std::setw(2) << (int)guid._bytes[6] | |
86 | << std::setw(2) << (int)guid._bytes[7] | |
87 | << "-" | |
88 | << std::setw(2) << (int)guid._bytes[8] | |
89 | << std::setw(2) << (int)guid._bytes[9] | |
90 | << "-" | |
91 | << std::setw(2) << (int)guid._bytes[10] | |
92 | << std::setw(2) << (int)guid._bytes[11] | |
93 | << std::setw(2) << (int)guid._bytes[12] | |
94 | << std::setw(2) << (int)guid._bytes[13] | |
95 | << std::setw(2) << (int)guid._bytes[14] | |
96 | << std::setw(2) << (int)guid._bytes[15]; | |
97 | s.flags(f); | |
98 | return s; | |
99 | } | |
100 | ||
101 | bool operator<(const xg::Guid &lhs, const xg::Guid &rhs) | |
102 | { | |
103 | return lhs.bytes() < rhs.bytes(); | |
104 | } | |
105 | ||
106 | bool Guid::isValid() const | |
107 | { | |
108 | xg::Guid empty; | |
109 | return *this != empty; | |
110 | } | |
111 | ||
112 | // convert to string using std::snprintf() and std::string | |
113 | std::string Guid::str() const | |
114 | { | |
115 | char one[10], two[6], three[6], four[6], five[14]; | |
116 | ||
117 | snprintf(one, 10, "%02x%02x%02x%02x", | |
118 | _bytes[0], _bytes[1], _bytes[2], _bytes[3]); | |
119 | snprintf(two, 6, "%02x%02x", | |
120 | _bytes[4], _bytes[5]); | |
121 | snprintf(three, 6, "%02x%02x", | |
122 | _bytes[6], _bytes[7]); | |
123 | snprintf(four, 6, "%02x%02x", | |
124 | _bytes[8], _bytes[9]); | |
125 | snprintf(five, 14, "%02x%02x%02x%02x%02x%02x", | |
126 | _bytes[10], _bytes[11], _bytes[12], _bytes[13], _bytes[14], _bytes[15]); | |
127 | const std::string sep("-"); | |
128 | std::string out(one); | |
129 | ||
130 | out += sep + two; | |
131 | out += sep + three; | |
132 | out += sep + four; | |
133 | out += sep + five; | |
134 | ||
135 | return out; | |
136 | } | |
137 | ||
138 | // conversion operator for std::string | |
139 | Guid::operator std::string() const | |
140 | { | |
141 | return str(); | |
142 | } | |
143 | ||
144 | // Access underlying bytes | |
145 | const std::array<unsigned char, 16>& Guid::bytes() const | |
146 | { | |
147 | return _bytes; | |
148 | } | |
149 | ||
150 | // create a guid from vector of bytes | |
151 | Guid::Guid(const std::array<unsigned char, 16> &bytes) : _bytes(bytes) | |
152 | { } | |
153 | ||
154 | // create a guid from vector of bytes | |
155 | Guid::Guid(std::array<unsigned char, 16> &&bytes) : _bytes(std::move(bytes)) | |
156 | { } | |
157 | ||
158 | // converts a single hex char to a number (0 - 15) | |
159 | unsigned char hexDigitToChar(char ch) | |
160 | { | |
161 | // 0-9 | |
162 | if (ch > 47 && ch < 58) | |
163 | return ch - 48; | |
164 | ||
165 | // a-f | |
166 | if (ch > 96 && ch < 103) | |
167 | return ch - 87; | |
168 | ||
169 | // A-F | |
170 | if (ch > 64 && ch < 71) | |
171 | return ch - 55; | |
172 | ||
173 | return 0; | |
174 | } | |
175 | ||
176 | bool isValidHexChar(char ch) | |
177 | { | |
178 | // 0-9 | |
179 | if (ch > 47 && ch < 58) | |
180 | return true; | |
181 | ||
182 | // a-f | |
183 | if (ch > 96 && ch < 103) | |
184 | return true; | |
185 | ||
186 | // A-F | |
187 | if (ch > 64 && ch < 71) | |
188 | return true; | |
189 | ||
190 | return false; | |
191 | } | |
192 | ||
193 | // converts the two hexadecimal characters to an unsigned char (a byte) | |
194 | unsigned char hexPairToChar(char a, char b) | |
195 | { | |
196 | return hexDigitToChar(a) * 16 + hexDigitToChar(b); | |
197 | } | |
198 | ||
199 | // create a guid from string | |
200 | Guid::Guid(std::string_view fromString) | |
201 | { | |
202 | char charOne = '\0'; | |
203 | char charTwo = '\0'; | |
204 | bool lookingForFirstChar = true; | |
205 | unsigned nextByte = 0; | |
206 | ||
207 | for (const char &ch : fromString) | |
208 | { | |
209 | if (ch == '-') | |
210 | continue; | |
211 | ||
212 | if (nextByte >= 16 || !isValidHexChar(ch)) | |
213 | { | |
214 | // Invalid string so bail | |
215 | zeroify(); | |
216 | return; | |
217 | } | |
218 | ||
219 | if (lookingForFirstChar) | |
220 | { | |
221 | charOne = ch; | |
222 | lookingForFirstChar = false; | |
223 | } | |
224 | else | |
225 | { | |
226 | charTwo = ch; | |
227 | auto byte = hexPairToChar(charOne, charTwo); | |
228 | _bytes[nextByte++] = byte; | |
229 | lookingForFirstChar = true; | |
230 | } | |
231 | } | |
232 | ||
233 | // if there were fewer than 16 bytes in the string then guid is bad | |
234 | if (nextByte < 16) | |
235 | { | |
236 | zeroify(); | |
237 | return; | |
238 | } | |
239 | } | |
240 | ||
241 | // create empty guid | |
242 | Guid::Guid() : _bytes{ {0} } | |
243 | { } | |
244 | ||
245 | // set all bytes to zero | |
246 | void Guid::zeroify() | |
247 | { | |
248 | std::fill(_bytes.begin(), _bytes.end(), static_cast<unsigned char>(0)); | |
249 | } | |
250 | ||
251 | // overload equality operator | |
252 | bool Guid::operator==(const Guid &other) const | |
253 | { | |
254 | return _bytes == other._bytes; | |
255 | } | |
256 | ||
257 | // overload inequality operator | |
258 | bool Guid::operator!=(const Guid &other) const | |
259 | { | |
260 | return !((*this) == other); | |
261 | } | |
262 | ||
263 | // member swap function | |
264 | void Guid::swap(Guid &other) | |
265 | { | |
266 | _bytes.swap(other._bytes); | |
267 | } | |
268 | ||
269 | // This is the linux friendly implementation, but it could work on other | |
270 | // systems that have libuuid available | |
271 | #ifdef GUID_LIBUUID | |
272 | Guid newGuid() | |
273 | { | |
274 | std::array<unsigned char, 16> data; | |
275 | static_assert(std::is_same<unsigned char[16], uuid_t>::value, "Wrong type!"); | |
276 | uuid_generate(data.data()); | |
277 | return Guid{std::move(data)}; | |
278 | } | |
279 | #endif | |
280 | ||
281 | // this is the mac and ios version | |
282 | #ifdef GUID_CFUUID | |
283 | Guid newGuid() | |
284 | { | |
285 | auto newId = CFUUIDCreate(NULL); | |
286 | auto bytes = CFUUIDGetUUIDBytes(newId); | |
287 | CFRelease(newId); | |
288 | ||
289 | std::array<unsigned char, 16> byteArray = | |
290 | {{ | |
291 | bytes.byte0, | |
292 | bytes.byte1, | |
293 | bytes.byte2, | |
294 | bytes.byte3, | |
295 | bytes.byte4, | |
296 | bytes.byte5, | |
297 | bytes.byte6, | |
298 | bytes.byte7, | |
299 | bytes.byte8, | |
300 | bytes.byte9, | |
301 | bytes.byte10, | |
302 | bytes.byte11, | |
303 | bytes.byte12, | |
304 | bytes.byte13, | |
305 | bytes.byte14, | |
306 | bytes.byte15 | |
307 | }}; | |
308 | return Guid{std::move(byteArray)}; | |
309 | } | |
310 | #endif | |
311 | ||
312 | // obviously this is the windows version | |
313 | #ifdef GUID_WINDOWS | |
314 | Guid newGuid() | |
315 | { | |
316 | GUID newId; | |
317 | CoCreateGuid(&newId); | |
318 | ||
319 | std::array<unsigned char, 16> bytes = | |
320 | { | |
321 | (unsigned char)((newId.Data1 >> 24) & 0xFF), | |
322 | (unsigned char)((newId.Data1 >> 16) & 0xFF), | |
323 | (unsigned char)((newId.Data1 >> 8) & 0xFF), | |
324 | (unsigned char)((newId.Data1) & 0xff), | |
325 | ||
326 | (unsigned char)((newId.Data2 >> 8) & 0xFF), | |
327 | (unsigned char)((newId.Data2) & 0xff), | |
328 | ||
329 | (unsigned char)((newId.Data3 >> 8) & 0xFF), | |
330 | (unsigned char)((newId.Data3) & 0xFF), | |
331 | ||
332 | (unsigned char)newId.Data4[0], | |
333 | (unsigned char)newId.Data4[1], | |
334 | (unsigned char)newId.Data4[2], | |
335 | (unsigned char)newId.Data4[3], | |
336 | (unsigned char)newId.Data4[4], | |
337 | (unsigned char)newId.Data4[5], | |
338 | (unsigned char)newId.Data4[6], | |
339 | (unsigned char)newId.Data4[7] | |
340 | }; | |
341 | ||
342 | return Guid{std::move(bytes)}; | |
343 | } | |
344 | #endif | |
345 | ||
346 | // android version that uses a call to a java api | |
347 | #ifdef GUID_ANDROID | |
348 | Guid newGuid(JNIEnv *env) | |
349 | { | |
350 | assert(env != androidInfo.env || std::this_thread::get_id() == androidInfo.initThreadId); | |
351 | ||
352 | jobject javaUuid = env->CallStaticObjectMethod( | |
353 | androidInfo.uuidClass, androidInfo.newGuidMethod); | |
354 | jlong mostSignificant = env->CallLongMethod(javaUuid, | |
355 | androidInfo.mostSignificantBitsMethod); | |
356 | jlong leastSignificant = env->CallLongMethod(javaUuid, | |
357 | androidInfo.leastSignificantBitsMethod); | |
358 | ||
359 | std::array<unsigned char, 16> bytes = | |
360 | { | |
361 | (unsigned char)((mostSignificant >> 56) & 0xFF), | |
362 | (unsigned char)((mostSignificant >> 48) & 0xFF), | |
363 | (unsigned char)((mostSignificant >> 40) & 0xFF), | |
364 | (unsigned char)((mostSignificant >> 32) & 0xFF), | |
365 | (unsigned char)((mostSignificant >> 24) & 0xFF), | |
366 | (unsigned char)((mostSignificant >> 16) & 0xFF), | |
367 | (unsigned char)((mostSignificant >> 8) & 0xFF), | |
368 | (unsigned char)((mostSignificant) & 0xFF), | |
369 | (unsigned char)((leastSignificant >> 56) & 0xFF), | |
370 | (unsigned char)((leastSignificant >> 48) & 0xFF), | |
371 | (unsigned char)((leastSignificant >> 40) & 0xFF), | |
372 | (unsigned char)((leastSignificant >> 32) & 0xFF), | |
373 | (unsigned char)((leastSignificant >> 24) & 0xFF), | |
374 | (unsigned char)((leastSignificant >> 16) & 0xFF), | |
375 | (unsigned char)((leastSignificant >> 8) & 0xFF), | |
376 | (unsigned char)((leastSignificant) & 0xFF) | |
377 | }; | |
378 | ||
379 | env->DeleteLocalRef(javaUuid); | |
380 | ||
381 | return Guid{std::move(bytes)}; | |
382 | } | |
383 | ||
384 | Guid newGuid() | |
385 | { | |
386 | return newGuid(androidInfo.env); | |
387 | } | |
388 | #endif | |
389 | ||
390 | ||
391 | END_XG_NAMESPACE | |
392 | ||
393 | // Specialization for std::swap<Guid>() -- | |
394 | // call member swap function of lhs, passing rhs | |
395 | namespace std | |
396 | { | |
397 | template <> | |
398 | void swap(xg::Guid &lhs, xg::Guid &rhs) noexcept | |
399 | { | |
400 | lhs.swap(rhs); | |
401 | } | |
402 | } |
0 | #include "Test.hpp" | |
1 | ||
2 | int test(std::ostream &outStream) | |
3 | { | |
4 | int failed = 0; | |
5 | ||
6 | /************************************************************************* | |
7 | * HAPPY PATH TESTS | |
8 | *************************************************************************/ | |
9 | ||
10 | auto r1 = xg::newGuid(); | |
11 | auto r2 = xg::newGuid(); | |
12 | auto r3 = xg::newGuid(); | |
13 | ||
14 | outStream << r1 << std::endl << r2 << std::endl << r3 << std::endl; | |
15 | ||
16 | xg::Guid s1("7bcd757f-5b10-4f9b-af69-1a1f226f3b3e"); | |
17 | xg::Guid s2("16d1bd03-09a5-47d3-944b-5e326fd52d27"); | |
18 | xg::Guid s3("fdaba646-e07e-49de-9529-4499a5580c75"); | |
19 | xg::Guid s4("7bcd757f-5b10-4f9b-af69-1a1f226f3b3e"); | |
20 | xg::Guid s5("7bcd757f-5b10-4f9b-af69-1a1f226f3b31"); | |
21 | ||
22 | if (r1 == r2 || r1 == r3 || r2 == r3) | |
23 | { | |
24 | outStream << "FAIL - not all random guids are different" << std::endl; | |
25 | failed++; | |
26 | } | |
27 | ||
28 | if (s1 == s2) | |
29 | { | |
30 | outStream << "FAIL - s1 and s2 should be different" << std::endl; | |
31 | failed++; | |
32 | } | |
33 | ||
34 | if (s1 != s4) | |
35 | { | |
36 | outStream << "FAIL - s1 and s4 should be equal" << std::endl; | |
37 | failed++; | |
38 | } | |
39 | ||
40 | if (s4 < s5) { | |
41 | outStream << "FAIL - s5 should should less than s4" << std::endl; | |
42 | failed++; | |
43 | } | |
44 | ||
45 | std::stringstream ss1; | |
46 | ss1 << s1; | |
47 | if (ss1.str() != "7bcd757f-5b10-4f9b-af69-1a1f226f3b3e") | |
48 | { | |
49 | outStream << "FAIL - string from s1 stream is wrong" << std::endl; | |
50 | outStream << "--> " << ss1.str() << std::endl; | |
51 | failed++; | |
52 | } | |
53 | ||
54 | if (s1.str() != "7bcd757f-5b10-4f9b-af69-1a1f226f3b3e") | |
55 | { | |
56 | outStream << "FAIL - string from s1.str() is wrong" << std::endl; | |
57 | outStream << "--> " << s1.str() << std::endl; | |
58 | failed++; | |
59 | } | |
60 | ||
61 | std::stringstream ss2; | |
62 | ss2 << s2; | |
63 | if (ss2.str() != "16d1bd03-09a5-47d3-944b-5e326fd52d27") | |
64 | { | |
65 | outStream << "FAIL - string generated from s2 is wrong" << std::endl; | |
66 | outStream << "--> " << ss2.str() << std::endl; | |
67 | return 1; | |
68 | } | |
69 | ||
70 | std::stringstream ss3; | |
71 | ss3 << s3; | |
72 | if (ss3.str() != "fdaba646-e07e-49de-9529-4499a5580c75") | |
73 | { | |
74 | outStream << "FAIL - string generated from s3 is wrong" << std::endl; | |
75 | outStream << "--> " << ss3.str() << std::endl; | |
76 | failed++; | |
77 | } | |
78 | ||
79 | auto swap1 = xg::newGuid(); | |
80 | auto swap2 = xg::newGuid(); | |
81 | auto swap3 = swap1; | |
82 | auto swap4 = swap2; | |
83 | ||
84 | if (swap1 != swap3 || swap2 != swap4 || swap1 == swap2) | |
85 | { | |
86 | outStream << "FAIL - swap guids have bad initial state" << std::endl; | |
87 | failed++; | |
88 | } | |
89 | ||
90 | swap1.swap(swap2); | |
91 | ||
92 | if (swap1 != swap4 || swap2 != swap3 || swap1 == swap2) | |
93 | { | |
94 | outStream << "FAIL - swap didn't swap" << std::endl; | |
95 | failed++; | |
96 | } | |
97 | ||
98 | { | |
99 | std::unordered_map<xg::Guid, int> m = {{s1, 1}, {s2, 2}}; | |
100 | auto it1 = m.find(s1); | |
101 | auto it2 = m.find(s2); | |
102 | if(!( it1 != m.end() && it1->first == s1 && it1->second == 1 && it2 != m.end() && it2->first == s2 && it2->second == 2)) | |
103 | { | |
104 | outStream << "FAIL - map/hash failed!" << std::endl; | |
105 | failed++; | |
106 | } | |
107 | auto it3 = m.find(s3); | |
108 | if(it3 != m.end()) | |
109 | { | |
110 | outStream << "FAIL - map/hash failed!" << std::endl; | |
111 | failed++; | |
112 | } | |
113 | } | |
114 | std::array<unsigned char, 16> bytes = | |
115 | {{ | |
116 | 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, | |
117 | 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xdd | |
118 | }}; | |
119 | xg::Guid guidFromBytes(bytes); | |
120 | xg::Guid guidFromString("0102030405060708090a0b0c0d0e0fdd"); | |
121 | if (guidFromBytes != guidFromString) | |
122 | { | |
123 | outStream << "FAIL - String/bytes make different guids" << std::endl; | |
124 | failed++; | |
125 | } | |
126 | ||
127 | if(!std::equal(guidFromBytes.bytes().begin(), guidFromBytes.bytes().end(), bytes.begin())) | |
128 | { | |
129 | outStream << "FAIL - array returned from bytes() is wrong" << std::endl; | |
130 | failed++; | |
131 | } | |
132 | ||
133 | /************************************************************************* | |
134 | * ERROR HANDLING | |
135 | *************************************************************************/ | |
136 | ||
137 | xg::Guid empty; | |
138 | xg::Guid twoTooFew("7bcd757f-5b10-4f9b-af69-1a1f226f3b"); | |
139 | if (twoTooFew != empty || twoTooFew.isValid()) | |
140 | { | |
141 | outStream << "FAIL - Guid from two too few chars" << std::endl; | |
142 | failed++; | |
143 | } | |
144 | ||
145 | xg::Guid oneTooFew("16d1bd03-09a5-47d3-944b-5e326fd52d2"); | |
146 | if (oneTooFew != empty || oneTooFew.isValid()) | |
147 | { | |
148 | outStream << "FAIL - Guid from one too few chars" << std::endl; | |
149 | failed++; | |
150 | } | |
151 | ||
152 | xg::Guid twoTooMany("7bcd757f-5b10-4f9b-af69-1a1f226f3beeff"); | |
153 | if (twoTooMany != empty || twoTooMany.isValid()) | |
154 | { | |
155 | outStream << "FAIL - Guid from two too many chars" << std::endl; | |
156 | failed++; | |
157 | } | |
158 | ||
159 | xg::Guid oneTooMany("16d1bd03-09a5-47d3-944b-5e326fd52d27a"); | |
160 | if (oneTooMany != empty || oneTooMany.isValid()) | |
161 | { | |
162 | outStream << "FAIL - Guid from one too many chars" << std::endl; | |
163 | failed++; | |
164 | } | |
165 | ||
166 | xg::Guid badString("!!bad-guid-string!!"); | |
167 | if (badString != empty || badString.isValid()) | |
168 | { | |
169 | outStream << "FAIL - Guid from bad string" << std::endl; | |
170 | failed++; | |
171 | } | |
172 | ||
173 | if (failed == 0) | |
174 | { | |
175 | outStream << "All tests passed!" << std::endl; | |
176 | return 0; | |
177 | } | |
178 | else | |
179 | { | |
180 | outStream << failed << " tests failed." << std::endl; | |
181 | return 1; | |
182 | } | |
183 | } |
0 | #pragma once | |
1 | ||
2 | #include <crossguid/guid.hpp> | |
3 | #include <iostream> | |
4 | #include <unordered_map> | |
5 | ||
6 | int test(std::ostream &outStream); |
0 | #include "guid.h" | |
1 | ||
2 | using namespace std; | |
3 | ||
4 | int test(GuidGenerator generator, std::ostream &outStream) | |
5 | { | |
6 | auto r1 = generator.newGuid(); | |
7 | auto r2 = generator.newGuid(); | |
8 | auto r3 = generator.newGuid(); | |
9 | ||
10 | outStream << r1 << endl << r2 << endl << r3 << endl; | |
11 | ||
12 | Guid s1("7bcd757f-5b10-4f9b-af69-1a1f226f3b3e"); | |
13 | Guid s2("16d1bd03-09a5-47d3-944b-5e326fd52d27"); | |
14 | Guid s3("fdaba646-e07e-49de-9529-4499a5580c75"); | |
15 | Guid s4("7bcd757f-5b10-4f9b-af69-1a1f226f3b3e"); | |
16 | ||
17 | if (r1 == r2 || r1 == r3 || r2 == r3) | |
18 | { | |
19 | outStream << "FAIL - not all random guids are different" << endl; | |
20 | return 1; | |
21 | } | |
22 | ||
23 | if (s1 == s2) | |
24 | { | |
25 | outStream << "FAIL - s1 and s2 should be different" << endl; | |
26 | return 1; | |
27 | } | |
28 | ||
29 | if (s1 != s4) | |
30 | { | |
31 | outStream << "FAIL - s1 and s4 should be equal" << endl; | |
32 | return 1; | |
33 | } | |
34 | ||
35 | stringstream ss1; | |
36 | ss1 << s1; | |
37 | if (ss1.str() != "7bcd757f-5b10-4f9b-af69-1a1f226f3b3e") | |
38 | { | |
39 | outStream << "FAIL - string generated from s1 is wrong" << endl; | |
40 | return 1; | |
41 | } | |
42 | ||
43 | stringstream ss2; | |
44 | ss2 << s2; | |
45 | if (ss2.str() != "16d1bd03-09a5-47d3-944b-5e326fd52d27") | |
46 | { | |
47 | outStream << "FAIL - string generated from s2 is wrong" << endl; | |
48 | return 1; | |
49 | } | |
50 | ||
51 | stringstream ss3; | |
52 | ss3 << s3; | |
53 | if (ss3.str() != "fdaba646-e07e-49de-9529-4499a5580c75") | |
54 | { | |
55 | outStream << "FAIL - string generated from s3 is wrong" << endl; | |
56 | return 1; | |
57 | } | |
58 | ||
59 | outStream << "All tests passed!" << endl; | |
60 | ||
61 | return 0; | |
62 | } |