Skip to content

Add templated bitwise AND block with tests #536

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Testing/Temporary/CTestCostData.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
---
3 changes: 3 additions & 0 deletions Testing/Temporary/LastTest.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Start testing: Mar 25 17:54 GMT
----------------------------------------------------------
End testing: Mar 25 17:54 GMT
49 changes: 25 additions & 24 deletions blocks/basic/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,27 +1,28 @@
set(GrBasicBlocks_HDRS
include/gnuradio-4.0/basic/ClockSource.hpp
include/gnuradio-4.0/basic/CommonBlocks.hpp
include/gnuradio-4.0/basic/ConverterBlocks.hpp
include/gnuradio-4.0/basic/DataSink.hpp
include/gnuradio-4.0/basic/FunctionGenerator.hpp
include/gnuradio-4.0/basic/Selector.hpp
include/gnuradio-4.0/basic/SignalGenerator.hpp
include/gnuradio-4.0/basic/StreamToDataSet.hpp
include/gnuradio-4.0/basic/SyncBlock.hpp
include/gnuradio-4.0/basic/Trigger.hpp)

set(GrBasicBlocks_LIBS gr-basic gr-testing)

if(PYTHON_AVAILABLE)
list(
APPEND
GrBasicBlocks_HDRS
include/gnuradio-4.0/basic/PythonBlock.hpp
include/gnuradio-4.0/basic/PythonInterpreter.hpp)
list(APPEND GrBasicBlocks_LIBS ${Python3_LIBRARIES})
endif()

add_library(gr-basic INTERFACE ${GrBasicBlocks_HDRS})
add_library(
gr-basic
INTERFACE
include/gnuradio-4.0/basic/ClockSource.hpp
include/gnuradio-4.0/basic/CommonBlocks.hpp
include/gnuradio-4.0/basic/ConverterBlocks.hpp
include/gnuradio-4.0/basic/DataSink.hpp
include/gnuradio-4.0/basic/FunctionGenerator.hpp
include/gnuradio-4.0/basic/PythonBlock.hpp
include/gnuradio-4.0/basic/PythonInterpreter.hpp
include/gnuradio-4.0/basic/Selector.hpp
include/gnuradio-4.0/basic/SignalGenerator.hpp
include/gnuradio-4.0/basic/StreamToDataSet.hpp
include/gnuradio-4.0/basic/SyncBlock.hpp
<<<<<<< HEAD
include/gnuradio-4.0/basic/Trigger.hpp)
=======
include/gnuradio-4.0/basic/Trigger.hpp
include/gnuradio-4.0/basic/And.hpp
include/gnuradio-4.0/basic/AndConst.hpp
include/gnuradio-4.0/basic/Not.hpp
include/gnuradio-4.0/basic/Or.hpp
include/gnuradio-4.0/basic/Xor.hpp
)
>>>>>>> 0c1c5cd (Update restyled And block implementation.)
target_link_libraries(gr-basic INTERFACE gnuradio-core gnuradio-algorithm)
target_include_directories(gr-basic INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/>
$<INSTALL_INTERFACE:include/>)
Expand Down
27 changes: 27 additions & 0 deletions blocks/basic/include/gnuradio-4.0/basic/And.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#ifndef AND_HPP
#define AND_HPP

#include <concepts>
#include <gnuradio-4.0/Block.hpp>
#include <gnuradio-4.0/BlockRegistry.hpp>

namespace gr::basic {

GR_REGISTER_BLOCK(gr::basic::And, [ uint8_t, int16_t, int32_t ])

template<std::integral T>
struct And : Block<And<T>> {
using Description = Doc<"@brief Performs a bitwise AND operation on two inputs, producing one output stream.">;

PortIn<T> in1;
PortIn<T> in2;
PortOut<T> out;

GR_MAKE_REFLECTABLE(And, in1, in2, out);

[[nodiscard]] constexpr T processOne(T input1, T input2) const noexcept { return input1 & input2; }
};

} // namespace gr::basic

#endif // AND_HPP
37 changes: 37 additions & 0 deletions blocks/basic/include/gnuradio-4.0/basic/AndConst.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#ifndef ANDCONST_HPP
#define ANDCONST_HPP

#include <concepts>
#include <gnuradio-4.0/Block.hpp>
#include <gnuradio-4.0/BlockRegistry.hpp>

namespace gr::basic {

GR_REGISTER_BLOCK(gr::basic::AndConst, [ uint8_t, int16_t, int32_t ])

template<std::integral T>
struct AndConst : Block<AndConst<T>> {
using Description = Doc<"@brief Performs a bitwise AND operation on two inputs, producing one output stream.">;

PortIn<T> in;
PortOut<T> out;

T constant = 1;

GR_MAKE_REFLECTABLE(AndConst, in, out, constant);

[[nodiscard]] constexpr T processOne(T input) const noexcept { return input & constant; }

// Validate constant value (restrict to 0 or 1)
void settingsChanged(const property_map& /* old_settings */, const property_map& new_settings) {
if (new_settings.contains("constant")) {
if (constant != 0 && constant != 1) {
throw std::runtime_error("Constant must be 0 or 1.");
}
}
}
};

} // namespace gr::basic

#endif // ANDCONST_HPP
26 changes: 26 additions & 0 deletions blocks/basic/include/gnuradio-4.0/basic/Not.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#ifndef NOT_HPP
#define NOT_HPP

#include <concepts>
#include <gnuradio-4.0/Block.hpp>
#include <gnuradio-4.0/BlockRegistry.hpp>

namespace gr::basic {

GR_REGISTER_BLOCK(gr::basic::Not, [ uint8_t, int16_t, int32_t ])

template<std::integral T>
struct Not : Block<Not<T>> {
using Description = Doc<"@brief Performs a bitwise NOT operation on the input stream, producing an output stream with inverted bits.">;

PortIn<T> in;
PortOut<T> out;

GR_MAKE_REFLECTABLE(Not, in, out);

[[nodiscard]] constexpr T processOne(T input) const noexcept { return ~input; }
};

} // namespace gr::basic

#endif // NOT_HPP
27 changes: 27 additions & 0 deletions blocks/basic/include/gnuradio-4.0/basic/Or.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#ifndef OR_HPP
#define OR_HPP

#include <concepts>
#include <gnuradio-4.0/Block.hpp>
#include <gnuradio-4.0/BlockRegistry.hpp>

namespace gr::basic {

GR_REGISTER_BLOCK(gr::basic::Or, [ uint8_t, int16_t, int32_t ])

template<std::integral T>
struct Or : Block<Or<T>> {
using Description = Doc<"@brief Performs a bitwise OR operation on two inputs, producing one output stream.">;

PortIn<T> in1;
PortIn<T> in2;
PortOut<T> out;

GR_MAKE_REFLECTABLE(Or, in1, in2, out);

[[nodiscard]] constexpr T processOne(T input1, T input2) const noexcept { return input1 | input2; }
};

} // namespace gr::basic

#endif // OR_HPP
27 changes: 27 additions & 0 deletions blocks/basic/include/gnuradio-4.0/basic/Xor.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#ifndef XOR_HPP
#define XOR_HPP

#include <concepts>
#include <gnuradio-4.0/Block.hpp>
#include <gnuradio-4.0/BlockRegistry.hpp>

namespace gr::basic {

GR_REGISTER_BLOCK(gr::basic::Xor, [ uint8_t, int16_t, int32_t ])

template<std::integral T>
struct Xor : Block<Xor<T>> {
using Description = Doc<"@brief Performs a bitwise XOR operation on two input streams, producing one output stream.">;

PortIn<T> in1;
PortIn<T> in2;
PortOut<T> out;

GR_MAKE_REFLECTABLE(Xor, in1, in2, out);

[[nodiscard]] constexpr T processOne(T input1, T input2) const noexcept { return input1 ^ input2; }
};

} // namespace gr::basic

