Skip to content

Commit

Permalink
Merge pull request #17 from Samuel-Tyler/devel
Browse files Browse the repository at this point in the history
Devel
  • Loading branch information
Samuel-Tyler committed Apr 19, 2020
2 parents c53e30e + 01bf95d commit 3aad811
Show file tree
Hide file tree
Showing 134 changed files with 12,515 additions and 6,615 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/build*
*.user
compile_commands.json
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,6 @@
[submodule "3rd_party/--force"]
path = 3rd_party/--force
url = https://github.com/vlm/asn1c.git
[submodule "3rd_party/run-clang-format"]
path = 3rd_party/run-clang-format
url = https://github.com/Sarcasm/run-clang-format.git
14 changes: 6 additions & 8 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,6 @@ matrix:
packages:
- bison

- env: BUILD_TYPE=Release CXX_STANDARD=11
compiler: clang

- env: BUILD_TYPE=Release CXX_STANDARD=11
compiler: gcc

- env: BUILD_TYPE=Release CXX_STANDARD=17
compiler: clang
dist: bionic
Expand All @@ -32,9 +26,13 @@ matrix:
compiler: gcc
dist: bionic

branches:
only:
- master

script:
- mkdir build
- cd build
- cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_STANDARD=$CXX_STANDARD
- make
- ctest
- cmake --build . -- -j4
- ctest -j4
1 change: 1 addition & 0 deletions 3rd_party/run-clang-format
Submodule run-clang-format added at de6e8c
50 changes: 37 additions & 13 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,30 +1,53 @@
cmake_minimum_required(VERSION 2.8)
project(fast_ber)
cmake_minimum_required(VERSION 3.0)
project(fast_ber VERSION "0.4")

if (NOT DEFINED CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 11)
endif()

add_subdirectory(3rd_party/abseil-cpp)
option(SKIP_TESTING "Skip building tests" OFF)
option(SKIP_AUTO_GENERATION "Use checked in lexer rather than generating with bison" OFF)

if (NOT ${SKIP_TESTING})
enable_testing()
endif()

set(ABSEIL_LIBS absl::base absl::container absl::strings absl::variant absl::optional absl::time absl::flat_hash_set)
if (EXISTS "${CMAKE_BINARY_DIR}/conanbuildinfo.cmake")
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()
set(ABSEIL_LIBS absl::absl)
find_package(absl REQUIRED CONFIG)
elseif (EXISTS "${CMAKE_SOURCE_DIR}/3rd_party/abseil-cpp/CMakeLists.txt")
add_subdirectory("3rd_party/abseil-cpp")
set(SKIP_INSTALL TRUE)
else()
find_package(absl REQUIRED)
endif()

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(default_build_type Release)
set(SKIP_AUTO_GENERATION false) # Set to true to avoid bison / asn1c autogeneration (use checked in files instead)
set(BENCHMARKS_INCLUDE_ASN1C true)

if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
add_compile_options("-O3" "-Wall" "-Wextra" "-pedantic" "-Wcast-align" "-Wpointer-arith" "-Wshadow")
add_compile_options("-Wfloat-equal" "-Wuninitialized")
add_compile_options("-Wno-missing-field-initializers") # Stop spam on g++-4.8
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wold-style-cast")

if (CMAKE_BUILD_TYPE MATCHES "Debug")
add_compile_options("-g")
# add_compile_options("-fsanitize=address" "-Werror")
# set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=address")
if (${FB_ENABLE_SANITIZER})
message("Enabled sanitizer")
add_compile_options("-fsanitize=address" "-fsanitize=undefined" "-Werror")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address -fsanitize=undefined -static-libsan")
endif()
else()
add_definitions("-DNDEBUG")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -flto")
add_definitions("-DNDEBUG -march=native")
if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
# Link time optimisation. Disabled on clang due to issue on travis
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -flto")
endif()
set(SKIP_AUTO_GENERATION true)
endif()
else()
Expand All @@ -38,8 +61,9 @@ else()
endif ()
endif()

enable_testing()
add_subdirectory(src)
add_subdirectory(test)
add_subdirectory(sample)
add_subdirectory(benchmarks)
if (DEFINED CMAKE_TESTING_ENABLED)
add_subdirectory(test)
add_subdirectory(sample)
add_subdirectory(benchmarks)
endif()
19 changes: 16 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# fast_ber ![version](https://img.shields.io/github/tag/samuel-tyler/fast_ber.svg) [![Appveyor status](https://ci.appveyor.com/api/projects/status/github/Samuel-Tyler/fast_ber?branch=master&svg=true)](https://ci.appveyor.com/project/Samuel-Tyler/fast-ber) [![Travis status](https://api.travis-ci.com/Samuel-Tyler/fast_ber.svg?branch=master)](https://travis-ci.com/Samuel-Tyler/fast_ber) ![C++11](https://img.shields.io/badge/language-C%2B%2B11-green.svg) ![C++14](https://img.shields.io/badge/language-C%2B%2B14-green.svg) ![C++17](https://img.shields.io/badge/language-C%2B%2B17-green.svg) ![C++20](https://img.shields.io/badge/language-C%2B%2B20-green.svg)
# fast_ber ![version](https://img.shields.io/github/tag/samuel-tyler/fast_ber.svg) [![Appveyor status](https://ci.appveyor.com/api/projects/status/github/Samuel-Tyler/fast_ber?branch=master&svg=true)](https://ci.appveyor.com/project/Samuel-Tyler/fast-ber) [![Travis status](https://api.travis-ci.com/Samuel-Tyler/fast_ber.svg?branch=master)](https://travis-ci.com/Samuel-Tyler/fast_ber) ![C++11](https://img.shields.io/badge/language-C%2B%2B11-green.svg) ![C++14](https://img.shields.io/badge/language-C%2B%2B14-green.svg) ![C++17](https://img.shields.io/badge/language-C%2B%2B17-green.svg) ![C++20](https://img.shields.io/badge/language-C%2B%2B20-green.svg) ![clang-format](https://github.com/Samuel-Tyler/fast_ber/workflows/clang-format/badge.svg)
A performant ASN.1 BER encoding and decoding library written in C++11

## Introduction
Expand All @@ -8,7 +8,6 @@ fast_ber is a small, lightweight library for BER encoding and decoding. Fast ber
- Simple, modern C++ interface
- ASN.1 sequences are represented as POD structs - no private members or complex getters and setters
- No exceptions, no RTTI and limited memory allocations (everything is small buffer optimised)
- Header only
- View classes are provided for zero copy decoding
- Interfaces mimic STL types such as std::string, std::vector and std::optional

Expand All @@ -18,13 +17,27 @@ fast_ber is a small, lightweight library for BER encoding and decoding. Fast ber
- No circular data structures
- Size and value constraints are not implemented

### Tools
fast_ber_view can be used to dump the contents of a BER PDU, without requiring a schema.
```
./build/src/fast_ber_view ./build_gcc/sample/pokemon.ber | jq
{
"length": 125,
"identifier": {
"class": "Universal",
"tag": "Sequence / Sequence Of"
},
"content": ...
}
```

## Call for Test Data
Test data is wanted to improve this project! If you have any test ASN.1 specs or BER files please share them. More test data will improve parsing and help find any issues with the library.

