diff --git a/.clang-format b/.clang-format index d3f5e189..06fdb97d 100644 --- a/.clang-format +++ b/.clang-format @@ -87,6 +87,7 @@ IndentGotoLabels: true IndentPPDirectives: None IndentWidth: 2 IndentWrappedFunctionNames: false +InsertNewlineAtEOF: true JavaScriptQuotes: Leave JavaScriptWrapImports: true KeepEmptyLinesAtTheStartOfBlocks: false diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 00000000..5f1c3ce5 --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1 @@ +225b07e41f03d82358171a3d91ab3f210d0ae783 # ignore repository-wide reformat diff --git a/.github/workflows/code-quality.yml b/.github/workflows/code-quality.yml index 3997a989..9fe82de3 100644 --- a/.github/workflows/code-quality.yml +++ b/.github/workflows/code-quality.yml @@ -21,17 +21,6 @@ jobs: sudo apt-get install -y clang-format clang-tidy cmake g++ make bash scripts/install_dependency.sh - - name: Get changed C/C++ files - id: changed-files - uses: tj-actions/changed-files@v46.0.5 - with: - files: | - **/*.c - **/*.h - **/*.cpp - **/*.cc - **/*.hpp - - name: Create log directory run: mkdir -p logs @@ -41,7 +30,7 @@ jobs: echo "Running clang-format checks..." FORMAT_ERRORS=0 - for file in ${{ steps.changed-files.outputs.all_changed_files }}; do + for file in $(find . -iname '*.h' -or -iname '*.c' -or -iname '*.cpp' -or -iname '*.hpp' -or -iname '*.cc'); do echo "Checking formatting for $file" if ! clang-format --dry-run --Werror "$file" >> logs/format.log 2>&1; then echo "::error file=$file::Formatting issues in $file" @@ -72,7 +61,7 @@ jobs: echo "Running clang-tidy checks..." FILES_WITH_ISSUES=0 - for file in ${{ steps.changed-files.outputs.all_changed_files }}; do + for file in $(find . -iname '*.h' -or -iname '*.c' -or -iname '*.cpp' -or -iname '*.hpp' -or -iname '*.cc'); do echo "Checking $file with clang-tidy" LOG_FILE="logs/tidy_$(basename "$file").log" diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f57cb78..13450e3f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,8 @@ project(libCacheSim) set(DESCRIPTION "a high performance cache simulation library") set(PROJECT_WEB "http://cachesim.com") +find_package(PkgConfig REQUIRED) + set(${PROJECT_NAME}_VERSION_MAJOR 0) set(${PROJECT_NAME}_VERSION_MINOR 1) set(${PROJECT_NAME}_VERSION_PATCH 0) @@ -39,7 +41,6 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") add_definitions(-DOS_DARWIN) set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "/opt/homebrew/include/") set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "/opt/homebrew/") - elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux") add_definitions(-DOS_LINUX) else() @@ -116,9 +117,9 @@ message(STATUS "SUPPORT TTL ${SUPPORT_TTL}, USE_HUGEPAGE ${USE_HUGEPAGE}, LOGLEV # ####################################### # compiler flags # # ####################################### -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror -Wno-unused-variable -Wno-unused-function -Wno-unused-parameter -Wno-unused-but-set-variable -Wpedantic -Wformat=2 -Wformat-security -Wshadow -Wwrite-strings -Wstrict-prototypes -Wold-style-definition -Wredundant-decls -Wnested-externs -Wmissing-include-dirs") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror -Wno-unused-variable -Wno-unused-function -Wno-unused-parameter -Wno-unused-but-set-variable -Wpedantic -Wformat=2 -Wformat-security -Wshadow -Wwrite-strings -Wstrict-prototypes -Wold-style-definition -Wredundant-decls -Wnested-externs -Wmissing-include-dirs -Wno-gnu-zero-variadic-macro-arguments") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Werror -Wno-deprecated-copy -Wno-unused-variable -Wno-unused-function -Wno-unused-parameter -Wno-unused-but-set-variable -Wno-pedantic -Wformat=2 -Wformat-security -Wshadow -Wwrite-strings -Wmissing-include-dirs") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Werror -Wno-deprecated-copy -Wno-unused-variable -Wno-unused-function -Wno-unused-parameter -Wno-unused-but-set-variable -Wno-pedantic -Wformat=2 -Wformat-security -Wshadow -Wwrite-strings -Wmissing-include-dirs -Wno-gnu-zero-variadic-macro-arguments") # if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") # set(CFLAGS "$ENV{CFLAGS} " "-Wl,--export-dynamic ") @@ -142,7 +143,7 @@ set(LIBS ${LIBS} ${ARGP_LIBRARY}) if(OPT_SUPPORT_ZSTD_TRACE) add_compile_definitions(SUPPORT_ZSTD_TRACE=1) - find_package(ZSTD) + pkg_check_modules(ZSTD REQUIRED libzstd) # https://stackoverflow.com/questions/61377055/cannot-find-gflags-gflags-h-while-building-library-osx/61379123#61379123 include_directories(${ZSTD_INCLUDE_DIR}) @@ -151,6 +152,7 @@ if(OPT_SUPPORT_ZSTD_TRACE) message(FATAL_ERROR "zstd not found") endif() + link_directories(${ZSTD_LIBRARY_DIRS}) link_libraries(${ZSTD_LIBRARIES}) message(STATUS "ZSTD_INCLUDE_DIR ${ZSTD_INCLUDE_DIR}, ZSTD_LIBRARIES ${ZSTD_LIBRARIES}") else() @@ -349,7 +351,11 @@ SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) add_library(${PROJECT_NAME} ${LIB_SOURCE}) # target_compile_options(${PROJECT_NAME} PRIVATE -fPIC) -target_link_options(${PROJECT_NAME} PRIVATE -Wl,--export-dynamic) + +# Skip unsupported linker option for macOS (export-dynamic) +if(NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin") + target_link_options(${PROJECT_NAME} PRIVATE -Wl,--export-dynamic) +endif() # add_library(${PROJECT_NAME} SHARED ${LIB_SOURCE}) diff --git a/example/cacheCluster/cacheCluster.cpp b/example/cacheCluster/cacheCluster.cpp index 4890a305..fdc448b0 100644 --- a/example/cacheCluster/cacheCluster.cpp +++ b/example/cacheCluster/cacheCluster.cpp @@ -15,8 +15,7 @@ namespace CDNSimulator { bool CacheCluster::get(request_t *req) { // find the server idx - uint64_t idx = - ch_ring_get_server_from_uint64(req->obj_id, this->_ring); + uint64_t idx = ch_ring_get_server_from_uint64(req->obj_id, this->_ring); // find the server CacheServer &server = this->_cache_servers_vec.at(idx); diff --git a/example/cacheCluster/consistentHash.c b/example/cacheCluster/consistentHash.c index ccc90226..73de894b 100644 --- a/example/cacheCluster/consistentHash.c +++ b/example/cacheCluster/consistentHash.c @@ -136,10 +136,9 @@ int ch_ring_get_server(const char *const key, const ring_t *const ring) { return (ring->vnodes + ch_ring_get_vnode_idx(key, ring))->server_id; } -int ch_ring_get_server_from_uint64(uint64_t obj_id, - const ring_t *const ring) { - char key[8]; - memcpy(key, (char *) &obj_id, 8); +int ch_ring_get_server_from_uint64(uint64_t obj_id, const ring_t *const ring) { + char key[8]; + memcpy(key, (char *)&obj_id, 8); key[7] = 0; return (ring->vnodes + ch_ring_get_vnode_idx(key, ring))->server_id; } @@ -217,4 +216,4 @@ void ch_ring_destroy_ring(ring_t *ring) { #ifdef __cplusplus } -#endif \ No newline at end of file +#endif diff --git a/example/cacheCluster/include/cache.hpp b/example/cacheCluster/include/cache.hpp index 93648c0a..634e7447 100644 --- a/example/cacheCluster/include/cache.hpp +++ b/example/cacheCluster/include/cache.hpp @@ -10,9 +10,10 @@ #ifndef CDNSIMULATOR_CACHE_HPP #define CDNSIMULATOR_CACHE_HPP +#include + #include #include -#include #include "libCacheSim/cache.h" #include "libCacheSim/evictionAlgo.h" diff --git a/example/cacheCluster/include/cacheCluster.hpp b/example/cacheCluster/include/cacheCluster.hpp index 4f19a992..66c41e32 100644 --- a/example/cacheCluster/include/cacheCluster.hpp +++ b/example/cacheCluster/include/cacheCluster.hpp @@ -24,7 +24,6 @@ namespace CDNSimulator { class CacheCluster { private: - // the consistent hash ring ring_t *_ring = nullptr; diff --git a/example/cacheCluster/include/consistentHash.h b/example/cacheCluster/include/consistentHash.h index ef211887..235f6571 100644 --- a/example/cacheCluster/include/consistentHash.h +++ b/example/cacheCluster/include/consistentHash.h @@ -9,11 +9,11 @@ extern "C" { #endif +#include #include #include #include #include -#include #define N_VNODE_PER_SERVER 160 diff --git a/example/cacheCluster/include/md5.h b/example/cacheCluster/include/md5.h index d9a45cb2..b8e8606f 100644 --- a/example/cacheCluster/include/md5.h +++ b/example/cacheCluster/include/md5.h @@ -27,7 +27,7 @@ This code implements the MD5 Algorithm defined in RFC 1321, whose text is available at - http://www.ietf.org/rfc/rfc1321.txt + http://www.ietf.org/rfc/rfc1321.txt The code is derived from the text of the RFC, including the test suite (section A.5) but excluding the rest of Appendix A. It does not include any code or documentation that is identified in the RFC as being @@ -38,17 +38,17 @@ that follows (in reverse chronological order): 2002-04-13 lpd Removed support for non-ANSI compilers; removed - references to Ghostscript; clarified derivation from RFC 1321; - now handles byte order either statically or dynamically. + references to Ghostscript; clarified derivation from RFC 1321; + now handles byte order either statically or dynamically. 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); - added conditionalization for C++ compilation from Martin - Purschke . + added conditionalization for C++ compilation from Martin + Purschke . 1999-05-03 lpd Original version. */ #ifndef md5_INCLUDED -# define md5_INCLUDED +#define md5_INCLUDED /* * This package supports both compile-time and run-time determination of CPU @@ -61,18 +61,17 @@ */ typedef unsigned char md5_byte_t; /* 8-bit byte */ -typedef unsigned int md5_word_t; /* 32-bit word */ +typedef unsigned int md5_word_t; /* 32-bit word */ /* Define the state of the MD5 Algorithm. */ typedef struct md5_state_s { - md5_word_t count[2]; /* message length in bits, lsw first */ - md5_word_t abcd[4]; /* digest buffer */ - md5_byte_t buf[64]; /* accumulate block */ + md5_word_t count[2]; /* message length in bits, lsw first */ + md5_word_t abcd[4]; /* digest buffer */ + md5_byte_t buf[64]; /* accumulate block */ } md5_state_t; #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif /* Initialize the algorithm. */ @@ -95,7 +94,7 @@ _declspec(dllexport) void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); #ifdef __cplusplus -} /* end extern "C" */ +} /* end extern "C" */ #endif #endif /* md5_INCLUDED */ diff --git a/example/cacheCluster/libketama/include/ketama.h b/example/cacheCluster/libketama/include/ketama.h index 76de4e7e..2805dcb2 100644 --- a/example/cacheCluster/libketama/include/ketama.h +++ b/example/cacheCluster/libketama/include/ketama.h @@ -1,60 +1,56 @@ -/* -* Copyright (c) 2017, Emory University, All rights reserved. -* Juncheng Yang -* -* Modify for libCacheSim based on original version -* also add const modifier for compiler optimizations -* -*/ - - - +/* + * Copyright (c) 2017, Emory University, All rights reserved. + * Juncheng Yang + * + * Modify for libCacheSim based on original version + * also add const modifier for compiler optimizations + * + */ /* -* Copyright (c) 2007, Last.fm, All rights reserved. -* Richard Jones -* Christian Muehlhaeuser -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the Last.fm Limited nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY Last.fm ``AS IS'' AND ANY -* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL Last.fm BE LIABLE FOR ANY -* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ + * Copyright (c) 2007, Last.fm, All rights reserved. + * Richard Jones + * Christian Muehlhaeuser + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Last.fm Limited nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Last.fm ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Last.fm BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ #ifndef KETAMA_LIBKETAMA_KETAMA_H__ #define KETAMA_LIBKETAMA_KETAMA_H__ -#include /* semaphore functions and structs. */ +#include /* semaphore functions and structs. */ -#define MC_SHMSIZE 524288 // 512KB should be ample. +#define MC_SHMSIZE 524288 // 512KB should be ample. #ifdef __cplusplus /* If this is a C++ compiler, use C linkage */ extern "C" { #endif #ifndef __APPLE__ -union semun -{ - int val; /* used for SETVAL only */ - struct semid_ds *buf; /* for IPC_STAT and IPC_SET */ - ushort *array; /* used for GETALL and SETALL */ +union semun { + int val; /* used for SETVAL only */ + struct semid_ds *buf; /* for IPC_STAT and IPC_SET */ + ushort *array; /* used for GETALL and SETALL */ }; #endif @@ -67,64 +63,63 @@ typedef struct { typedef struct { char addr[22]; - unsigned long memory; // in CDNSimulator, this is used as weight + unsigned long memory; // in CDNSimulator, this is used as weight } serverinfo; typedef struct { int numpoints; void *modtime; - void *array; //array of mcs structs + void *array; // array of mcs structs } continuum; typedef continuum *ketama_continuum; /** build a consistent hashing ring - * given the number of servers and the weight of each server. - * if weight is NULL, then each server has equal weight. - * key_identifier is just a number for identifying shared memory */ + * given the number of servers and the weight of each server. + * if weight is NULL, then each server has equal weight. + * key_identifier is just a number for identifying shared memory */ int ketama_build_hashring(ketama_continuum *const contptr, const unsigned int num_servers, const unsigned long *const weight, const int key_identifier); -int ketama_get_server_index( - const ketama_continuum cont, - const char *const key); +int ketama_get_server_index(const ketama_continuum cont, const char *const key); -void ketama_get_server_indexes( - const ketama_continuum cont, - const char *const key, - unsigned int n, int *indexes); +void ketama_get_server_indexes(const ketama_continuum cont, + const char *const key, unsigned int n, + int *indexes); /** \brief Get a continuum struct that contains a reference to the server list. - * \param contptr The value of this pointer will contain the retrieved continuum. - * \param filename The server-definition file which defines our continuum. - * \return 0 on failure, 1 on success. */ + * \param contptr The value of this pointer will contain the retrieved + * continuum. + * \param filename The server-definition file which defines our continuum. + * \return 0 on failure, 1 on success. */ int ketama_roll(ketama_continuum *contptr, char *filename); /** \brief Frees any allocated memory. - * \param contptr The continuum that you want to be destroy. */ + * \param contptr The continuum that you want to be destroy. */ void ketama_smoke(ketama_continuum contptr); /** \brief Maps a key onto a server in the continuum. - * \param key The key that you want to map to a specific server. - * \param cont Pointer to the continuum in which we will search. - * \return The mcs struct that the given key maps to. */ + * \param key The key that you want to map to a specific server. + * \param cont Pointer to the continuum in which we will search. + * \return The mcs struct that the given key maps to. */ mcs *ketama_get_server(char *key, ketama_continuum cont); /** \brief Print the server list of a continuum to stdout. - * \param c The continuum to print. */ + * \param c The continuum to print. */ void ketama_print_continuum(ketama_continuum c); /** \brief Compare two server entries in the circle. - * \param a The first entry. - * \param b The second entry. - * \return -1 if b greater a, +1 if a greater b or 0 if both are equal. */ + * \param a The first entry. + * \param b The second entry. + * \return -1 if b greater a, +1 if a greater b or 0 if both are equal. */ int ketama_compare(mcs *a, mcs *b); -/** \brief Hashing function, converting a string to an unsigned int by using MD5. - * \param inString The string that you want to hash. - * \return The resulting hash. */ +/** \brief Hashing function, converting a string to an unsigned int by using + * MD5. + * \param inString The string that you want to hash. + * \return The resulting hash. */ unsigned int ketama_hashi(const char *const inString); /** \brief Hashing function to 16 bytes char array using MD5. @@ -133,12 +128,11 @@ unsigned int ketama_hashi(const char *const inString); void ketama_md5_digest(const char *const inString, unsigned char md5pword[16]); /** \brief Error method for error checking. - * \return The latest error that occurred. */ + * \return The latest error that occurred. */ char *ketama_error(); #ifdef __cplusplus /* If this is a C++ compiler, end C linkage */ } #endif -#endif // KETAMA_LIBKETAMA_KETAMA_H__ - +#endif // KETAMA_LIBKETAMA_KETAMA_H__ diff --git a/example/cacheCluster/libketama/ketama.c b/example/cacheCluster/libketama/ketama.c index 225ac866..9c073b31 100644 --- a/example/cacheCluster/libketama/ketama.c +++ b/example/cacheCluster/libketama/ketama.c @@ -1,43 +1,44 @@ /* -* Copyright (c) 2007, Last.fm, All rights reserved. -* Richard Jones -* Christian Muehlhaeuser -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the Last.fm Limited nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY Last.fm ``AS IS'' AND ANY -* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL Last.fm BE LIABLE FOR ANY -* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ + * Copyright (c) 2007, Last.fm, All rights reserved. + * Richard Jones + * Christian Muehlhaeuser + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Last.fm Limited nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Last.fm ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Last.fm BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ #include "ketama.h" -#include "md5.h" -#include +#include +#include /* floor & floorf */ #include +#include #include -#include -#include /* for reading last time modification */ -#include /* needed for usleep */ -#include /* floor & floorf */ -#include /* various type definitions */ -#include /* shared memory functions and structs */ +#include /* shared memory functions and structs */ +#include /* various type definitions */ +#include /* for reading last time modification */ +#include /* needed for usleep */ + +#include "md5.h" #ifdef DEBUG #include @@ -45,7 +46,6 @@ #include - char k_error[255] = ""; int num_sem_ids = 0; @@ -58,815 +58,767 @@ int *sem_ids = NULL; int *shm_ids = NULL; int **shm_data = NULL; -static void -set_error(const char *format, ...) { - va_list ap; - va_start(ap, format); - vsnprintf(k_error, sizeof(k_error), format, ap); - va_end(ap); +static void set_error(const char *format, ...) { + va_list ap; + va_start(ap, format); + vsnprintf(k_error, sizeof(k_error), format, ap); + va_end(ap); } -static void -init_sem_id_tracker() { - sem_ids = (int *) malloc(sizeof(int) * 1024); +static void init_sem_id_tracker() { + sem_ids = (int *)malloc(sizeof(int) * 1024); } -static void -init_shm_id_tracker() { - shm_ids = (int *) malloc(sizeof(int) * 1024); +static void init_shm_id_tracker() { + shm_ids = (int *)malloc(sizeof(int) * 1024); } -static void -init_shm_data_tracker() { - shm_data = (int **) malloc(sizeof(int *) * 1024); +static void init_shm_data_tracker() { + shm_data = (int **)malloc(sizeof(int *) * 1024); } -static void -track_shm_data(int *data) { - if (num_data == shm_data_size) { - int **tmp = (int **) realloc(shm_data, sizeof(int *) * (shm_data_size + 1024)); - if (tmp != NULL) { - shm_data = tmp; - } else { - set_error("Cannot realloc shm data tracker"); - exit(1); - } - - shm_data_size += 1024; +static void track_shm_data(int *data) { + if (num_data == shm_data_size) { + int **tmp = + (int **)realloc(shm_data, sizeof(int *) * (shm_data_size + 1024)); + if (tmp != NULL) { + shm_data = tmp; + } else { + set_error("Cannot realloc shm data tracker"); + exit(1); } - shm_data[num_data] = data; - num_data++; -} + shm_data_size += 1024; + } -static void -track_sem_id(int semid) { - if (num_sem_ids == sem_ids_size) { - int *tmp = (int *) realloc(sem_ids, sizeof(int) * (sem_ids_size + 1024)); - if (tmp != NULL) { - sem_ids = tmp; - } else { - set_error("Cannot realloc semids"); - exit(1); - } + shm_data[num_data] = data; + num_data++; +} - sem_ids_size += 1024; +static void track_sem_id(int semid) { + if (num_sem_ids == sem_ids_size) { + int *tmp = (int *)realloc(sem_ids, sizeof(int) * (sem_ids_size + 1024)); + if (tmp != NULL) { + sem_ids = tmp; + } else { + set_error("Cannot realloc semids"); + exit(1); } - sem_ids[num_sem_ids] = semid; - num_sem_ids++; -} + sem_ids_size += 1024; + } -static void -track_shm_id(int shmid) { - if (num_shm_ids == shm_ids_size) { - int *tmp = (int *) realloc(shm_ids, sizeof(int) * (shm_ids_size + 1024)); - if (tmp != NULL) { - shm_ids = tmp; - } else { - set_error("Cannot realloc shmids"); - exit(1); - } + sem_ids[num_sem_ids] = semid; + num_sem_ids++; +} - shm_ids_size += 1024; +static void track_shm_id(int shmid) { + if (num_shm_ids == shm_ids_size) { + int *tmp = (int *)realloc(shm_ids, sizeof(int) * (shm_ids_size + 1024)); + if (tmp != NULL) { + shm_ids = tmp; + } else { + set_error("Cannot realloc shmids"); + exit(1); } - shm_ids[num_shm_ids] = shmid; - num_shm_ids++; + shm_ids_size += 1024; + } + + shm_ids[num_shm_ids] = shmid; + num_shm_ids++; } /** \brief Locks the semaphore. - * \param sem_set_id The semaphore handle that you want to lock. */ -static void -ketama_sem_lock(int sem_set_id) { - union semun sem_val; - sem_val.val = 2; - semctl(sem_set_id, 0, SETVAL, sem_val); + * \param sem_set_id The semaphore handle that you want to lock. */ +static void ketama_sem_lock(int sem_set_id) { + union semun sem_val; + sem_val.val = 2; + semctl(sem_set_id, 0, SETVAL, sem_val); } - /** \brief Unlocks the semaphore. - * \param sem_set_id The semaphore handle that you want to unlock. */ -static void -ketama_sem_unlock(int sem_set_id) { - union semun sem_val; - sem_val.val = 1; - semctl(sem_set_id, 0, SETVAL, sem_val); + * \param sem_set_id The semaphore handle that you want to unlock. */ +static void ketama_sem_unlock(int sem_set_id) { + union semun sem_val; + sem_val.val = 1; + semctl(sem_set_id, 0, SETVAL, sem_val); } - /** \brief Initialize a semaphore. - * \param key Semaphore key to use. - * \return The freshly allocated semaphore handle. */ -static int -ketama_sem_init(key_t key) { - if (sem_ids == NULL) { - init_sem_id_tracker(); - } + * \param key Semaphore key to use. + * \return The freshly allocated semaphore handle. */ +static int ketama_sem_init(key_t key) { + if (sem_ids == NULL) { + init_sem_id_tracker(); + } - int sem_set_id; + int sem_set_id; - sem_set_id = semget(key, 1, 0); + sem_set_id = semget(key, 1, 0); + track_sem_id(sem_set_id); + + if (sem_set_id == -1) { + // create a semaphore set with ID SEM_ID + sem_set_id = semget(key, 1, IPC_CREAT | 0666); track_sem_id(sem_set_id); if (sem_set_id == -1) { - // create a semaphore set with ID SEM_ID - sem_set_id = semget(key, 1, IPC_CREAT | 0666); - track_sem_id(sem_set_id); - - if (sem_set_id == -1) { - strcpy(k_error, "Could not open semaphore!"); - return 0; - } - - ketama_sem_unlock(sem_set_id); + strcpy(k_error, "Could not open semaphore!"); + return 0; } - return sem_set_id; -} + ketama_sem_unlock(sem_set_id); + } + return sem_set_id; +} /* ketama.h does not expose this function */ -void -ketama_md5_digest(const char *const inString, unsigned char md5pword[16]) { - md5_state_t md5state; +void ketama_md5_digest(const char *const inString, unsigned char md5pword[16]) { + md5_state_t md5state; - md5_init(&md5state); - md5_append(&md5state, (unsigned char *) inString, (int) strlen(inString)); - md5_finish(&md5state, md5pword); + md5_init(&md5state); + md5_append(&md5state, (unsigned char *)inString, (int)strlen(inString)); + md5_finish(&md5state, md5pword); } - /** \brief Retrieve the modification time of a file. - * \param filename The full path to the file. - * \return The timestamp of the latest modification to the file. */ -static time_t -file_modtime(char *filename) { - struct tm *clock; - struct stat attrib; + * \param filename The full path to the file. + * \return The timestamp of the latest modification to the file. */ +static time_t file_modtime(char *filename) { + struct tm *clock; + struct stat attrib; - stat(filename, &attrib); - clock = gmtime(&(attrib.st_mtime)); + stat(filename, &attrib); + clock = gmtime(&(attrib.st_mtime)); - return mktime(clock); + return mktime(clock); } - /** \brief Retrieve a serverinfo struct for one a sever definition. - * \param line The entire server definition in plain-text. - * \return A serverinfo struct, parsed from the given definition. */ -static serverinfo -read_server_line(char *line) { - char *delimiter = "\t "; - serverinfo server; - server.memory = 0; - - char *tok = strtok(line, delimiter); - if ((strlen(tok) - 1) < 23) { - char *mem = 0; - char *endptr = 0; - - strncpy(server.addr, tok, strlen(tok)); - server.addr[strlen(tok)] = '\0'; - - tok = strtok(0, delimiter); - /* We do not check for a NULL return earlier because strtok will - * always return at least the first token; hence never return NULL. - */ - if (tok == 0) { - strcpy(k_error, "Unable to find delimiter"); - server.memory = 0; - } else { - mem = (char *) malloc(strlen(tok)); - strncpy(mem, tok, strlen(tok) - 1); - mem[strlen(tok) - 1] = '\0'; - - errno = 0; - server.memory = (unsigned long) strtol(mem, &endptr, 10); - if (errno == ERANGE || endptr == mem) { - strcpy(k_error, "Invalid memory value"); - server.memory = 0; - } - - free(mem); - } - } - - return server; -} + * \param line The entire server definition in plain-text. + * \return A serverinfo struct, parsed from the given definition. */ +static serverinfo read_server_line(char *line) { + char *delimiter = "\t "; + serverinfo server; + server.memory = 0; + + char *tok = strtok(line, delimiter); + if (tok && (strlen(tok) - 1) < 23) { + char *mem = 0; + char *endptr = 0; + + strncpy(server.addr, tok, strlen(tok)); + server.addr[strlen(tok)] = '\0'; + + tok = strtok(0, delimiter); + /* We do not check for a NULL return earlier because strtok will + * always return at least the first token; hence never return NULL. + */ + if (tok == 0) { + strcpy(k_error, "Unable to find delimiter"); + server.memory = 0; + } else { + mem = (char *)malloc(strlen(tok)); + strncpy(mem, tok, strlen(tok) - 1); + mem[strlen(tok) - 1] = '\0'; + errno = 0; + server.memory = (unsigned long)strtol(mem, &endptr, 10); + if (errno == ERANGE || endptr == mem) { + strcpy(k_error, "Invalid memory value"); + server.memory = 0; + } -/** \brief Retrieve all server definitions from a file. - * \param filename The full path to the file which contains the server definitions. - * \param count The value of this pointer will be set to the amount of servers which could be parsed. - * \param memory The value of this pointer will be set to the total amount of allocated memory across all servers. - * \return A serverinfo array, containing all servers that could be parsed from the given file. */ -static serverinfo * -read_server_definitions(char *filename, unsigned int *count, unsigned long *memory) { - serverinfo *slist = 0; - unsigned int lineno = 0; - unsigned int numservers = 0; - unsigned long memtotal = 0; - - FILE *fi = fopen(filename, "r"); - while (fi && !feof(fi)) { - char sline[128] = ""; - - if (fgets(sline, 127, fi) == NULL) - continue; - - lineno++; - - if (strlen(sline) < 2 || sline[0] == '#') - continue; - - serverinfo server = read_server_line(sline); - if (server.memory > 0 && strlen(server.addr)) { - slist = (serverinfo *) realloc(slist, sizeof(serverinfo) * (numservers + 1)); - memcpy(&slist[numservers], &server, sizeof(serverinfo)); - numservers++; - memtotal += server.memory; - } else { - /* This kind of tells the parent code that - * "there were servers but not really" - */ - *count = 1; - free(slist); - set_error("%s (line %d in %s)", k_error, lineno, filename); - return 0; - } + free(mem); } + } - if (!fi) { - set_error("File %s doesn't exist!", filename); + return server; +} - *count = 0; - return 0; +/** \brief Retrieve all server definitions from a file. + * \param filename The full path to the file which contains the server + * definitions. + * \param count The value of this pointer will be set to the amount of servers + * which could be parsed. + * \param memory The value of this pointer will be set to the total amount of + * allocated memory across all servers. + * \return A serverinfo array, containing all servers that could be parsed from + * the given file. */ +static serverinfo *read_server_definitions(char *filename, unsigned int *count, + unsigned long *memory) { + serverinfo *slist = 0; + unsigned int lineno = 0; + unsigned int numservers = 0; + unsigned long memtotal = 0; + + FILE *fi = fopen(filename, "r"); + while (fi && !feof(fi)) { + char sline[128] = ""; + + if (fgets(sline, 127, fi) == NULL) continue; + + lineno++; + + if (!sline || strlen(sline) < 2 || sline[0] == '#') continue; + + serverinfo server = read_server_line(sline); + if (server.memory > 0 && strlen(server.addr)) { + slist = + (serverinfo *)realloc(slist, sizeof(serverinfo) * (numservers + 1)); + memcpy(&slist[numservers], &server, sizeof(serverinfo)); + numservers++; + memtotal += server.memory; } else { - fclose(fi); - } - - *count = numservers; - *memory = memtotal; - return slist; + /* This kind of tells the parent code that + * "there were servers but not really" + */ + *count = 1; + free(slist); + set_error("%s (line %d in %s)", k_error, lineno, filename); + return 0; + } + } + + if (!fi) { + set_error("File %s doesn't exist!", filename); + + *count = 0; + return 0; + } else { + fclose(fi); + } + + *count = numservers; + *memory = memtotal; + return slist; } +unsigned int ketama_hashi(const char *const inString) { + unsigned char digest[16]; -unsigned int -ketama_hashi(const char *const inString) { - unsigned char digest[16]; - - ketama_md5_digest(inString, digest); - return (unsigned int) ((digest[3] << 24) - | (digest[2] << 16) - | (digest[1] << 8) - | digest[0]); + ketama_md5_digest(inString, digest); + return (unsigned int)((digest[3] << 24) | (digest[2] << 16) | + (digest[1] << 8) | digest[0]); } +mcs *ketama_get_server(char *key, ketama_continuum cont) { + unsigned int h = ketama_hashi(key); + int highp = cont->numpoints; + mcs(*mcsarr)[cont->numpoints] = (mcs(*)[cont->numpoints])cont->array; + int lowp = 0, midp; + unsigned int midval, midval1; -mcs * -ketama_get_server(char *key, ketama_continuum cont) { - unsigned int h = ketama_hashi(key); - int highp = cont->numpoints; - mcs (*mcsarr)[cont->numpoints] = (mcs (*)[cont->numpoints]) cont->array; - int lowp = 0, midp; - unsigned int midval, midval1; - - // divide and conquer array search to find server with next biggest - // point after what this key hashes to - while (1) { - midp = (int) ((lowp + highp) / 2); + // divide and conquer array search to find server with next biggest + // point after what this key hashes to + while (1) { + midp = (int)((lowp + highp) / 2); - if (midp == cont->numpoints) - return &((*mcsarr)[0]); // if at the end, roll back to zeroth + if (midp == cont->numpoints) + return &((*mcsarr)[0]); // if at the end, roll back to zeroth - midval = (*mcsarr)[midp].point; - midval1 = midp == 0 ? 0 : (*mcsarr)[midp - 1].point; + midval = (*mcsarr)[midp].point; + midval1 = midp == 0 ? 0 : (*mcsarr)[midp - 1].point; - if (h <= midval && h > midval1) - return &((*mcsarr)[midp]); + if (h <= midval && h > midval1) return &((*mcsarr)[midp]); - if (midval < h) - lowp = midp + 1; - else - highp = midp - 1; + if (midval < h) + lowp = midp + 1; + else + highp = midp - 1; - if (lowp > highp) - return &((*mcsarr)[0]); - } + if (lowp > highp) return &((*mcsarr)[0]); + } } - -/** \brief Generates the continuum of servers (each server as many points on a circle). - * \param key Shared memory key for storing the newly created continuum. - * \param filename Server definition file, which will be parsed to create this continuum. - * \return 0 on failure, 1 on success. */ -static int -ketama_create_continuum(key_t key, char *filename) { - if (shm_ids == NULL) { - init_shm_id_tracker(); - } - - if (shm_data == NULL) { - init_shm_data_tracker(); - } - - int shmid; - int *data; /* Pointer to shmem location */ - unsigned int numservers = 0; - unsigned long memory; - serverinfo *slist; - - slist = read_server_definitions(filename, &numservers, &memory); - /* Check numservers first; if it is zero then there is no error message - * and we need to set one. */ - if (numservers < 1) { - set_error("No valid server definitions in file %s", filename); - return 0; - } else if (slist == 0) { - /* read_server_definitions must've set error message. */ - return 0; - } +/** \brief Generates the continuum of servers (each server as many points on a + * circle). + * \param key Shared memory key for storing the newly created continuum. + * \param filename Server definition file, which will be parsed to create this + * continuum. + * \return 0 on failure, 1 on success. */ +static int ketama_create_continuum(key_t key, char *filename) { + if (shm_ids == NULL) { + init_shm_id_tracker(); + } + + if (shm_data == NULL) { + init_shm_data_tracker(); + } + + int shmid; + int *data; /* Pointer to shmem location */ + unsigned int numservers = 0; + unsigned long memory; + serverinfo *slist; + + slist = read_server_definitions(filename, &numservers, &memory); + /* Check numservers first; if it is zero then there is no error message + * and we need to set one. */ + if (numservers < 1) { + set_error("No valid server definitions in file %s", filename); + return 0; + } else if (slist == 0) { + /* read_server_definitions must've set error message. */ + return 0; + } #ifdef DEBUG - syslog( LOG_INFO, "Server definitions read: %u servers, total memory: %lu.\n", - numservers, memory ); + syslog(LOG_INFO, "Server definitions read: %u servers, total memory: %lu.\n", + numservers, memory); #endif - /* Continuum will hold one mcs for each point on the circle: */ - mcs continuum[numservers * 160]; - unsigned int i, k, cont = 0; + /* Continuum will hold one mcs for each point on the circle: */ + mcs continuum[numservers * 160]; + unsigned int i, k, cont = 0; - for (i = 0; i < numservers; i++) { - float pct = (float) slist[i].memory / (float) memory; - unsigned int ks = (unsigned int) floorf(pct * 40.0f * (float) numservers); + for (i = 0; i < numservers; i++) { + float pct = (float)slist[i].memory / (float)memory; + unsigned int ks = (unsigned int)floorf(pct * 40.0f * (float)numservers); #ifdef DEBUG - int hpct = floorf( pct * 100.0 ); + int hpct = floorf(pct * 100.0); - syslog( LOG_INFO, "Server no. %d: %s (mem: %lu = %u%% or %d of %d)\n", - i, slist[i].addr, slist[i].memory, hpct, ks, numservers * 40 ); + syslog(LOG_INFO, "Server no. %d: %s (mem: %lu = %u%% or %d of %d)\n", i, + slist[i].addr, slist[i].memory, hpct, ks, numservers * 40); #endif - for (k = 0; k < ks; k++) { - /* 40 hashes, 4 numbers per hash = 160 points per server */ - char ss[30]; - unsigned char digest[16]; - - sprintf(ss, "%s-%d", slist[i].addr, k); - ketama_md5_digest(ss, digest); - - /* Use successive 4-bytes from hash as numbers - * for the points on the circle: */ - int h; - for (h = 0; h < 4; h++) { - continuum[cont].point = (digest[3 + h * 4] << 24) - | (digest[2 + h * 4] << 16) - | (digest[1 + h * 4] << 8) - | digest[h * 4]; - - memcpy(continuum[cont].ip, slist[i].addr, 22); - cont++; - } - } - } - free(slist); - - /* Sorts in ascending order of "point" */ - qsort((void *) &continuum, cont, sizeof(mcs), (compfn) ketama_compare); - - /* Add data to shmmem */ - shmid = shmget(key, MC_SHMSIZE, 0644 | IPC_CREAT); - track_shm_id(shmid); - - data = (int *) shmat(shmid, (void *) 0, 0); - if (data == (void *) (-1)) { - strcpy(k_error, "Can't open shmmem for writing."); - return 0; - } - - time_t modtime = file_modtime(filename); - int nump = cont; - memcpy(data, &nump, sizeof(int)); - memcpy(data + 1, &modtime, sizeof(time_t)); - memcpy(data + 1 + sizeof(void *), &continuum, sizeof(mcs) * nump); - - /* We detach here because we will re-attach in read-only - * mode to actually use it. */ + for (k = 0; k < ks; k++) { + /* 40 hashes, 4 numbers per hash = 160 points per server */ + char ss[30]; + unsigned char digest[16]; + + sprintf(ss, "%s-%d", slist[i].addr, k); + ketama_md5_digest(ss, digest); + + /* Use successive 4-bytes from hash as numbers + * for the points on the circle: */ + int h; + for (h = 0; h < 4; h++) { + continuum[cont].point = (digest[3 + h * 4] << 24) | + (digest[2 + h * 4] << 16) | + (digest[1 + h * 4] << 8) | digest[h * 4]; + + memcpy(continuum[cont].ip, slist[i].addr, 22); + cont++; + } + } + } + free(slist); + + /* Sorts in ascending order of "point" */ + qsort((void *)&continuum, cont, sizeof(mcs), (compfn)ketama_compare); + + /* Add data to shmmem */ + shmid = shmget(key, MC_SHMSIZE, 0644 | IPC_CREAT); + track_shm_id(shmid); + + data = (int *)shmat(shmid, (void *)0, 0); + if (data == (void *)(-1)) { + strcpy(k_error, "Can't open shmmem for writing."); + return 0; + } + + time_t modtime = file_modtime(filename); + int nump = cont; + memcpy(data, &nump, sizeof(int)); + memcpy(data + 1, &modtime, sizeof(time_t)); + memcpy(data + 1 + sizeof(void *), &continuum, sizeof(mcs) * nump); + + /* We detach here because we will re-attach in read-only + * mode to actually use it. */ #ifdef SOLARIS - if ( shmdt( (char *) data ) == -1 ) + if (shmdt((char *)data) == -1) #else - if (shmdt(data) == -1) + if (shmdt(data) == -1) #endif - strcpy(k_error, "Error detaching from shared memory!"); + strcpy(k_error, "Error detaching from shared memory!"); - return 1; + return 1; } +int ketama_roll(ketama_continuum *contptr, char *filename) { + if (shm_ids == NULL) { + init_shm_id_tracker(); + } -int -ketama_roll(ketama_continuum *contptr, char *filename) { - if (shm_ids == NULL) { - init_shm_id_tracker(); - } + if (shm_data == NULL) { + init_shm_data_tracker(); + } - if (shm_data == NULL) { - init_shm_data_tracker(); - } + strcpy(k_error, ""); - strcpy(k_error, ""); + key_t key; + int shmid; + int *data; + int sem_set_id; - key_t key; - int shmid; - int *data; - int sem_set_id; + key = ftok(filename, 'R'); + if (key == -1) { + set_error("Invalid filename specified: %s", filename); + return 0; + } - key = ftok(filename, 'R'); - if (key == -1) { - set_error("Invalid filename specified: %s", filename); - return 0; - } + *contptr = (ketama_continuum)malloc(sizeof(continuum)); + (*contptr)->numpoints = 0; + (*contptr)->array = 0; + (*contptr)->modtime = 0; - *contptr = (ketama_continuum) malloc(sizeof(continuum)); - (*contptr)->numpoints = 0; - (*contptr)->array = 0; - (*contptr)->modtime = 0; + sem_set_id = ketama_sem_init(key); - sem_set_id = ketama_sem_init(key); + int sanity = 0; + while (semctl(sem_set_id, 0, GETVAL, 0) == 2) { + // wait for the continuum creator to finish, but don't block others + usleep(5); - int sanity = 0; - while (semctl(sem_set_id, 0, GETVAL, 0) == 2) { - // wait for the continuum creator to finish, but don't block others - usleep(5); - - // if we are waiting for > 1 second, take drastic action: - if (++sanity > 1000000) { - usleep(rand() % 50000); - ketama_sem_unlock(sem_set_id); - break; - } + // if we are waiting for > 1 second, take drastic action: + if (++sanity > 1000000) { + usleep(rand() % 50000); + ketama_sem_unlock(sem_set_id); + break; } + } - time_t modtime = file_modtime(filename); - time_t *fmodtime = 0; - while (!fmodtime || modtime != *fmodtime) { - shmid = shmget(key, MC_SHMSIZE, 0); // read only attempt. - track_shm_id(shmid); - - data = (int *) shmat(shmid, (void *) 0, SHM_RDONLY); - - if (data == (void *) (-1) || (*contptr)->modtime != 0) { - ketama_sem_lock(sem_set_id); - - if (!ketama_create_continuum(key, filename)) { - strcpy(k_error, "Ketama_create_continuum() failed!"); - ketama_sem_unlock(sem_set_id); - return 0; - } -/* else - syslog( LOG_INFO, "ketama_create_continuum() successfully finished.\n" );*/ + time_t modtime = file_modtime(filename); + time_t *fmodtime = 0; + while (!fmodtime || modtime != *fmodtime) { + shmid = shmget(key, MC_SHMSIZE, 0); // read only attempt. + track_shm_id(shmid); - shmid = shmget(key, MC_SHMSIZE, 0); // read only attempt. - track_shm_id(shmid); + data = (int *)shmat(shmid, (void *)0, SHM_RDONLY); - data = (int *) shmat(shmid, (void *) 0, SHM_RDONLY); - ketama_sem_unlock(sem_set_id); - } + if (data == (void *)(-1) || (*contptr)->modtime != 0) { + ketama_sem_lock(sem_set_id); - if (data == (void *) (-1)) { - strcpy(k_error, "Failed miserably to get pointer to shmemdata!"); - return 0; - } + if (!ketama_create_continuum(key, filename)) { + strcpy(k_error, "Ketama_create_continuum() failed!"); + ketama_sem_unlock(sem_set_id); + return 0; + } + /* else + syslog( LOG_INFO, "ketama_create_continuum() successfully + finished.\n" );*/ - track_shm_data(data); + shmid = shmget(key, MC_SHMSIZE, 0); // read only attempt. + track_shm_id(shmid); - (*contptr)->numpoints = *data; - (*contptr)->modtime = ++data; - (*contptr)->array = data + sizeof(void *); - fmodtime = (time_t *) ((*contptr)->modtime); + data = (int *)shmat(shmid, (void *)0, SHM_RDONLY); + ketama_sem_unlock(sem_set_id); } - return 1; -} - - -void -ketama_smoke(ketama_continuum contptr) { - int i; - if (shm_data != NULL) { - for (i = 0; i < num_data; i++) { - shmdt(shm_data[i]); - } - free(shm_data); - shm_data = NULL; - num_data = 0; - shm_data_size = 1024; + if (data == (void *)(-1)) { + strcpy(k_error, "Failed miserably to get pointer to shmemdata!"); + return 0; } - if (sem_ids != NULL) { - for (i = 0; i < num_sem_ids; i++) { - semctl(sem_ids[i], 0, IPC_RMID, 0); - } - free(sem_ids); - sem_ids = NULL; - num_sem_ids = 0; - sem_ids_size = 1024; - } + track_shm_data(data); - if (shm_ids != NULL) { - for (i = 0; i < num_shm_ids; i++) { - shmctl(shm_ids[i], IPC_RMID, 0); - } - free(shm_ids); - shm_ids = NULL; - num_shm_ids = 0; - shm_ids_size = 1024; - } + (*contptr)->numpoints = *data; + (*contptr)->modtime = ++data; + (*contptr)->array = data + sizeof(void *); + fmodtime = (time_t *)((*contptr)->modtime); + } - free(contptr); + return 1; } - -void -ketama_print_continuum(ketama_continuum cont) { - int a; - printf("Numpoints in continuum: %d\n", cont->numpoints); - - if (cont->array == 0) { - printf("Continuum empty\n"); - } else { - mcs (*mcsarr)[cont->numpoints] = (mcs (*)[cont->numpoints]) cont->array; - for (a = 0; a < cont->numpoints; a++) { - printf("%s (%u)\n", (*mcsarr)[a].ip, (*mcsarr)[a].point); - } - } +void ketama_smoke(ketama_continuum contptr) { + int i; + if (shm_data != NULL) { + for (i = 0; i < num_data; i++) { + shmdt(shm_data[i]); + } + free(shm_data); + shm_data = NULL; + num_data = 0; + shm_data_size = 1024; + } + + if (sem_ids != NULL) { + for (i = 0; i < num_sem_ids; i++) { + semctl(sem_ids[i], 0, IPC_RMID, 0); + } + free(sem_ids); + sem_ids = NULL; + num_sem_ids = 0; + sem_ids_size = 1024; + } + + if (shm_ids != NULL) { + for (i = 0; i < num_shm_ids; i++) { + shmctl(shm_ids[i], IPC_RMID, 0); + } + free(shm_ids); + shm_ids = NULL; + num_shm_ids = 0; + shm_ids_size = 1024; + } + + free(contptr); } +void ketama_print_continuum(ketama_continuum cont) { + int a; + printf("Numpoints in continuum: %d\n", cont->numpoints); -int -ketama_compare(mcs *a, mcs *b) { - return (a->point < b->point) ? -1 : ((a->point > b->point) ? 1 : 0); + if (cont->array == 0) { + printf("Continuum empty\n"); + } else { + mcs(*mcsarr)[cont->numpoints] = (mcs(*)[cont->numpoints])cont->array; + for (a = 0; a < cont->numpoints; a++) { + printf("%s (%u)\n", (*mcsarr)[a].ip, (*mcsarr)[a].point); + } + } } - -char * -ketama_error() { - return k_error; +int ketama_compare(mcs *a, mcs *b) { + return (a->point < b->point) ? -1 : ((a->point > b->point) ? 1 : 0); } +char *ketama_error() { return k_error; } /* weight should be an array of unsigned long, for example memory size */ -static int -ketama_create_continuum_libCacheSim(const key_t key, - const unsigned int num_servers, - const unsigned long *const weight) { - if (shm_ids == NULL) { - init_shm_id_tracker(); - } - - if (shm_data == NULL) { - init_shm_data_tracker(); - } - - unsigned int i, k, cont = 0; - int shmid; - int *data; /* Pointer to shmem location */ - unsigned long total_weight = 0; - serverinfo *slist = (serverinfo *) malloc(sizeof(serverinfo) * num_servers); - - // calculate total weight - if (weight != NULL) { - for (i = 0; i < num_servers; i++) - total_weight += weight[i]; - } else - total_weight = num_servers; - - // fill in serverinfo - for (i = 0; i < num_servers; i++) { - /* all server ip are effective ID, begins from 0 */ - sprintf(slist[i].addr, "%d", i); - if (weight != NULL) - slist[i].memory = weight[i]; - else - slist[i].memory = 1; - } - - /* Continuum will hold one mcs for each point on the circle: */ - mcs continuum[num_servers * 160]; - - for (i = 0; i < num_servers; i++) { - float pct = (float) slist[i].memory / (float) total_weight; - unsigned int ks = (unsigned int) floorf(pct * 40.0f * (float) num_servers); - for (k = 0; k < ks; k++) { - /* 40 hashes, 4 numbers per hash = 160 points per server */ - char ss[30]; - unsigned char digest[16]; - - sprintf(ss, "%s-%d", slist[i].addr, k); - ketama_md5_digest(ss, digest); - - /* Use successive 4-bytes from hash as numbers - * for the points on the circle: */ - int h; - for (h = 0; h < 4; h++) { - continuum[cont].point = (digest[3 + h * 4] << 24) - | (digest[2 + h * 4] << 16) - | (digest[1 + h * 4] << 8) - | digest[h * 4]; - - memcpy(continuum[cont].ip, slist[i].addr, 22); - cont++; - } - } - } - free(slist); - - /* Sorts in ascending order of "point" */ - qsort((void *) &continuum, cont, sizeof(mcs), (compfn) ketama_compare); - - /* Add data to shmmem */ - shmid = shmget(key, MC_SHMSIZE, 0644 | IPC_CREAT); - track_shm_id(shmid); - - data = (int *) shmat(shmid, (void *) 0, 0); - if (data == (void *) (-1)) { - strcpy(k_error, "Can't open shmmem for writing."); - printf("ERROR\n"); - return 0; - } - - time_t modtime = time(NULL); - int nump = cont; - memcpy(data, &nump, sizeof(int)); - memcpy(data + 1, &modtime, sizeof(time_t)); - memcpy(data + 1 + sizeof(void *), &continuum, sizeof(mcs) * nump); - - /* We detach here because we will re-attach in read-only - * mode to actually use it. */ +static int ketama_create_continuum_libCacheSim( + const key_t key, const unsigned int num_servers, + const unsigned long *const weight) { + if (shm_ids == NULL) { + init_shm_id_tracker(); + } + + if (shm_data == NULL) { + init_shm_data_tracker(); + } + + unsigned int i, k, cont = 0; + int shmid; + int *data; /* Pointer to shmem location */ + unsigned long total_weight = 0; + serverinfo *slist = (serverinfo *)malloc(sizeof(serverinfo) * num_servers); + + // calculate total weight + if (weight != NULL) { + for (i = 0; i < num_servers; i++) total_weight += weight[i]; + } else + total_weight = num_servers; + + // fill in serverinfo + for (i = 0; i < num_servers; i++) { + /* all server ip are effective ID, begins from 0 */ + sprintf(slist[i].addr, "%d", i); + if (weight != NULL) + slist[i].memory = weight[i]; + else + slist[i].memory = 1; + } + + /* Continuum will hold one mcs for each point on the circle: */ + mcs continuum[num_servers * 160]; + + for (i = 0; i < num_servers; i++) { + float pct = (float)slist[i].memory / (float)total_weight; + unsigned int ks = (unsigned int)floorf(pct * 40.0f * (float)num_servers); + for (k = 0; k < ks; k++) { + /* 40 hashes, 4 numbers per hash = 160 points per server */ + char ss[30]; + unsigned char digest[16]; + + sprintf(ss, "%s-%d", slist[i].addr, k); + ketama_md5_digest(ss, digest); + + /* Use successive 4-bytes from hash as numbers + * for the points on the circle: */ + int h; + for (h = 0; h < 4; h++) { + continuum[cont].point = (digest[3 + h * 4] << 24) | + (digest[2 + h * 4] << 16) | + (digest[1 + h * 4] << 8) | digest[h * 4]; + + memcpy(continuum[cont].ip, slist[i].addr, 22); + cont++; + } + } + } + free(slist); + + /* Sorts in ascending order of "point" */ + qsort((void *)&continuum, cont, sizeof(mcs), (compfn)ketama_compare); + + /* Add data to shmmem */ + shmid = shmget(key, MC_SHMSIZE, 0644 | IPC_CREAT); + track_shm_id(shmid); + + data = (int *)shmat(shmid, (void *)0, 0); + if (data == (void *)(-1)) { + strcpy(k_error, "Can't open shmmem for writing."); + printf("ERROR\n"); + return 0; + } + + time_t modtime = time(NULL); + int nump = cont; + memcpy(data, &nump, sizeof(int)); + memcpy(data + 1, &modtime, sizeof(time_t)); + memcpy(data + 1 + sizeof(void *), &continuum, sizeof(mcs) * nump); + + /* We detach here because we will re-attach in read-only + * mode to actually use it. */ #ifdef SOLARIS - if ( shmdt( (char *) data ) == -1 ) + if (shmdt((char *)data) == -1) #else - if (shmdt(data) == -1) + if (shmdt(data) == -1) #endif - strcpy(k_error, "Error detaching from shared memory!"); + strcpy(k_error, "Error detaching from shared memory!"); - return 1; + return 1; } +int ketama_build_hashring(ketama_continuum *const contptr, + const unsigned int num_servers, + const unsigned long *const weight, + const int key_identifier) { + if (shm_ids == NULL) { + init_shm_id_tracker(); + } + + if (shm_data == NULL) { + init_shm_data_tracker(); + } + + strcpy(k_error, ""); + + key_t key; + int shmid; + int *data; + int sem_set_id; + + FILE *temp = fopen("/tmp/ketama", "w"); + fclose(temp); + + key = ftok("/tmp/ketama", key_identifier); + if (key == -1) { + set_error("failed to get shared memory key, key_identifier: %d", + key_identifier); + return 0; + } + + *contptr = (ketama_continuum)malloc(sizeof(continuum)); + (*contptr)->numpoints = 0; + (*contptr)->array = 0; + (*contptr)->modtime = 0; + + sem_set_id = ketama_sem_init(key); + + int sanity = 0; + while (semctl(sem_set_id, 0, GETVAL, 0) == 2) { + // wait for the continuum creator to finish, but don't block others + usleep(5); + + // if we are waiting for > 1 second, take drastic action: + if (++sanity > 1000000) { + usleep(rand() % 50000); + ketama_sem_unlock(sem_set_id); + break; + } + } + + time_t modtime = time(NULL); + time_t *fmodtime = 0; + while (!fmodtime || modtime != *fmodtime) { + shmid = shmget(key, MC_SHMSIZE, 0); // read only attempt. + track_shm_id(shmid); -int -ketama_build_hashring(ketama_continuum *const contptr, - const unsigned int num_servers, - const unsigned long *const weight, - const int key_identifier) { - - if (shm_ids == NULL) { - init_shm_id_tracker(); - } - - if (shm_data == NULL) { - init_shm_data_tracker(); - } - - strcpy(k_error, ""); - - key_t key; - int shmid; - int *data; - int sem_set_id; + data = (int *)shmat(shmid, (void *)0, SHM_RDONLY); - FILE *temp = fopen("/tmp/ketama", "w"); - fclose(temp); + if (data == (void *)(-1) || (*contptr)->modtime != 0) { + ketama_sem_lock(sem_set_id); - key = ftok("/tmp/ketama", key_identifier); - if (key == -1) { - set_error("failed to get shared memory key, key_identifier: %d", key_identifier); + if (!ketama_create_continuum_libCacheSim(key, num_servers, weight)) { + ketama_sem_unlock(sem_set_id); return 0; - } - - *contptr = (ketama_continuum) malloc(sizeof(continuum)); - (*contptr)->numpoints = 0; - (*contptr)->array = 0; - (*contptr)->modtime = 0; + } - sem_set_id = ketama_sem_init(key); + shmid = shmget(key, MC_SHMSIZE, 0); // read only attempt. + track_shm_id(shmid); - int sanity = 0; - while (semctl(sem_set_id, 0, GETVAL, 0) == 2) { - // wait for the continuum creator to finish, but don't block others - usleep(5); - - // if we are waiting for > 1 second, take drastic action: - if (++sanity > 1000000) { - usleep(rand() % 50000); - ketama_sem_unlock(sem_set_id); - break; - } + data = (int *)shmat(shmid, (void *)0, SHM_RDONLY); + ketama_sem_unlock(sem_set_id); } - time_t modtime = time(NULL); - time_t *fmodtime = 0; - while (!fmodtime || modtime != *fmodtime) { - shmid = shmget(key, MC_SHMSIZE, 0); // read only attempt. - track_shm_id(shmid); - - data = (int *) shmat(shmid, (void *) 0, SHM_RDONLY); - - if (data == (void *) (-1) || (*contptr)->modtime != 0) { - ketama_sem_lock(sem_set_id); - - if (!ketama_create_continuum_libCacheSim(key, num_servers, weight)) { - ketama_sem_unlock(sem_set_id); - return 0; - } - - shmid = shmget(key, MC_SHMSIZE, 0); // read only attempt. - track_shm_id(shmid); - - data = (int *) shmat(shmid, (void *) 0, SHM_RDONLY); - ketama_sem_unlock(sem_set_id); - } - - if (data == (void *) (-1)) { - strcpy(k_error, "Failed miserably to get pointer to shmemdata!"); - return 0; - } - - track_shm_data(data); - (*contptr)->numpoints = *data; - (*contptr)->modtime = ++data; // mod time is the second int in data - (*contptr)->array = data + sizeof(void *); - fmodtime = (time_t *) ((*contptr)->modtime); + if (data == (void *)(-1)) { + strcpy(k_error, "Failed miserably to get pointer to shmemdata!"); + return 0; } + + track_shm_data(data); + (*contptr)->numpoints = *data; + (*contptr)->modtime = ++data; // mod time is the second int in data + (*contptr)->array = data + sizeof(void *); + fmodtime = (time_t *)((*contptr)->modtime); + } #ifdef DEBUG - ketama_print_continuum(*contptr); + ketama_print_continuum(*contptr); #endif - return 1; + return 1; } +int ketama_get_server_index(const ketama_continuum cont, + const char *const key) { + unsigned int h = ketama_hashi(key); + int highp = cont->numpoints; + mcs(*mcsarr)[cont->numpoints] = (mcs(*)[cont->numpoints])cont->array; + int lowp = 0, midp; + unsigned int midval, midval1; -int -ketama_get_server_index(const ketama_continuum cont, const char *const key) { - unsigned int h = ketama_hashi(key); - int highp = cont->numpoints; - mcs (*mcsarr)[cont->numpoints] = (mcs (*)[cont->numpoints]) cont->array; - int lowp = 0, midp; - unsigned int midval, midval1; - - // divide and conquer array search to find server with next biggest - // point after what this key hashes to - while (1) { - midp = (int) ((lowp + highp) / 2); + // divide and conquer array search to find server with next biggest + // point after what this key hashes to + while (1) { + midp = (int)((lowp + highp) / 2); - if (midp == cont->numpoints) - return atoi((*mcsarr)[0].ip); // if at the end, roll back to zeroth + if (midp == cont->numpoints) + return atoi((*mcsarr)[0].ip); // if at the end, roll back to zeroth - midval = (*mcsarr)[midp].point; - midval1 = midp == 0 ? 0 : (*mcsarr)[midp - 1].point; + midval = (*mcsarr)[midp].point; + midval1 = midp == 0 ? 0 : (*mcsarr)[midp - 1].point; - if (h <= midval && h > midval1) - return atoi((*mcsarr)[midp].ip); + if (h <= midval && h > midval1) return atoi((*mcsarr)[midp].ip); - if (midval < h) - lowp = midp + 1; - else - highp = midp - 1; + if (midval < h) + lowp = midp + 1; + else + highp = midp - 1; - if (lowp > highp) - return atoi((*mcsarr)[0].ip); - } + if (lowp > highp) return atoi((*mcsarr)[0].ip); + } } - /* n: the number of servers that's going to retrieve */ -void ketama_get_server_indexes( - const ketama_continuum cont, - const char *const key, - unsigned int n, int *indexes) { - - size_t len = strlen(key); - char *temp = malloc(sizeof(char) * len + 2); - memcpy(temp, key, len); - temp[len + 1] = 0; - - unsigned int i = 0, j = 0; - int n_found=0, found_b = 0; - while (n_found < n) { - found_b = 0; - while (!found_b) { - temp[len] = (char) i; - indexes[n_found] = ketama_get_server_index(cont, temp); - found_b = 1; - for (j = 0; j < n_found; j++) { - if (indexes[j] == indexes[n_found]) { - found_b = 0; - break; - } - } - i++; +void ketama_get_server_indexes(const ketama_continuum cont, + const char *const key, unsigned int n, + int *indexes) { + size_t len = strlen(key); + char *temp = malloc(sizeof(char) * len + 2); + memcpy(temp, key, len); + temp[len + 1] = 0; + + unsigned int i = 0, j = 0; + int n_found = 0, found_b = 0; + while (n_found < n) { + found_b = 0; + while (!found_b) { + temp[len] = (char)i; + indexes[n_found] = ketama_get_server_index(cont, temp); + found_b = 1; + for (j = 0; j < n_found; j++) { + if (indexes[j] == indexes[n_found]) { + found_b = 0; + break; } - n_found++; - } -// if (i != n_found) -// printf("i %u n %u\n", i, n_found); - free(temp); + } + i++; + } + n_found++; + } + // if (i != n_found) + // printf("i %u n %u\n", i, n_found); + free(temp); } - diff --git a/example/cacheCluster/main.cpp b/example/cacheCluster/main.cpp index 747e1ac7..9135b98a 100644 --- a/example/cacheCluster/main.cpp +++ b/example/cacheCluster/main.cpp @@ -75,8 +75,10 @@ void simulate(int argc, char *argv[]) { n_req_byte += req->obj_size; } - std::cout << n_req << " requests, " << n_miss << " misses, miss ratio: " << (double)n_miss / n_req - << ", byte miss ratio: " << (double)n_miss_byte / n_req_byte << std::endl; + std::cout << n_req << " requests, " << n_miss + << " misses, miss ratio: " << (double)n_miss / n_req + << ", byte miss ratio: " << (double)n_miss_byte / n_req_byte + << std::endl; close_trace(reader); } diff --git a/example/cacheCluster/md5.c b/example/cacheCluster/md5.c index 9434249f..b76ffbe3 100644 --- a/example/cacheCluster/md5.c +++ b/example/cacheCluster/md5.c @@ -27,7 +27,7 @@ This code implements the MD5 Algorithm defined in RFC 1321, whose text is available at - http://www.ietf.org/rfc/rfc1321.txt + http://www.ietf.org/rfc/rfc1321.txt The code is derived from the text of the RFC, including the test suite (section A.5) but excluding the rest of Appendix A. It does not include any code or documentation that is identified in the RFC as being @@ -38,344 +38,328 @@ that follows (in reverse chronological order): 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order - either statically or dynamically; added missing #include - in library. + either statically or dynamically; added missing #include + in library. 2002-03-11 lpd Corrected argument list for main(), and added int return - type, in test program and T value program. + type, in test program and T value program. 2002-02-21 lpd Added missing #include in test program. 2000-07-03 lpd Patched to eliminate warnings about "constant is - unsigned in ANSI C, signed in traditional"; made test program - self-checking. + unsigned in ANSI C, signed in traditional"; made test program + self-checking. 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). 1999-05-03 lpd Original version. */ #include "include/md5.h" + #include -#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ +#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ #ifdef ARCH_IS_BIG_ENDIAN -# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) +#define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) #else -# define BYTE_ORDER 0 +#define BYTE_ORDER 0 #endif #define T_MASK ((md5_word_t)~0) #define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) #define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) -#define T3 0x242070db +#define T3 0x242070db #define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) #define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) -#define T6 0x4787c62a +#define T6 0x4787c62a #define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) #define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) -#define T9 0x698098d8 +#define T9 0x698098d8 #define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) #define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) #define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) -#define T13 0x6b901122 +#define T13 0x6b901122 #define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) #define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) -#define T16 0x49b40821 +#define T16 0x49b40821 #define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) #define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) -#define T19 0x265e5a51 +#define T19 0x265e5a51 #define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) #define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) -#define T22 0x02441453 +#define T22 0x02441453 #define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) #define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) -#define T25 0x21e1cde6 +#define T25 0x21e1cde6 #define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) #define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) -#define T28 0x455a14ed +#define T28 0x455a14ed #define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) #define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) -#define T31 0x676f02d9 +#define T31 0x676f02d9 #define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) #define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) #define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) -#define T35 0x6d9d6122 +#define T35 0x6d9d6122 #define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) #define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) -#define T38 0x4bdecfa9 +#define T38 0x4bdecfa9 #define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) #define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) -#define T41 0x289b7ec6 +#define T41 0x289b7ec6 #define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) #define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) -#define T44 0x04881d05 +#define T44 0x04881d05 #define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) #define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) -#define T47 0x1fa27cf8 +#define T47 0x1fa27cf8 #define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) #define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) -#define T50 0x432aff97 +#define T50 0x432aff97 #define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) #define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) -#define T53 0x655b59c3 +#define T53 0x655b59c3 #define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) #define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) #define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) -#define T57 0x6fa87e4f +#define T57 0x6fa87e4f #define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) #define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) -#define T60 0x4e0811a1 +#define T60 0x4e0811a1 #define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) #define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) -#define T63 0x2ad7d2bb +#define T63 0x2ad7d2bb #define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) - -static void -md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) -{ - md5_word_t - a = pms->abcd[0], b = pms->abcd[1], - c = pms->abcd[2], d = pms->abcd[3]; - md5_word_t t; +static void md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) { + md5_word_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2], + d = pms->abcd[3]; + md5_word_t t; #if BYTE_ORDER > 0 - /* Define storage only for big-endian CPUs. */ - md5_word_t X[16]; + /* Define storage only for big-endian CPUs. */ + md5_word_t X[16]; #else - /* Define storage for little-endian or both types of CPUs. */ - md5_word_t xbuf[16]; - const md5_word_t *X; + /* Define storage for little-endian or both types of CPUs. */ + md5_word_t xbuf[16]; + const md5_word_t *X; #endif - { + { #if BYTE_ORDER == 0 - /* - * Determine dynamically whether this is a big-endian or - * little-endian machine, since we can use a more efficient - * algorithm on the latter. - */ - static const int w = 1; - - if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ + /* + * Determine dynamically whether this is a big-endian or + * little-endian machine, since we can use a more efficient + * algorithm on the latter. + */ + static const int w = 1; + + if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ #endif -#if BYTE_ORDER <= 0 /* little-endian */ - { - /* - * On little-endian machines, we can process properly aligned - * data without copying it. - */ - if (!((data - (const md5_byte_t *)0) & 3)) { - /* data are properly aligned */ - X = (const md5_word_t *)data; - } else { - /* not aligned */ - memcpy(xbuf, data, 64); - X = xbuf; - } - } +#if BYTE_ORDER <= 0 /* little-endian */ + { + /* + * On little-endian machines, we can process properly aligned + * data without copying it. + */ + if (!((data - (const md5_byte_t *)0) & 3)) { + /* data are properly aligned */ + X = (const md5_word_t *)data; + } else { + /* not aligned */ + memcpy(xbuf, data, 64); + X = xbuf; + } + } #endif #if BYTE_ORDER == 0 - else /* dynamic big-endian */ + else /* dynamic big-endian */ #endif -#if BYTE_ORDER >= 0 /* big-endian */ - { - /* - * On big-endian machines, we must arrange the bytes in the - * right order. - */ - const md5_byte_t *xp = data; - int i; - -# if BYTE_ORDER == 0 - X = xbuf; /* (dynamic only) */ -# else -# define xbuf X /* (static only) */ -# endif - for (i = 0; i < 16; ++i, xp += 4) - xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); - } +#if BYTE_ORDER >= 0 /* big-endian */ + { + /* + * On big-endian machines, we must arrange the bytes in the + * right order. + */ + const md5_byte_t *xp = data; + int i; + +#if BYTE_ORDER == 0 + X = xbuf; /* (dynamic only) */ +#else +#define xbuf X /* (static only) */ #endif + for (i = 0; i < 16; ++i, xp += 4) + xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); } +#endif + } #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) - /* Round 1. */ - /* Let [abcd k s i] denote the operation - a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ + /* Round 1. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ #define F(x, y, z) (((x) & (y)) | (~(x) & (z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + F(b,c,d) + X[k] + Ti;\ +#define SET(a, b, c, d, k, s, Ti) \ + t = a + F(b, c, d) + X[k] + Ti; \ a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 0, 7, T1); - SET(d, a, b, c, 1, 12, T2); - SET(c, d, a, b, 2, 17, T3); - SET(b, c, d, a, 3, 22, T4); - SET(a, b, c, d, 4, 7, T5); - SET(d, a, b, c, 5, 12, T6); - SET(c, d, a, b, 6, 17, T7); - SET(b, c, d, a, 7, 22, T8); - SET(a, b, c, d, 8, 7, T9); - SET(d, a, b, c, 9, 12, T10); - SET(c, d, a, b, 10, 17, T11); - SET(b, c, d, a, 11, 22, T12); - SET(a, b, c, d, 12, 7, T13); - SET(d, a, b, c, 13, 12, T14); - SET(c, d, a, b, 14, 17, T15); - SET(b, c, d, a, 15, 22, T16); + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 7, T1); + SET(d, a, b, c, 1, 12, T2); + SET(c, d, a, b, 2, 17, T3); + SET(b, c, d, a, 3, 22, T4); + SET(a, b, c, d, 4, 7, T5); + SET(d, a, b, c, 5, 12, T6); + SET(c, d, a, b, 6, 17, T7); + SET(b, c, d, a, 7, 22, T8); + SET(a, b, c, d, 8, 7, T9); + SET(d, a, b, c, 9, 12, T10); + SET(c, d, a, b, 10, 17, T11); + SET(b, c, d, a, 11, 22, T12); + SET(a, b, c, d, 12, 7, T13); + SET(d, a, b, c, 13, 12, T14); + SET(c, d, a, b, 14, 17, T15); + SET(b, c, d, a, 15, 22, T16); #undef SET - /* Round 2. */ - /* Let [abcd k s i] denote the operation - a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ + /* Round 2. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ #define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + G(b,c,d) + X[k] + Ti;\ +#define SET(a, b, c, d, k, s, Ti) \ + t = a + G(b, c, d) + X[k] + Ti; \ a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 1, 5, T17); - SET(d, a, b, c, 6, 9, T18); - SET(c, d, a, b, 11, 14, T19); - SET(b, c, d, a, 0, 20, T20); - SET(a, b, c, d, 5, 5, T21); - SET(d, a, b, c, 10, 9, T22); - SET(c, d, a, b, 15, 14, T23); - SET(b, c, d, a, 4, 20, T24); - SET(a, b, c, d, 9, 5, T25); - SET(d, a, b, c, 14, 9, T26); - SET(c, d, a, b, 3, 14, T27); - SET(b, c, d, a, 8, 20, T28); - SET(a, b, c, d, 13, 5, T29); - SET(d, a, b, c, 2, 9, T30); - SET(c, d, a, b, 7, 14, T31); - SET(b, c, d, a, 12, 20, T32); + /* Do the following 16 operations. */ + SET(a, b, c, d, 1, 5, T17); + SET(d, a, b, c, 6, 9, T18); + SET(c, d, a, b, 11, 14, T19); + SET(b, c, d, a, 0, 20, T20); + SET(a, b, c, d, 5, 5, T21); + SET(d, a, b, c, 10, 9, T22); + SET(c, d, a, b, 15, 14, T23); + SET(b, c, d, a, 4, 20, T24); + SET(a, b, c, d, 9, 5, T25); + SET(d, a, b, c, 14, 9, T26); + SET(c, d, a, b, 3, 14, T27); + SET(b, c, d, a, 8, 20, T28); + SET(a, b, c, d, 13, 5, T29); + SET(d, a, b, c, 2, 9, T30); + SET(c, d, a, b, 7, 14, T31); + SET(b, c, d, a, 12, 20, T32); #undef SET - /* Round 3. */ - /* Let [abcd k s t] denote the operation - a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ + /* Round 3. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ #define H(x, y, z) ((x) ^ (y) ^ (z)) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + H(b,c,d) + X[k] + Ti;\ +#define SET(a, b, c, d, k, s, Ti) \ + t = a + H(b, c, d) + X[k] + Ti; \ a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 5, 4, T33); - SET(d, a, b, c, 8, 11, T34); - SET(c, d, a, b, 11, 16, T35); - SET(b, c, d, a, 14, 23, T36); - SET(a, b, c, d, 1, 4, T37); - SET(d, a, b, c, 4, 11, T38); - SET(c, d, a, b, 7, 16, T39); - SET(b, c, d, a, 10, 23, T40); - SET(a, b, c, d, 13, 4, T41); - SET(d, a, b, c, 0, 11, T42); - SET(c, d, a, b, 3, 16, T43); - SET(b, c, d, a, 6, 23, T44); - SET(a, b, c, d, 9, 4, T45); - SET(d, a, b, c, 12, 11, T46); - SET(c, d, a, b, 15, 16, T47); - SET(b, c, d, a, 2, 23, T48); + /* Do the following 16 operations. */ + SET(a, b, c, d, 5, 4, T33); + SET(d, a, b, c, 8, 11, T34); + SET(c, d, a, b, 11, 16, T35); + SET(b, c, d, a, 14, 23, T36); + SET(a, b, c, d, 1, 4, T37); + SET(d, a, b, c, 4, 11, T38); + SET(c, d, a, b, 7, 16, T39); + SET(b, c, d, a, 10, 23, T40); + SET(a, b, c, d, 13, 4, T41); + SET(d, a, b, c, 0, 11, T42); + SET(c, d, a, b, 3, 16, T43); + SET(b, c, d, a, 6, 23, T44); + SET(a, b, c, d, 9, 4, T45); + SET(d, a, b, c, 12, 11, T46); + SET(c, d, a, b, 15, 16, T47); + SET(b, c, d, a, 2, 23, T48); #undef SET - /* Round 4. */ - /* Let [abcd k s t] denote the operation - a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ + /* Round 4. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ #define I(x, y, z) ((y) ^ ((x) | ~(z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + I(b,c,d) + X[k] + Ti;\ +#define SET(a, b, c, d, k, s, Ti) \ + t = a + I(b, c, d) + X[k] + Ti; \ a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 0, 6, T49); - SET(d, a, b, c, 7, 10, T50); - SET(c, d, a, b, 14, 15, T51); - SET(b, c, d, a, 5, 21, T52); - SET(a, b, c, d, 12, 6, T53); - SET(d, a, b, c, 3, 10, T54); - SET(c, d, a, b, 10, 15, T55); - SET(b, c, d, a, 1, 21, T56); - SET(a, b, c, d, 8, 6, T57); - SET(d, a, b, c, 15, 10, T58); - SET(c, d, a, b, 6, 15, T59); - SET(b, c, d, a, 13, 21, T60); - SET(a, b, c, d, 4, 6, T61); - SET(d, a, b, c, 11, 10, T62); - SET(c, d, a, b, 2, 15, T63); - SET(b, c, d, a, 9, 21, T64); + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 6, T49); + SET(d, a, b, c, 7, 10, T50); + SET(c, d, a, b, 14, 15, T51); + SET(b, c, d, a, 5, 21, T52); + SET(a, b, c, d, 12, 6, T53); + SET(d, a, b, c, 3, 10, T54); + SET(c, d, a, b, 10, 15, T55); + SET(b, c, d, a, 1, 21, T56); + SET(a, b, c, d, 8, 6, T57); + SET(d, a, b, c, 15, 10, T58); + SET(c, d, a, b, 6, 15, T59); + SET(b, c, d, a, 13, 21, T60); + SET(a, b, c, d, 4, 6, T61); + SET(d, a, b, c, 11, 10, T62); + SET(c, d, a, b, 2, 15, T63); + SET(b, c, d, a, 9, 21, T64); #undef SET - /* Then perform the following additions. (That is increment each - of the four registers by the value it had before this block - was started.) */ - pms->abcd[0] += a; - pms->abcd[1] += b; - pms->abcd[2] += c; - pms->abcd[3] += d; + /* Then perform the following additions. (That is increment each + of the four registers by the value it had before this block + was started.) */ + pms->abcd[0] += a; + pms->abcd[1] += b; + pms->abcd[2] += c; + pms->abcd[3] += d; } -void -md5_init(md5_state_t *pms) -{ - pms->count[0] = pms->count[1] = 0; - pms->abcd[0] = 0x67452301; - pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; - pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; - pms->abcd[3] = 0x10325476; +void md5_init(md5_state_t *pms) { + pms->count[0] = pms->count[1] = 0; + pms->abcd[0] = 0x67452301; + pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; + pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; + pms->abcd[3] = 0x10325476; } -void -md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) -{ - const md5_byte_t *p = data; - int left = nbytes; - int offset = (pms->count[0] >> 3) & 63; - md5_word_t nbits = (md5_word_t)(nbytes << 3); - - if (nbytes <= 0) - return; - - /* Update the message length. */ - pms->count[1] += nbytes >> 29; - pms->count[0] += nbits; - if (pms->count[0] < nbits) - pms->count[1]++; - - /* Process an initial partial block. */ - if (offset) { - int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); - - memcpy(pms->buf + offset, p, copy); - if (offset + copy < 64) - return; - p += copy; - left -= copy; - md5_process(pms, pms->buf); - } +void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) { + const md5_byte_t *p = data; + int left = nbytes; + int offset = (pms->count[0] >> 3) & 63; + md5_word_t nbits = (md5_word_t)(nbytes << 3); + + if (nbytes <= 0) return; + + /* Update the message length. */ + pms->count[1] += nbytes >> 29; + pms->count[0] += nbits; + if (pms->count[0] < nbits) pms->count[1]++; + + /* Process an initial partial block. */ + if (offset) { + int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); + + memcpy(pms->buf + offset, p, copy); + if (offset + copy < 64) return; + p += copy; + left -= copy; + md5_process(pms, pms->buf); + } - /* Process full blocks. */ - for (; left >= 64; p += 64, left -= 64) - md5_process(pms, p); + /* Process full blocks. */ + for (; left >= 64; p += 64, left -= 64) md5_process(pms, p); - /* Process a final partial block. */ - if (left) - memcpy(pms->buf, p, left); + /* Process a final partial block. */ + if (left) memcpy(pms->buf, p, left); } -void -md5_finish(md5_state_t *pms, md5_byte_t digest[16]) -{ - static const md5_byte_t pad[64] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - md5_byte_t data[8]; - int i; - - /* Save the length before padding. */ - for (i = 0; i < 8; ++i) - data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); - /* Pad to 56 bytes mod 64. */ - md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); - /* Append the length. */ - md5_append(pms, data, 8); - for (i = 0; i < 16; ++i) - digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); +void md5_finish(md5_state_t *pms, md5_byte_t digest[16]) { + static const md5_byte_t pad[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + md5_byte_t data[8]; + int i; + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) + data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); + /* Pad to 56 bytes mod 64. */ + md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); + /* Append the length. */ + md5_append(pms, data, 8); + for (i = 0; i < 16; ++i) + digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); } diff --git a/example/cacheHierarchy/CMakeLists.txt b/example/cacheHierarchy/CMakeLists.txt index 3b7d47df..63d17873 100644 --- a/example/cacheHierarchy/CMakeLists.txt +++ b/example/cacheHierarchy/CMakeLists.txt @@ -28,3 +28,15 @@ target_link_libraries(layeredCache -Wl,--no-whole-archive dl m ${GLib_LIBRARY} ${ZSTD_LIBRARIES} pthread) +# Skip unsupported linker options for macOS (whole-archive, no-whole-archive) +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + target_link_libraries(layeredCache + -Wl,--whole-archive + libCacheSim + -Wl,--no-whole-archive + dl m ${GLib_LIBRARY} ${ZSTD_LIBRARIES} pthread) +elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + target_link_libraries(layeredCache + libCacheSim + dl m ${GLib_LIBRARY} ${ZSTD_LIBRARIES} pthread) +endif() diff --git a/example/cacheHierarchy/fkYAML/node.hpp b/example/cacheHierarchy/fkYAML/node.hpp index d8bcf4a4..b3b317ac 100644 --- a/example/cacheHierarchy/fkYAML/node.hpp +++ b/example/cacheHierarchy/fkYAML/node.hpp @@ -1,7 +1,8 @@ // _______ __ __ __ _____ __ __ __ -// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML library -// | __| _ < \_ _/| ___ | _ | |___ version 0.4.2 -// |__| |_| \__| |_| |_| |_|___||___|______| https://github.com/fktn-k/fkYAML +// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML +// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2 +// |__| |_| \__| |_| |_| |_|___||___|______| +// https://github.com/fktn-k/fkYAML // // SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani // SPDX-License-Identifier: MIT @@ -21,9 +22,10 @@ // #include // _______ __ __ __ _____ __ __ __ -// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML library -// | __| _ < \_ _/| ___ | _ | |___ version 0.4.2 -// |__| |_| \__| |_| |_| |_|___||___|______| https://github.com/fktn-k/fkYAML +// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML +// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2 +// |__| |_| \__| |_| |_| |_|___||___|______| +// https://github.com/fktn-k/fkYAML // // SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani // SPDX-License-Identifier: MIT @@ -33,16 +35,19 @@ // #include // _______ __ __ __ _____ __ __ __ -// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML library -// | __| _ < \_ _/| ___ | _ | |___ version 0.4.2 -// |__| |_| \__| |_| |_| |_|___||___|______| https://github.com/fktn-k/fkYAML +// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML +// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2 +// |__| |_| \__| |_| |_| |_|___||___|______| +// https://github.com/fktn-k/fkYAML // // SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani // SPDX-License-Identifier: MIT // Check version definitions if already defined. -#if defined(FK_YAML_MAJOR_VERSION) && defined(FK_YAML_MINOR_VERSION) && defined(FK_YAML_PATCH_VERSION) -#if FK_YAML_MAJOR_VERSION != 0 || FK_YAML_MINOR_VERSION != 4 || FK_YAML_PATCH_VERSION != 2 +#if defined(FK_YAML_MAJOR_VERSION) && defined(FK_YAML_MINOR_VERSION) && \ + defined(FK_YAML_PATCH_VERSION) +#if FK_YAML_MAJOR_VERSION != 0 || FK_YAML_MINOR_VERSION != 4 || \ + FK_YAML_PATCH_VERSION != 2 #warning Already included a different version of the fkYAML library! #else // define macros to skip defining macros down below. @@ -56,36 +61,40 @@ #define FK_YAML_MINOR_VERSION 4 #define FK_YAML_PATCH_VERSION 2 -#define FK_YAML_NAMESPACE_VERSION_CONCAT_IMPL(major, minor, patch) v##major##_##minor##_##patch +#define FK_YAML_NAMESPACE_VERSION_CONCAT_IMPL(major, minor, patch) \ + v##major##_##minor##_##patch -#define FK_YAML_NAMESPACE_VERSION_CONCAT(major, minor, patch) FK_YAML_NAMESPACE_VERSION_CONCAT_IMPL(major, minor, patch) +#define FK_YAML_NAMESPACE_VERSION_CONCAT(major, minor, patch) \ + FK_YAML_NAMESPACE_VERSION_CONCAT_IMPL(major, minor, patch) -#define FK_YAML_NAMESPACE_VERSION \ - FK_YAML_NAMESPACE_VERSION_CONCAT(FK_YAML_MAJOR_VERSION, FK_YAML_MINOR_VERSION, FK_YAML_PATCH_VERSION) +#define FK_YAML_NAMESPACE_VERSION \ + FK_YAML_NAMESPACE_VERSION_CONCAT( \ + FK_YAML_MAJOR_VERSION, FK_YAML_MINOR_VERSION, FK_YAML_PATCH_VERSION) -#define FK_YAML_NAMESPACE_BEGIN \ - namespace fkyaml { \ - inline namespace FK_YAML_NAMESPACE_VERSION { +#define FK_YAML_NAMESPACE_BEGIN \ + namespace fkyaml { \ + inline namespace FK_YAML_NAMESPACE_VERSION { -#define FK_YAML_NAMESPACE_END \ - } /* inline namespace FK_YAML_NAMESPACE_VERSION */ \ - } // namespace fkyaml +#define FK_YAML_NAMESPACE_END \ + } /* inline namespace FK_YAML_NAMESPACE_VERSION */ \ + } // namespace fkyaml -#define FK_YAML_DETAIL_NAMESPACE_BEGIN \ - FK_YAML_NAMESPACE_BEGIN \ - namespace detail { +#define FK_YAML_DETAIL_NAMESPACE_BEGIN \ + FK_YAML_NAMESPACE_BEGIN \ + namespace detail { -#define FK_YAML_DETAIL_NAMESPACE_END \ - } /* namespace detail */ \ - FK_YAML_NAMESPACE_END +#define FK_YAML_DETAIL_NAMESPACE_END \ + } /* namespace detail */ \ + FK_YAML_NAMESPACE_END -#endif // !defined(FK_YAML_VERCHECK_SUCCEEDED) +#endif // !defined(FK_YAML_VERCHECK_SUCCEEDED) // #include // _______ __ __ __ _____ __ __ __ -// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML library -// | __| _ < \_ _/| ___ | _ | |___ version 0.4.2 -// |__| |_| \__| |_| |_| |_|___||___|______| https://github.com/fktn-k/fkYAML +// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML +// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2 +// |__| |_| \__| |_| |_| |_|___||___|______| +// https://github.com/fktn-k/fkYAML // // SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani // SPDX-License-Identifier: MIT @@ -94,11 +103,14 @@ #define FK_YAML_DETAIL_MACROS_CPP_CONFIG_MACROS_HPP // This file is assumed to be included only by version_macros.hpp file. -// To avoid redundant inclusion, do not include version_macros.hpp file as the other files do. - -// With the MSVC compilers, the value of __cplusplus is by default always "199611L"(C++98). -// To avoid that, the library instead references _MSVC_LANG which is always set a correct value. -// See https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/ for more details. +// To avoid redundant inclusion, do not include version_macros.hpp file as the +// other files do. + +// With the MSVC compilers, the value of __cplusplus is by default always +// "199611L"(C++98). To avoid that, the library instead references _MSVC_LANG +// which is always set a correct value. See +// https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/ +// for more details. #if defined(_MSVC_LANG) && !defined(__clang__) #define FK_YAML_CPLUSPLUS _MSVC_LANG #else @@ -107,8 +119,9 @@ // C++ language standard detection // Skip detection if the definitions listed below already exist. -#if !defined(FK_YAML_HAS_CXX_23) && !defined(FK_YAML_HAS_CXX_20) && !defined(FK_YAML_HAS_CXX_17) && \ - !defined(FK_YAML_HAS_CXX_14) && !defined(FK_YAML_CXX_11) +#if !defined(FK_YAML_HAS_CXX_23) && !defined(FK_YAML_HAS_CXX_20) && \ + !defined(FK_YAML_HAS_CXX_17) && !defined(FK_YAML_HAS_CXX_14) && \ + !defined(FK_YAML_CXX_11) #if FK_YAML_CPLUSPLUS >= 202302L #define FK_YAML_HAS_CXX_23 #define FK_YAML_HAS_CXX_20 @@ -129,7 +142,8 @@ #define FK_YAML_HAS_CXX_11 #endif -// switch usage of the deprecated attribute. [[deprecated]] is available since C++14. +// switch usage of the deprecated attribute. [[deprecated]] is available since +// C++14. #if defined(FK_YAML_HAS_CXX_14) #define FK_YAML_DEPRECATED(msg) [[deprecated(msg)]] #else @@ -183,7 +197,8 @@ #define FK_YAML_HAS_FEATURE(feat) (0) #endif -// switch usage of the no_sanitize attribute only when Clang sanitizer is active. +// switch usage of the no_sanitize attribute only when Clang sanitizer is +// active. #if defined(__clang__) && FK_YAML_HAS_FEATURE(address_sanitizer) #define FK_YAML_NO_SANITIZE(...) __attribute__((no_sanitize(__VA_ARGS__))) #else @@ -199,15 +214,18 @@ // C++ feature detections // -// switch usages of the std::to_chars()/std::from_chars() functions which have been available since C++17. -#if defined(FK_YAML_HAS_CXX_17) && defined(__cpp_lib_to_chars) && __cpp_lib_to_chars >= 201611L +// switch usages of the std::to_chars()/std::from_chars() functions which have +// been available since C++17. +#if defined(FK_YAML_HAS_CXX_17) && defined(__cpp_lib_to_chars) && \ + __cpp_lib_to_chars >= 201611L #define FK_YAML_HAS_TO_CHARS (1) #else #define FK_YAML_HAS_TO_CHARS (0) #endif // switch usage of char8_t which has been available since C++20. -#if defined(FK_YAML_HAS_CXX_20) && defined(__cpp_char8_t) && __cpp_char8_t >= 201811L +#if defined(FK_YAML_HAS_CXX_20) && defined(__cpp_char8_t) && \ + __cpp_char8_t >= 201811L #define FK_YAML_HAS_CHAR8_T (1) #else #define FK_YAML_HAS_CHAR8_T (0) @@ -217,7 +235,8 @@ // utility macros // -// switch usage of [[likely]] C++ attribute which has been available since C++20. +// switch usage of [[likely]] C++ attribute which has been available since +// C++20. #if defined(FK_YAML_HAS_CXX_20) && FK_YAML_HAS_CPP_ATTRIBUTE(likely) >= 201803L #define FK_YAML_LIKELY(expr) (!!(expr)) [[likely]] #elif FK_YAML_HAS_BUILTIN(__builtin_expect) @@ -226,8 +245,10 @@ #define FK_YAML_LIKELY(expr) (!!(expr)) #endif -// switch usage of [[unlikely]] C++ attribute which has been available since C++20. -#if defined(FK_YAML_HAS_CXX_20) && FK_YAML_HAS_CPP_ATTRIBUTE(unlikely) >= 201803L +// switch usage of [[unlikely]] C++ attribute which has been available since +// C++20. +#if defined(FK_YAML_HAS_CXX_20) && \ + FK_YAML_HAS_CPP_ATTRIBUTE(unlikely) >= 201803L #define FK_YAML_UNLIKELY(expr) (!!(expr)) [[unlikely]] #elif FK_YAML_HAS_BUILTIN(__builtin_expect) #define FK_YAML_UNLIKELY(expr) (__builtin_expect(!!(expr), 0)) @@ -237,14 +258,14 @@ #endif /* FK_YAML_DETAIL_MACROS_CPP_CONFIG_MACROS_HPP */ - #endif /* FK_YAML_DETAIL_MACROS_DEFINE_MACROS_HPP */ // #include // _______ __ __ __ _____ __ __ __ -// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML library -// | __| _ < \_ _/| ___ | _ | |___ version 0.4.2 -// |__| |_| \__| |_| |_| |_|___||___|______| https://github.com/fktn-k/fkYAML +// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML +// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2 +// |__| |_| \__| |_| |_| |_|___||___|______| +// https://github.com/fktn-k/fkYAML // // SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani // SPDX-License-Identifier: MIT @@ -266,9 +287,10 @@ // #include // _______ __ __ __ _____ __ __ __ -// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML library -// | __| _ < \_ _/| ___ | _ | |___ version 0.4.2 -// |__| |_| \__| |_| |_| |_|___||___|______| https://github.com/fktn-k/fkYAML +// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML +// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2 +// |__| |_| \__| |_| |_| |_|___||___|______| +// https://github.com/fktn-k/fkYAML // // SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani // SPDX-License-Identifier: MIT @@ -276,16 +298,17 @@ #ifndef FK_YAML_DETAIL_DOCUMENT_METAINFO_HPP #define FK_YAML_DETAIL_DOCUMENT_METAINFO_HPP -#include #include +#include // #include // #include // _______ __ __ __ _____ __ __ __ -// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML library -// | __| _ < \_ _/| ___ | _ | |___ version 0.4.2 -// |__| |_| \__| |_| |_| |_|___||___|______| https://github.com/fktn-k/fkYAML +// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML +// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2 +// |__| |_| \__| |_| |_| |_|___||___|______| +// https://github.com/fktn-k/fkYAML // // SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani // SPDX-License-Identifier: MIT @@ -297,9 +320,10 @@ // #include // _______ __ __ __ _____ __ __ __ -// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML library -// | __| _ < \_ _/| ___ | _ | |___ version 0.4.2 -// |__| |_| \__| |_| |_| |_|___||___|______| https://github.com/fktn-k/fkYAML +// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML +// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2 +// |__| |_| \__| |_| |_| |_|___||___|______| +// https://github.com/fktn-k/fkYAML // // SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani // SPDX-License-Identifier: MIT @@ -314,9 +338,10 @@ // #include // _______ __ __ __ _____ __ __ __ -// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML library -// | __| _ < \_ _/| ___ | _ | |___ version 0.4.2 -// |__| |_| \__| |_| |_| |_|___||___|______| https://github.com/fktn-k/fkYAML +// | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML +// library | __| _ < \_ _/| ___ | _ | |___ version 0.4.2 +// |__| |_| \__| |_| |_| |_|___||___|______| +// https://github.com/fktn-k/fkYAML // // SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani // SPDX-License-Identifier: MIT @@ -329,7 +354,6 @@ // #include - #ifdef FK_YAML_HAS_CXX_14 #include #endif @@ -338,11 +362,11 @@ FK_YAML_DETAIL_NAMESPACE_BEGIN ///////////////////////////////////////////////////////////////////////////////////////////////////////// // For contributors: -// This file is for supplementing future C++ STL implementations to utilize some useful features -// implemented in C++14 or better. -// This file is needed to keep the fkYAML library requirement to C++11. -// **DO NOT** implement features which are not included any version of STL in this file. -// Such implementations must be in the type_traits.hpp file. +// This file is for supplementing future C++ STL implementations to utilize +// some useful features implemented in C++14 or better. This file is needed +// to keep the fkYAML library requirement to C++11. +// **DO NOT** implement features which are not included any version of STL +// in this file. Such implementations must be in the type_traits.hpp file. ///////////////////////////////////////////////////////////////////////////////////////////////////////// #ifndef FK_YAML_HAS_CXX_14 @@ -367,7 +391,8 @@ using enable_if_t = typename std::enable_if::type; /// @sa https://en.cppreference.com/w/cpp/types/is_null_pointer /// @tparam T The type to be checked if it's equal to std::nullptr_t. template -struct is_null_pointer : std::is_same::type> {}; +struct is_null_pointer + : std::is_same::type> {}; /// @brief An alias template for std::remove_cv::type with C++11. /// @note std::remove_cv_t is available since C++14. @@ -392,13 +417,12 @@ using remove_reference_t = typename std::remove_reference::type; template struct integer_sequence { - using value_type = T; - static constexpr std::size_t size() noexcept { - return sizeof...(I); - } + using value_type = T; + static constexpr std::size_t size() noexcept { return sizeof...(I); } }; -#if !FK_YAML_HAS_BUILTIN(__make_integer_seq) && !FK_YAML_HAS_BUILTIN(__integer_pack) +#if !FK_YAML_HAS_BUILTIN(__make_integer_seq) && \ + !FK_YAML_HAS_BUILTIN(__integer_pack) namespace make_int_seq_impl { @@ -407,37 +431,39 @@ struct merger; template struct merger, integer_sequence> { - using type = integer_sequence; + using type = integer_sequence; }; template struct generator { - using type = - typename merger::type, typename generator::type>::type; + using type = + typename merger::type, + typename generator::type>::type; }; template struct generator { - using type = integer_sequence; + using type = integer_sequence; }; template struct generator { - using type = integer_sequence; + using type = integer_sequence; }; -} // namespace make_int_seq_impl +} // namespace make_int_seq_impl #endif template using make_integer_sequence #if FK_YAML_HAS_BUILTIN(__make_integer_seq) - // clang defines built-in __make_integer_seq to generate an integer sequence. + // clang defines built-in __make_integer_seq to generate an integer + // sequence. = __make_integer_seq; #elif FK_YAML_HAS_BUILTIN(__integer_pack) - // GCC or other compilers may implement built-in __integer_pack to generate an - // integer sequence. + // GCC or other compilers may implement built-in __integer_pack to generate + // an integer sequence. = integer_sequence; #else // fallback to the library implementation of make_integer_sequence. @@ -453,7 +479,7 @@ using make_index_sequence = make_integer_sequence; template using index_sequence_for = make_index_sequence; -#else // !defined(FK_YAML_HAS_CXX_14) +#else // !defined(FK_YAML_HAS_CXX_14) using std::add_pointer_t; using std::enable_if_t; @@ -467,7 +493,7 @@ using std::remove_cv_t; using std::remove_pointer_t; using std::remove_reference_t; -#endif // !defined(FK_YAML_HAS_CXX_14) +#endif // !defined(FK_YAML_HAS_CXX_14) #ifndef FK_YAML_HAS_CXX_17 @@ -490,18 +516,22 @@ struct conjunction : std::true_type {}; template struct conjunction : Trait {}; -/// @brief A partial specialization of conjunction if more than one traits are given. +/// @brief A partial specialization of conjunction if more than one traits are +/// given. /// @tparam First The first type trait to be checked if its ::value is true. -/// @tparam Rest The rest of traits passed as another conjunction template arguments if First::value is true. +/// @tparam Rest The rest of traits passed as another conjunction template +/// arguments if First::value is true. template -struct conjunction : std::conditional, First>::type {}; +struct conjunction + : std::conditional, First>::type {}; /// @brief A simple implementation to use std::disjunction with C++11/C++14. /// @note /// std::disjunction is available since C++17. /// This is applied when no traits are specified as inputs. /// @sa https://en.cppreference.com/w/cpp/types/disjunction -/// @tparam Traits Type traits to be checked if at least one of their ::value is true. +/// @tparam Traits Type traits to be checked if at least one of their ::value is +/// true. template struct disjunction : std::false_type {}; @@ -510,11 +540,14 @@ struct disjunction : std::false_type {}; template struct disjunction : Trait {}; -/// @brief A partial specialization of disjunction if more than one traits are given. +/// @brief A partial specialization of disjunction if more than one traits are +/// given. /// @tparam First The first type trait to be checked if its ::value is true. -/// @tparam Rest The rest of traits passed as another conjunction template arguments if First::value is false. +/// @tparam Rest The rest of traits passed as another conjunction template +/// arguments if First::value is false. template -struct disjunction : std::conditional>::type {}; +struct disjunction + : std::conditional>::type {}; /// @brief A simple implementation to use std::negation with C++11/C++14. /// @note std::negation is available since C++17. @@ -527,7 +560,7 @@ struct negation : std::integral_constant {}; /// @tparam Types Any types to be transformed to void type. template struct make_void { - using type = void; + using type = void; }; /// @brief A simple implementation to use std::void_t with C++11/C++14. @@ -537,7 +570,7 @@ struct make_void { template using void_t = typename make_void::type; -#else // !defined(FK_YAML_HAS_CXX_17) +#else // !defined(FK_YAML_HAS_CXX_17) using std::bool_constant; using std::conjunction; @@ -545,16 +578,18 @@ using std::disjunction; using std::negation; using std::void_t; -#endif // !defined(FK_YAML_HAS_CXX_17) +#endif // !defined(FK_YAML_HAS_CXX_17) #ifndef FK_YAML_HAS_CXX_20 -/// @brief A simple implementation to use std::remove_cvref_t with C++11/C++14/C++17. +/// @brief A simple implementation to use std::remove_cvref_t with +/// C++11/C++14/C++17. /// @note std::remove_cvref & std::remove_cvref_t are available since C++20. /// @sa https://en.cppreference.com/w/cpp/types/remove_cvref /// @tparam T A type from which cv-qualifiers and reference are removed. template -using remove_cvref_t = typename std::remove_cv::type>::type; +using remove_cvref_t = + typename std::remove_cv::type>::type; #else @@ -562,20 +597,23 @@ using std::remove_cvref_t; #endif -/// @brief A wrapper function to call std::unreachable() (since C++23) or similar compiler specific extensions. -/// @note This function is implemented only for better code optimization against dead code and thus excluded from -/// coverage report. +/// @brief A wrapper function to call std::unreachable() (since C++23) or +/// similar compiler specific extensions. +/// @note This function is implemented only for better code optimization against +/// dead code and thus excluded from coverage report. // LCOV_EXCL_START [[noreturn]] inline void unreachable() { - // use compiler specific extensions if possible. - // undefined behavior should be raised by an empty function with noreturn attribute. - -#if defined(FK_YAML_HAS_CXX_23) || (defined(__cpp_lib_unreachable) && __cpp_lib_unreachable >= 202202L) - std::unreachable(); -#elif defined(_MSC_VER) && !defined(__clang__) // MSVC - __assume(false); + // use compiler specific extensions if possible. + // undefined behavior should be raised by an empty function with noreturn + // attribute. + +#if defined(FK_YAML_HAS_CXX_23) || \ + (defined(__cpp_lib_unreachable) && __cpp_lib_unreachable >= 202202L) + std::unreachable(); +#elif defined(_MSC_VER) && !defined(__clang__) // MSVC + __assume(false); #else - __builtin_unreachable(); + __builtin_unreachable(); #endif } // LCOV_EXCL_STOP @@ -584,17 +622,16 @@ FK_YAML_DETAIL_NAMESPACE_END #endif /* FK_YAML_DETAIL_META_STL_SUPPLEMENT_HPP */ - FK_YAML_DETAIL_NAMESPACE_BEGIN /// @brief A dummy struct to represent detection failure. struct nonesuch { - nonesuch() = delete; - ~nonesuch() = delete; - nonesuch(const nonesuch&) = delete; - nonesuch(nonesuch&&) = delete; - nonesuch& operator=(const nonesuch&) = delete; - nonesuch& operator=(nonesuch&&) = delete; + nonesuch() = delete; + ~nonesuch() = delete; + nonesuch(const nonesuch&) = delete; + nonesuch(nonesuch&&) = delete; + nonesuch& operator=(const nonesuch&) = delete; + nonesuch& operator=(nonesuch&&) = delete; }; /// @brief namespace to implement detector type traits @@ -605,23 +642,25 @@ namespace detector_impl { /// @tparam AlwaysVoid This must be void type. /// @tparam Op A type for desired operation type. /// @tparam Args Argument types passed to desired operation. -template class Op, typename... Args> +template class Op, typename... Args> struct detector : std::false_type { - /// @brief A type which represents detection failure. - using type = Default; + /// @brief A type which represents detection failure. + using type = Default; }; -/// @brief A partial specialization of detector if desired operation type is found. +/// @brief A partial specialization of detector if desired operation type is +/// found. /// @tparam Default A type to represent detection failure. /// @tparam Op A type for desired operation type. /// @tparam Args Argument types passed to desired operation. template class Op, typename... Args> struct detector>, Op, Args...> : std::true_type { - /// @brief A detected type. - using type = Op; + /// @brief A detected type. + using type = Op; }; -} // namespace detector_impl +} // namespace detector_impl /// @brief Type traits to detect Op operation with Args argument types /// @tparam Op A desired operation type. @@ -633,9 +672,11 @@ using is_detected = detector_impl::detector; /// @tparam Op A type for desired operation type. /// @tparam Args Argument types passed to desired operation. template