#endif // XOR_HPP
6 changes: 6 additions & 0 deletions blocks/basic/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ add_ut_test(qa_Selector)
add_ut_test(qa_sources)
add_ut_test(qa_DataSink)
add_ut_test(qa_TriggerBlocks)
add_ut_test(qa_And)
add_ut_test(qa_AndConst)
add_ut_test(qa_Not)
add_ut_test(qa_Or)
add_ut_test(qa_Xor)


if(GR_ENABLE_BLOCK_REGISTRY AND INTERNAL_ENABLE_BLOCK_PLUGINS)
add_ut_test(qa_BasicKnownBlocks)
Expand Down
60 changes: 60 additions & 0 deletions blocks/basic/test/qa_And.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#include <boost/ut.hpp>
#include <gnuradio-4.0/basic/And.hpp>
// #include <limits>

using namespace gr::basic;
using namespace boost::ut;

const suite AndTests = [] {
"Bitwise AND operations"_test = [] {
And<uint8_t> andBlock;
// Basic bitwise AND operation
expect(eq(andBlock.processOne(0xFF, 0x0F), 0x0F)); // 0xFF & 0x0F = 0x0F
expect(eq(andBlock.processOne(0x00, 0xFF), 0x00));
expect(eq(andBlock.processOne(0xAB, 0x22), 0x22));
};

"Edge cases"_test = [] {
And<uint8_t> andBlock;
// Edge cases for boundary values (max and min values)
expect(eq(andBlock.processOne(0xFF, 0xFF), 0xFF)); // 0xFF & 0xFF = 0xFF
expect(eq(andBlock.processOne(0x00, 0x00), 0x00)); // 0x00 & 0x00 = 0x00
};

"int16_t support"_test = [] {
And<int16_t> andBlock;
// Test with int16_t values
expect(eq(andBlock.processOne(0x7FFF, 0x00FF), 0x00FF)); // 0x7FFF & 0x00FF = 0x0101
expect(eq(andBlock.processOne(static_cast<int16_t>(-1), static_cast<int16_t>(0xAABB)), static_cast<int16_t>(0xAABB))); // -1 & 0xAABB = 0xAABB
};

"int32_t support"_test = [] {
And<int32_t> andBlock;
// Test bitwise AND on int32_t values (max and min values)
expect(eq(andBlock.processOne(0xFFFF, 0x0F0F), 0x0F0F)); // 0xFFFF (1111111111111111) & 0x0F0F (0000111100001111) = 0x0F0F
expect(eq(andBlock.processOne(-1, 0x0000), 0x0000)); // -1 & 0x0000 = 0x0000
};

"Boundary cases"_test = [] {
And<int32_t> andBlock;
// Boundary test cases for int32_t limits
expect(eq(andBlock.processOne(std::numeric_limits<int32_t>::max(), std::numeric_limits<int32_t>::min()), 0)); // MAX & MIN = 0
expect(eq(andBlock.processOne(std::numeric_limits<int32_t>::max(), -1), std::numeric_limits<int32_t>::max())); // MAX & -1 = MAX
};

"Negative values"_test = [] {
And<int16_t> andBlock;
// Test with negative values for int16_t
expect(eq(andBlock.processOne(static_cast<int16_t>(-1), static_cast<int16_t>(-1)), static_cast<int16_t>(-1))); // -1 & -1 = -1

/*
1111 1111 1111 1011 (-5 in two's complement)
& 0000 0000 0000 0011 (3 in binary)
--------------------
0000 0000 0000 0011 (Result = 3)
*/
expect(eq(andBlock.processOne(static_cast<int16_t>(-5), static_cast<int16_t>(3)), static_cast<int16_t>(3))); // -5 & 3 = 3
};
};

int main() { return boost::ut::cfg<boost::ut::override>.run(); }
57 changes: 57 additions & 0 deletions blocks/basic/test/qa_AndConst.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#include <boost/ut.hpp>
#include <gnuradio-4.0/basic/AndConst.hpp>

using namespace gr::basic;
using namespace boost::ut;

const suite AndConstTests = [] {
"uint8_t support"_test = [] {
AndConst<uint8_t> andConstBlock;

// Test default constant = 1
andConstBlock.constant = 1;
expect(eq(andConstBlock.processOne(0xFF), 0x01));
expect(eq(andConstBlock.processOne(0x00), 0x00));
expect(eq(andConstBlock.processOne(0xAA), 0x00));

// Test constant = 0
andConstBlock.constant = 0;
expect(eq(andConstBlock.processOne(0xFF), 0x00));
expect(eq(andConstBlock.processOne(0x00), 0x00));
expect(eq(andConstBlock.processOne(0xAA), 0x00));
};

"int16_t support"_test = [] {
AndConst<int16_t> andConstBlock;

// Test default constant = 1
andConstBlock.constant = 1;
expect(eq(andConstBlock.processOne(static_cast<int16_t>(0xFF)), 0x0001));
expect(eq(andConstBlock.processOne(static_cast<int16_t>(0x00)), 0x0000));
expect(eq(andConstBlock.processOne(static_cast<int16_t>(0xAA)), 0x0000));

// Test constant = 0
andConstBlock.constant = 0;
expect(eq(andConstBlock.processOne(static_cast<int16_t>(0xFF)), 0x0000));
expect(eq(andConstBlock.processOne(static_cast<int16_t>(0x00)), 0x0000));
expect(eq(andConstBlock.processOne(static_cast<int16_t>(0xAA)), 0x0000));
};

"int32_t support"_test = [] {
AndConst<int32_t> andConstBlock;

// Test default constant = 1
andConstBlock.constant = 1;
expect(eq(andConstBlock.processOne((0xFF)), 0x00000001));
expect(eq(andConstBlock.processOne((0x00)), 0x00000000));
expect(eq(andConstBlock.processOne((0xAA)), 0x00000000));

// Test constant = 0
andConstBlock.constant = 0;
expect(eq(andConstBlock.processOne((0xFF)), 0x00000000));
expect(eq(andConstBlock.processOne((0x00)), 0x00000000));
expect(eq(andConstBlock.processOne((0xAA)), 0x00000000));
};
};

int main() { return boost::ut::cfg<boost::ut::override>.run(); }
33 changes: 33 additions & 0 deletions blocks/basic/test/qa_Not.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#include <boost/ut.hpp>
#include <gnuradio-4.0/basic/Not.hpp>

using namespace gr::basic;
using namespace boost::ut;

const suite NotTests = [] {
"uint8_t support"_test = [] {
Not<uint8_t> notBlock;

expect(eq(notBlock.processOne(0xFF), 0x00));
expect(eq(notBlock.processOne(0x00), 0xFF));
expect(eq(notBlock.processOne(0xAA), 0x55)); // ~(10101010) = 01010101
};

"int16_t support"_test = [] {
Not<int16_t> notBlock;

expect(eq(notBlock.processOne(static_cast<int16_t>(0x00FF)), static_cast<int16_t>(0xFF00)));
expect(eq(notBlock.processOne(static_cast<int16_t>(0x0000)), static_cast<int16_t>(0xFFFF)));
expect(eq(notBlock.processOne(static_cast<int16_t>(0xAAAA)), static_cast<int16_t>(0x5555)));
};

"int32_t support"_test = [] {
Not<int32_t> notBlock;

expect(eq(notBlock.processOne(0x000000FF), static_cast<int32_t>(0xFFFFFF00)));
expect(eq(notBlock.processOne(0x00000000), static_cast<int32_t>(0xFFFFFFFF)));
expect(eq(notBlock.processOne(0x0000AAAA), static_cast<int32_t>(0xFFFF5555)));
};
};

int main() { return boost::ut::cfg<boost::ut::override>.run(); }
Loading