## Example Project
`fast_ber` is designed to be easy to consume via CMake. This is demonstrated in [`fast_ber_ldap3`](https://github.com/Samuel-Tyler/fast_ber_ldap3), an example project using `fast_ber` to create and dissect LDAP3 certificates.

## Usage
## Compiler Usage
1. Build the compiler:
```
git submodule update --init
Expand Down
11 changes: 7 additions & 4 deletions appveyor.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
branches:
only:
- master

platform:
- x64

Expand All @@ -6,7 +10,7 @@ configuration:

image:
- Visual Studio 2017
- Visual Studio 2019
# - Visual Studio 2019

init:
- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" (call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64)
Expand All @@ -16,11 +20,10 @@ before_build:
- git submodule update --init
- mkdir build
- cd build

build_script:
- cmake .. -DCMAKE_BUILD_TYPE=Release -G "NMake Makefiles"
- cmake --build . --config Release

test_script:
- ctest -C Release -j 8

- ctest -C Release -j 4
11 changes: 2 additions & 9 deletions benchmarks/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
project(fast_ber_benchmarks)

include(${CMAKE_SOURCE_DIR}/cmake/fast_ber_generate.cmake)
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/autogen)

add_custom_command(
Expand All @@ -11,14 +12,6 @@ if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
add_compile_options("-w") # Silence spam from asn1c build
endif()

function(fast_ber_generate input_file output_name)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/autogen/${output_name}.hpp
COMMAND fast_ber_compiler ${input_file} ${CMAKE_CURRENT_BINARY_DIR}/autogen/${output_name}
DEPENDS fast_ber_compiler ${input_file}
)
endfunction(fast_ber_generate)

file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/autogen/asn1c)
function(asn1c_generate input_file)
add_custom_command(
Expand All @@ -43,6 +36,6 @@ endif()
target_include_directories(${PROJECT_NAME} PRIVATE SYSTEM ${CMAKE_SOURCE_DIR}/3rd_party/Catch2/single_include)
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/autogen/asn1c)
target_link_libraries(${PROJECT_NAME} fast_ber_lib absl::strings)
target_link_libraries(${PROJECT_NAME} fast_ber_lib)

add_test(NAME fast_ber_benchmarks COMMAND ${PROJECT_NAME})
68 changes: 55 additions & 13 deletions benchmarks/ComponentPerformance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@

#include <vector>

struct IntegerDefault
{
constexpr static int get_value() noexcept { return 100; }
};

struct StringDefault
{
constexpr static const char* get_value() noexcept { return "Test string!"; }
};

const int iterations = 1000000;

template <typename T>
Expand All @@ -25,7 +35,7 @@ template <typename T>
void component_benchmark_decode(const T& type, const std::string& type_name)
{
std::array<uint8_t, 1000> buffer{};
fast_ber::encode(absl::Span<uint8_t>(buffer), type);
fast_ber::EncodeResult encode_result = fast_ber::encode(absl::Span<uint8_t>(buffer), type);

T decoded_copy;

Expand All @@ -34,7 +44,7 @@ void component_benchmark_decode(const T& type, const std::string& type_name)
{
for (int i = 0; i < iterations; i++)
{
res = fast_ber::decode(absl::Span<uint8_t>(buffer), decoded_copy);
res = fast_ber::decode(absl::Span<uint8_t>(buffer.data(), encode_result.length), decoded_copy);
}
}
REQUIRE(res.success);
Expand Down Expand Up @@ -67,63 +77,95 @@ void component_benchmark_default_construct(const std::string& type_name)
TEST_CASE("Component Performance: Encode")
{
component_benchmark_encode(fast_ber::Integer<>(-99999999), "Integer");
component_benchmark_encode(fast_ber::Default<fast_ber::Integer<>, IntegerDefault>(-99999999), "Default Integer");
component_benchmark_encode(fast_ber::Boolean<>(true), "Boolean");
component_benchmark_encode(fast_ber::OctetString<>("Test string!"), "OctetString");
component_benchmark_encode(fast_ber::Default<fast_ber::OctetString<>, StringDefault>("Test string!"),
"Default OctetString");
component_benchmark_encode(fast_ber::Null<>(), "Null");
component_benchmark_encode(fast_ber::Real<>(0.333333333333333314829616256247390992939472198486328125), "Real");
component_benchmark_encode(fast_ber::ObjectIdentifier<>(fast_ber::ObjectIdentifierComponents{1, 2, 840, 113549}),
"ObjectIdentifier");
component_benchmark_encode(fast_ber::Optional<fast_ber::OctetString<>>("hello!"), "Optional (String)");
component_benchmark_encode(fast_ber::Optional<fast_ber::Integer<>>(500), "Optional (Integer)");
component_benchmark_encode(fast_ber::Optional<fast_ber::Integer<>>(absl::nullopt), "Optional (Empty)");
component_benchmark_encode(fast_ber::Choice<fast_ber::Choices<fast_ber::Integer<>, fast_ber::OctetString<>>>(
fast_ber::OctetString<>("hello!")),
"Choice (String)");
component_benchmark_encode(fast_ber::Choice<fast_ber::Choices<fast_ber::Integer<>, fast_ber::OctetString<>>,
fast_ber::ChoiceId<fast_ber::Identifier<fast_ber::Integer<>>,
fast_ber::Identifier<fast_ber::OctetString<>>>,
fast_ber::StorageMode::dynamic>(fast_ber::OctetString<>("hello!")),
"Choice (String, D)");
component_benchmark_encode(
fast_ber::Choice<fast_ber::Integer<>, fast_ber::OctetString<>>(fast_ber::OctetString<>("hello!")),
"Choice (String)");
component_benchmark_encode(fast_ber::Choice<fast_ber::Integer<>, fast_ber::OctetString<>>(fast_ber::Integer<>(5)),
"Choice (Integer)");
fast_ber::Choice<fast_ber::Choices<fast_ber::Integer<>, fast_ber::OctetString<>>>(fast_ber::Integer<>(5)),
"Choice (Integer)");
}

TEST_CASE("Component Performance: Decode")
{
component_benchmark_decode(fast_ber::Integer<>(-99999999), "Integer");
component_benchmark_decode(fast_ber::Default<fast_ber::Integer<>, IntegerDefault>(-99999999), "Default Integer");
component_benchmark_decode(fast_ber::Boolean<>(true), "Boolean");
component_benchmark_decode(fast_ber::OctetString<>("Test string!"), "OctetString");
component_benchmark_decode(fast_ber::Default<fast_ber::OctetString<>, StringDefault>("Test string!"),
"Default OctetString");
component_benchmark_decode(fast_ber::Null<>(), "Null");
component_benchmark_decode(fast_ber::Real<>(0.333333333333333314829616256247390992939472198486328125), "Real");
component_benchmark_decode(fast_ber::ObjectIdentifier<>(fast_ber::ObjectIdentifierComponents{1, 2, 840, 113549}),
"ObjectIdentifier");
component_benchmark_decode(fast_ber::Optional<fast_ber::OctetString<>>("hello!"), "Optional (String)");
component_benchmark_decode(fast_ber::Optional<fast_ber::Integer<>>(500), "Optional (Integer)");
component_benchmark_decode(fast_ber::Optional<fast_ber::Integer<>>(absl::nullopt), "Optional (Empty)");
component_benchmark_decode(fast_ber::Choice<fast_ber::Choices<fast_ber::Integer<>, fast_ber::OctetString<>>>(
fast_ber::OctetString<>("hello!")),
"Choice (String)");
component_benchmark_decode(fast_ber::Choice<fast_ber::Choices<fast_ber::Integer<>, fast_ber::OctetString<>>,
fast_ber::ChoiceId<fast_ber::Identifier<fast_ber::Integer<>>,
fast_ber::Identifier<fast_ber::OctetString<>>>,
fast_ber::StorageMode::dynamic>(fast_ber::OctetString<>("hello!")),
"Choice (String, D)");
component_benchmark_decode(
fast_ber::Choice<fast_ber::Integer<>, fast_ber::OctetString<>>(fast_ber::OctetString<>("hello!")),
"Choice (String)");
component_benchmark_decode(fast_ber::Choice<fast_ber::Integer<>, fast_ber::OctetString<>>(fast_ber::Integer<>(5)),
"Choice (Integer)");
fast_ber::Choice<fast_ber::Choices<fast_ber::Integer<>, fast_ber::OctetString<>>>(fast_ber::Integer<>(5)),
"Choice (Integer)");
}

TEST_CASE("Component Performance: Object Construction")
{
component_benchmark_construct<fast_ber::Integer<>>(-99999999, "Integer");
component_benchmark_construct<fast_ber::Default<fast_ber::Integer<>, IntegerDefault>>(-99999999, "Default Integer");
component_benchmark_construct<fast_ber::Boolean<>>(true, "Boolean");
component_benchmark_construct<fast_ber::OctetString<>>("Test string!", "OctetString");
component_benchmark_construct<fast_ber::Default<fast_ber::OctetString<>, StringDefault>>("Test string!",
"Default String");
component_benchmark_construct<fast_ber::Null<>>(fast_ber::Null<>{}, "Null");
component_benchmark_construct<fast_ber::Real<>>(0.333333333333333314829616256247390992939472198486328125, "Real");
component_benchmark_construct<fast_ber::ObjectIdentifier<>>(fast_ber::ObjectIdentifierComponents{1, 2, 840, 113549},
"ObjectIdentifier");
component_benchmark_construct<fast_ber::Optional<fast_ber::OctetString<>>>("hello!", "Optional (String)");
component_benchmark_construct<fast_ber::Optional<fast_ber::Integer<>>>(500, "Optional (Integer)");
component_benchmark_construct<fast_ber::Optional<fast_ber::Integer<>>>(absl::nullopt, "Optional (Empty)");
component_benchmark_construct<fast_ber::Choice<fast_ber::Integer<>, fast_ber::OctetString<>>>(
component_benchmark_construct<fast_ber::Choice<fast_ber::Choices<fast_ber::Integer<>, fast_ber::OctetString<>>>>(
fast_ber::OctetString<>("hello!"), "Choice (String)");
component_benchmark_construct<fast_ber::Choice<fast_ber::Integer<>, fast_ber::OctetString<>>>(
component_benchmark_construct<fast_ber::Choice<
fast_ber::Choices<fast_ber::Integer<>, fast_ber::OctetString<>>,
fast_ber::ChoiceId<fast_ber::Identifier<fast_ber::Integer<>>, fast_ber::Identifier<fast_ber::OctetString<>>>,
fast_ber::StorageMode::dynamic>>(fast_ber::OctetString<>("hello!"), "Choice (String, D)");
component_benchmark_construct<fast_ber::Choice<fast_ber::Choices<fast_ber::Integer<>, fast_ber::OctetString<>>>>(
fast_ber::Integer<>(5), "Choice (Integer)");
}

TEST_CASE("Component Performance: Default Construction")
{
component_benchmark_default_construct<fast_ber::Integer<>>("Integer");
component_benchmark_default_construct<fast_ber::Default<fast_ber::Integer<>, IntegerDefault>>("Default Int");
component_benchmark_default_construct<fast_ber::Boolean<>>("Boolean");
component_benchmark_default_construct<fast_ber::OctetString<>>("OctetString");
component_benchmark_default_construct<fast_ber::Default<fast_ber::OctetString<>, StringDefault>>("Default Str");
component_benchmark_default_construct<fast_ber::Null<>>("Null");
component_benchmark_default_construct<fast_ber::Real<>>("Real");
component_benchmark_default_construct<fast_ber::ObjectIdentifier<>>("ObjectId");
component_benchmark_default_construct<fast_ber::Optional<fast_ber::Integer<>>>("Optional");
component_benchmark_default_construct<fast_ber::Choice<fast_ber::Integer<>, fast_ber::OctetString<>>>("Choice");
component_benchmark_default_construct<
fast_ber::Choice<fast_ber::Choices<fast_ber::Integer<>, fast_ber::OctetString<>>>>("Choice");
}

0 comments on commit 3aad811

Please sign in to comment.