Commit 2c905f00 by Danila Klimenko

Added a generator for the chromatic tree rebalancing routines.

parent 028a03b5
......@@ -12,12 +12,25 @@ GroupSourcesMSVC(test)
set (EMBB_CONTAINERS_CPP_INCLUDE_DIRS "include" "src" "test")
include_directories(${EMBB_CONTAINERS_CPP_INCLUDE_DIRS}
${CMAKE_CURRENT_BINARY_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/../base_c/include
${CMAKE_CURRENT_BINARY_DIR}/../base_c/include
${CMAKE_CURRENT_SOURCE_DIR}/../base_cpp/include
${CMAKE_CURRENT_BINARY_DIR}/../base_cpp/include)
add_library (embb_containers_cpp ${EMBB_CONTAINERS_CPP_SOURCES} ${EMBB_CONTAINERS_CPP_HEADERS})
add_subdirectory(generator)
set(GENERATOR_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/include/embb/containers/internal)
set(CHROMATIC_TREE_GENERATED_HEADER ${GENERATOR_OUTPUT_DIR}/lock_free_chromatic_tree-rebalance.h)
file(MAKE_DIRECTORY ${GENERATOR_OUTPUT_DIR})
add_custom_command (
OUTPUT ${CHROMATIC_TREE_GENERATED_HEADER}
COMMAND chromatic_tree_generator ${CHROMATIC_TREE_GENERATED_HEADER}
DEPENDS chromatic_tree_generator
)
add_library (embb_containers_cpp ${EMBB_CONTAINERS_CPP_SOURCES} ${EMBB_CONTAINERS_CPP_HEADERS}
${CHROMATIC_TREE_GENERATED_HEADER})
target_link_libraries(embb_containers_cpp embb_base_cpp)
if (BUILD_TESTS STREQUAL ON)
......@@ -30,4 +43,5 @@ endif()
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/embb
DESTINATION include FILES_MATCHING PATTERN "*.h")
install(FILES ${CHROMATIC_TREE_GENERATED_HEADER} DESTINATION include/embb/containers/internal)
install(TARGETS embb_containers_cpp DESTINATION lib)
add_executable(chromatic_tree_generator chromatic_tree_generator.cc chromatic_tree_operations.h)
/*
* Copyright (c) 2014-2015, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "chromatic_tree_operations.h"
static const char INCLUDE_GUARD[] =
"EMBB_CONTAINERS_INTERNAL_LOCK_FREE_CHROMATIC_TREE_REBALANCE_H_";
static const char GENERATOR_NOTICE[] =
"//\n"
"// This file was created automatically by a code generator.\n"
"// Any direct changes will be lost after rebuild of the project.\n"
"//";
static const char RETURN_TYPE[] = "embb_errors_t";
static const char NODEARG_TYPE[] = "HazardNodePtr";
static const char LOCKARG_TYPE[] = "HazardOperationPtr";
static const char NEWNODE_TYPE[] = "Node*";
void PrintOperationSourceCode(FILE* file, const RebalancingOperation& op);
int main(int argc, char* argv[]) {
if (argc != 2) {
fprintf(stderr, "USAGE:\n %s <output_file>\n", argv[0]);
return 1;
}
const char* filename = argv[1];
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4996)
#endif
FILE *file = fopen(filename, "w");
#ifdef _MSC_VER
#pragma warning(pop)
#endif
if (file == NULL) {
fprintf(stderr, "Error: Cannot open file '%s' for writing!\n", filename);
return 1;
}
// Printing header
fprintf(file, "#ifndef %s\n#define %s\n\n", INCLUDE_GUARD, INCLUDE_GUARD);
fprintf(file, "%s\n\n", GENERATOR_NOTICE);
// Printing methods code
int num_operations = (sizeof(REBALANCING_OPERATIONS) /
sizeof(REBALANCING_OPERATIONS[0]));
for (int i = 0; i < num_operations; ++i) {
PrintOperationSourceCode(file, REBALANCING_OPERATIONS[i]);
}
// Printing trailer
fprintf(file, "#endif // %s\n", INCLUDE_GUARD);
fclose(file);
return 0;
}
void PrintOperationSourceCode(FILE* file, const RebalancingOperation& op) {
// Method signature
fprintf(file, "%s %s(", RETURN_TYPE, op.name);
// Method arguments
fprintf(file, "%s& u, %s& u_op", NODEARG_TYPE, LOCKARG_TYPE);
int offset = static_cast<int>(strlen(NODEARG_TYPE) + strlen(op.name) + 2);
for (int i = 0; i < op.num_nodes; ++i) {
fprintf(file, ",\n%*s%s& %s, %s& %s_op", offset, "",
NODEARG_TYPE, op.old_nodes[i].name,
LOCKARG_TYPE, op.old_nodes[i].name);
}
fprintf(file, ") {\n"
" embb_errors_t result = EMBB_NOMEM;\n");
// Define nodes
for (int i = 0; i < op.num_nodes; ++i) {
fprintf(file, " %s %s = NULL;\n", NEWNODE_TYPE, op.new_nodes[i].name);
}
fprintf(file, "\n"
" while (result != EMBB_SUCCESS) {\n");
// Construct new nodes
for (int i = 0; i < op.num_nodes; ++i) {
fprintf(file, " %s = node_pool_.Allocate(\n"
" %s->GetKey(), %s->GetValue(), %s,\n"
" %s, %s, Operation::INITIAL_DUMMY);\n"
" if (%s == NULL) break;\n",
op.new_nodes[i].name,
op.new_nodes[i].orig_node, op.new_nodes[i].orig_node,
op.new_nodes[i].weight,
op.new_nodes[i].left, op.new_nodes[i].right,
op.new_nodes[i].name);
}
fprintf(file, "\n"
" HazardOperationPtr op(GetOperationGuard(HIDX_CURRENT_OP));\n"
" op.ProtectSafe(operation_pool_.Allocate());\n"
" if (op == NULL) break;\n");
// Create and fill the operation object
fprintf(file, "\n"
" op->SetRoot(u, u_op);\n"
" op->SetNewChild(nx);\n"
" op->SetOldNodes(%s, %s_op",
op.old_nodes[0].name, op.old_nodes[0].name);
for (int i = 1; i < op.num_nodes; ++i) {
fprintf(file, ",\n %s, %s_op",
op.old_nodes[i].name, op.old_nodes[i].name);
}
fprintf(file, ");\n");
// Execute operation
fprintf(file, "\n"
" bool succeeded = op->Help(GetNodeGuard(HIDX_HELPING),\n"
" GetOperationGuard(HIDX_HELPING));\n"
" op->CleanUp();\n"
" \n"
" if (!succeeded) {\n"
" RetireOperation(op);\n"
" result = EMBB_BUSY;\n"
" break;\n"
" }\n");
// Release original nodes and operations
fprintf(file, "\n"
" RetireOperation(u_op);\n");
for (int i = 0; i < op.num_nodes; ++i) {
fprintf(file, " RetireNode(%s); RetireOperation(%s_op);\n",
op.old_nodes[i].name, op.old_nodes[i].name);
}
fprintf(file, "\n"
" result = EMBB_SUCCESS;\n"
" }\n");
// Delete new nodes if operation failed
fprintf(file, "\n"
" if (result != EMBB_SUCCESS) {\n");
for (int i = 0; i < op.num_nodes; ++i) {
fprintf(file, " if (%s) FreeNode(%s);\n",
op.new_nodes[i].name, op.new_nodes[i].name);
}
fprintf(file, " }\n");
// Return statement
fprintf(file, "\n"
" return result;\n"
"}\n"
"\n");
};
#ifndef OPERATIONS_H
#define OPERATIONS_H
static const int MAX_NODES = 5;
typedef struct {
const char *name;
} OldNode;
typedef struct {
const char *name;
const char *orig_node;
const char *weight;
const char *left;
const char *right;
} NewNode;
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4510 4512 4610)
#endif
typedef struct {
const char *name;
const int num_nodes;
const OldNode old_nodes[MAX_NODES];
const NewNode new_nodes[MAX_NODES];
} RebalancingOperation;
#ifdef _MSC_VER
#pragma warning(pop)
#endif
static const RebalancingOperation REBALANCING_OPERATIONS[] = {
{
"BLK",
3,
{"ux", "uxl", "uxr"},
{
{"nxl", "uxl", "1", "uxl->GetLeft()", "uxl->GetRight()"},
{"nxr", "uxr", "1", "uxr->GetLeft()", "uxr->GetRight()"},
{"nx", "ux", "u->IsSentinel() ? 1 : ux->GetWeight() - 1", "nxl", "nxr"}
}
},
{
"PUSH_L",
3,
{"ux", "uxl", "uxr"},
{
{"nxl", "uxl", "uxl->GetWeight() - 1", "uxl->GetLeft()", "uxl->GetRight()"},
{"nxr", "uxr", "0", "uxr->GetLeft()", "uxr->GetRight()"},
{"nx", "ux", "u->IsSentinel() ? 1 : ux->GetWeight() + 1", "nxl", "nxr"}
}
},
{
"PUSH_R",
3,
{"ux", "uxl", "uxr"},
{
{"nxr", "uxr", "uxr->GetWeight() - 1", "uxr->GetLeft()", "uxr->GetRight()"},
{"nxl", "uxl", "0", "uxl->GetLeft()", "uxl->GetRight()"},
{"nx", "ux", "u->IsSentinel() ? 1 : ux->GetWeight() + 1", "nxl", "nxr"}
}
},
{
"RB1_L",
2,
{"ux", "uxl"},
{
{"nxr", "ux", "0", "uxl->GetRight()", "ux->GetRight()"},
{"nx", "uxl", "ux->GetWeight()", "uxl->GetLeft()", "nxr"}
}
},
{
"RB1_R",
2,
{"ux", "uxr"},
{
{"nxl", "ux", "0", "ux->GetLeft()", "uxr->GetLeft()"},
{"nx", "uxr", "ux->GetWeight()", "nxl", "uxr->GetRight()"}
}
},
{
"RB2_L",
3,
{"ux", "uxl", "uxlr"},
{
{"nxl", "uxl", "0", "uxl->GetLeft()", "uxlr->GetLeft()"},
{"nxr", "ux", "0", "uxlr->GetRight()", "ux->GetRight()"},
{"nx", "uxlr", "ux->GetWeight()", "nxl", "nxr"}
}
},
{
"RB2_R",
3,
{"ux", "uxr", "uxrl"},
{
{"nxr", "uxr", "0", "uxrl->GetRight()", "uxr->GetRight()"},
{"nxl", "ux", "0", "ux->GetLeft()", "uxrl->GetLeft()"},
{"nx", "uxrl", "ux->GetWeight()", "nxl", "nxr"}
}
},
{
"W1_L",
4,
{"ux", "uxl", "uxr", "uxrl"},
{
{"nxll", "uxl", "uxl->GetWeight() - 1", "uxl->GetLeft()", "uxl->GetRight()"},
{"nxlr", "uxrl", "uxrl->GetWeight() - 1", "uxrl->GetLeft()", "uxrl->GetRight()"},
{"nxl", "ux", "1", "nxll", "nxlr"},
{"nx", "uxr", "ux->GetWeight()", "nxl", "uxr->GetRight()"}
}
},
{
"W1_R",
4,
{"ux", "uxl", "uxr", "uxlr"},
{
{"nxrr", "uxr", "uxr->GetWeight() - 1", "uxr->GetLeft()", "uxr->GetRight()"},
{"nxrl", "uxlr", "uxlr->GetWeight() - 1", "uxlr->GetLeft()", "uxlr->GetRight()"},
{"nxr", "ux", "1", "nxrl", "nxrr"},
{"nx", "uxl", "ux->GetWeight()", "uxl->GetLeft()", "nxr"}
}
},
{
"W2_L",
4,
{"ux", "uxl", "uxr", "uxrl"},
{
{"nxll", "uxl", "uxl->GetWeight() - 1", "uxl->GetLeft()", "uxl->GetRight()"},
{"nxlr", "uxrl", "0", "uxrl->GetLeft()", "uxrl->GetRight()"},
{"nxl", "ux", "1", "nxll", "nxlr"},
{"nx", "uxr", "ux->GetWeight()", "nxl", "uxr->GetRight()"}
}
},
{
"W2_R",
4,
{"ux", "uxl", "uxr", "uxlr"},
{
{"nxrr", "uxr", "uxr->GetWeight() - 1", "uxr->GetLeft()", "uxr->GetRight()"},
{"nxrl", "uxlr", "0", "uxlr->GetLeft()", "uxlr->GetRight()"},
{"nxr", "ux", "1", "nxrl", "nxrr"},
{"nx", "uxl", "ux->GetWeight()", "uxl->GetLeft()", "nxr"}
}
},
{
"W3_L",
5,
{"ux", "uxl", "uxr", "uxrl", "uxrll"},
{
{"nxlll", "uxl", "uxl->GetWeight() - 1", "uxl->GetLeft()", "uxl->GetRight()"},
{"nxll", "ux", "1", "nxlll", "uxrll->GetLeft()"},
{"nxlr", "uxrl", "1", "uxrll->GetRight()", "uxrl->GetRight()"},
{"nxl", "uxrll", "0", "nxll", "nxlr"},
{"nx", "uxr", "ux->GetWeight()", "nxl", "uxr->GetRight()"}
}
},
{
"W3_R",
5,
{"ux", "uxl", "uxr", "uxlr", "uxlrr"},
{
{"nxrrr", "uxr", "uxr->GetWeight() - 1", "uxr->GetLeft()", "uxr->GetRight()"},
{"nxrr", "ux", "1", "uxlrr->GetRight()", "nxrrr"},
{"nxrl", "uxlr", "1", "uxlr->GetLeft()", "uxlrr->GetLeft()"},
{"nxr", "uxlrr", "0", "nxrl", "nxrr"},
{"nx", "uxl", "ux->GetWeight()", "uxl->GetLeft()", "nxr"}
}
},
{
"W4_L",
5,
{"ux", "uxl", "uxr", "uxrl", "uxrlr"},
{
{"nxll", "uxl", "uxl->GetWeight() - 1", "uxl->GetLeft()", "uxl->GetRight()"},
{"nxrl", "uxrlr", "1", "uxrlr->GetLeft()", "uxrlr->GetRight()"},
{"nxl", "ux", "1", "nxll", "uxrl->GetLeft()"},
{"nxr", "uxr", "0", "nxrl", "uxr->GetRight()"},
{"nx", "uxrl", "ux->GetWeight()", "nxl", "nxr"}
}
},
{
"W4_R",
5,
{"ux", "uxl", "uxr", "uxlr", "uxlrl"},
{
{"nxrr", "uxr", "uxr->GetWeight() - 1", "uxr->GetLeft()", "uxr->GetRight()"},
{"nxlr", "uxlrl", "1", "uxlrl->GetLeft()", "uxlrl->GetRight()"},
{"nxr", "ux", "1", "uxlr->GetRight()", "nxrr"},
{"nxl", "uxl", "0", "uxl->GetLeft()", "nxlr"},
{"nx", "uxlr", "ux->GetWeight()", "nxl", "nxr"}
}
},
{
"W5_L",
4,
{"ux", "uxl", "uxr", "uxrr"},
{
{"nxll", "uxl", "uxl->GetWeight() - 1", "uxl->GetLeft()", "uxl->GetRight()"},
{"nxl", "ux", "1", "nxll", "uxr->GetLeft()"},
{"nxr", "uxrr", "1", "uxrr->GetLeft()", "uxrr->GetRight()"},
{"nx", "uxr", "ux->GetWeight()", "nxl", "nxr"}
}
},
{
"W5_R",
4,
{"ux", "uxl", "uxr", "uxll"},
{
{"nxrr", "uxr", "uxr->GetWeight() - 1", "uxr->GetLeft()", "uxr->GetRight()"},
{"nxr", "ux", "1", "uxl->GetRight()", "nxrr"},
{"nxl", "uxll", "1", "uxll->GetLeft()", "uxll->GetRight()"},
{"nx", "uxl", "ux->GetWeight()", "nxl", "nxr"}
}
},
{
"W6_L",
4,
{"ux", "uxl", "uxr", "uxrl"},
{
{"nxll", "uxl", "uxl->GetWeight() - 1", "uxl->GetLeft()", "uxl->GetRight()"},
{"nxl", "ux", "1", "nxll", "uxrl->GetLeft()"},
{"nxr", "uxr", "1", "uxrl->GetRight()", "uxr->GetRight()"},
{"nx", "uxrl", "ux->GetWeight()", "nxl", "nxr"}
}
},
{
"W6_R",
4,
{"ux", "uxl", "uxr", "uxlr"},
{
{"nxrr", "uxr", "uxr->GetWeight() - 1", "uxr->GetLeft()", "uxr->GetRight()"},
{"nxr", "ux", "1", "uxlr->GetRight()", "nxrr"},
{"nxl", "uxl", "1", "uxl->GetLeft()", "uxlr->GetLeft()"},
{"nx", "uxlr", "ux->GetWeight()", "nxl", "nxr"}
}
},
{
"W7",
3,
{"ux", "uxl", "uxr"},
{
{"nxl", "uxl", "uxl->GetWeight() - 1", "uxl->GetLeft()", "uxl->GetRight()"},
{"nxr", "uxr", "uxr->GetWeight() - 1", "uxr->GetLeft()", "uxr->GetRight()"},
{"nx", "ux", "u->IsSentinel() ? 1 : ux->GetWeight() + 1", "nxl", "nxr"}
}
}
};
#endif // OPERATIONS_H
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment