Skip to content

Commit

Permalink
feat: struct and tokenize tweaks
Browse files Browse the repository at this point in the history
  • Loading branch information
strasdat committed Mar 22, 2024
1 parent d5ee6bd commit f25ea36
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 9 deletions.
12 changes: 10 additions & 2 deletions cpp/farm_ng/core/misc/tokenize.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,22 @@ namespace farm_ng {
inline std::vector<std::string> tokenize(
std::string const& str, char delimiter = ' ') {
std::vector<std::string> tokens;

std::stringstream strstream(str);
std::string token;

while (getline(strstream, token, delimiter)) {
// Added check to handle the case where the last character is the delimiter
bool lastCharDelimiter = !str.empty() && str.back() == delimiter;

while (std::getline(strstream, token, delimiter)) {
tokens.push_back(token);
}

// If the last character in the input string is a delimiter,
// add an empty string to tokens to account for the final empty token.
if (lastCharDelimiter) {
tokens.push_back("");
}

return tokens;
}

Expand Down
19 changes: 18 additions & 1 deletion cpp/farm_ng/core/misc/tokenize_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,23 @@

#include "farm_ng/core/misc/tokenize.h"

#include <farm_ng/core/logging/expected.h>
#include <gtest/gtest.h>

TEST(tokenize, smoke) {} // NOLINT
TEST(tokenize, smoke) {
using namespace farm_ng;

std::vector<std::string> tokens = tokenize("foo bar");
FARM_ASSERT_EQ(tokens.size(), 2);
FARM_ASSERT_EQ(tokens[0], "foo");
FARM_ASSERT_EQ(tokens[1], "bar");

tokens = tokenize(",foo,,bar,", ',');
FARM_ASSERT_EQ(tokens.size(), 5);
FARM_ASSERT_EQ(tokens[0], "");
FARM_ASSERT_EQ(tokens[1], "foo");
FARM_ASSERT_EQ(tokens[2], "");
FARM_ASSERT_EQ(tokens[3], "bar");
FARM_ASSERT_EQ(tokens[4], "");

} // NOLINT
49 changes: 48 additions & 1 deletion cpp/farm_ng/core/struct/base.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,43 @@
#define FARM_STRUCT_DETAILS_FIELD_TYPE(Dummy1_, Dummy2_, Type_Name_Init_) \
, FARM_PP_TUPLE_ELEM(0, Type_Name_Init_)

/// Given a triplet such as (Type, name, init), return assignment as shown
/// below.
///
/// ${triplet}
///
/// => s.${triplet}[1] = std::move(std::get<index>(tuple));
///
/// Example:
///
/// Input: (Type0, name0, {init0})
/// Output: s.name0 = std::move(std::get<index>(tuple));
#define FARM_STRUCT_DETAILS_SET_FIELD_FROM_TUPLE( \
Dummy1_, Dummy2_, index, Type_Name_Init_) \
s.FARM_PP_TUPLE_ELEM(1, Type_Name_Init_) = std::move(std::get<index>(tuple));

/// Given a sequence of triplets, create a sequence of assignments
///
/// Example:
///
/// Input: ((Type0, name0, init0)) ((Type1, name1, init1)) ... Output: ,
///
/// Output:
/// s.name0 = std::move(std::get<index>(tuple));
/// s.name1 = std::move(std::get<index>(tuple));
/// ...
#define FARM_STRUCT_DETAILS_SET_FIELD_FROM_TUPLE_LOOP(Field_Seq_) \
FARM_PP_SEQ_FOR_EACH_I( \
FARM_STRUCT_DETAILS_SET_FIELD_FROM_TUPLE, _, Field_Seq_)

#define FARM_STRUCT_DETAILS_TO_TUPLE(Dummy1_, Dummy2_, index, Type_Name_Init_) \
, this->FARM_PP_TUPLE_ELEM(1, Type_Name_Init_)

#define FARM_STRUCT_DETAILS_TO_TUPLE_LOOP(Field_Seq_) \
this->FARM_PP_TUPLE_ELEM(1, FARM_PP_SEQ_ELEM(0, Field_Seq_)) \
FARM_PP_SEQ_FOR_EACH_I( \
FARM_STRUCT_DETAILS_TO_TUPLE, _, FARM_PP_SEQ_POP_FRONT(Field_Seq_))

/// Given a sequence of triplets, create a comma separated list of field types.
///
/// Example:
Expand All @@ -99,10 +136,20 @@
FARM_STRUCT_DETAILS_FIELD_TYPE, _, FARM_PP_SEQ_POP_FRONT(Field_Seq_))

/// Implementation details for FARM_STRUCT.
#define FARM_STRUCT_DETAILS_BASE(Num_Fields_, Field_Seq_) \
#define FARM_STRUCT_DETAILS_BASE(Struct_Name_, Num_Fields_, Field_Seq_) \
static int constexpr kNumFields = Num_Fields_; \
static std::array<std::string_view, kNumFields> constexpr kFieldNames = { \
FARM_STRUCT_DETAILS_FIELD_NAME_LOOP(Field_Seq_)}; \
using FieldTypes = \
std::tuple<FARM_STRUCT_DETAILS_FIELD_TYPE_LOOP(Field_Seq_)>; \
\
static Struct_Name_ fromTuple(FieldTypes&& tuple) noexcept { \
Struct_Name_ s; \
FARM_STRUCT_DETAILS_SET_FIELD_FROM_TUPLE_LOOP(Field_Seq_) \
return s; \
} \
\
auto toTuple() const noexcept->FieldTypes { \
return std::make_tuple(FARM_STRUCT_DETAILS_TO_TUPLE_LOOP(Field_Seq_)); \
} \
FARM_STRUCT_DETAILS_FIELD_DECLARATION_LOOP(Field_Seq_)
13 changes: 11 additions & 2 deletions cpp/farm_ng/core/struct/base_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,20 @@ TEST(struct_test, unit) {
"static int constexpr kNumFields = 2; "
"static std::array<std::string_view, kNumFields> constexpr kFieldNames = { \"i\" , \"d\" }; "
"using FieldTypes = std::tuple<int , double >; "
"static Foo fromTuple(FieldTypes&& tuple) noexcept { "
"Foo s; "
"s.i = std::move(std::get<0>(tuple)); "
"s.d = std::move(std::get<1>(tuple)); "
"return s; "
"} "
"auto toTuple() const noexcept -> FieldTypes { "
"return std::make_tuple(this->i , this->d ); "
"} "
"int i {1}; "
"double d {0.5};");
// clang-format on
EXPECT_EQ(
FARM_PP_STRINGIZE(
FARM_STRUCT_DETAILS_BASE(2, ((int, i, {1}))((double, d, {0.5})))),
FARM_PP_STRINGIZE(FARM_STRUCT_DETAILS_BASE(
Foo, 2, ((int, i, {1}))((double, d, {0.5})))),
expected_string);
}
4 changes: 2 additions & 2 deletions cpp/farm_ng/core/struct/struct.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@

/// Takes in a struct name and a sequence of fields and generates a struct.
///
/// This is an implementation details. User shall call FARM_STRUCT(StructName,
/// This is an implementation details. User shall call FARM_STRUCT(Struct_Name_,
/// ((Type0, name0, init0), ...))); instead;
///
/// This intermediate macro exists since the conversion from a list to a
/// sequence is likely somewhat expensive, so we want to do it once and reuse
/// it.
#define FARM_STRUCT_DETAIL_FROM_SEQ(Struct_Name_, Num_Fields_, Field_Seq_) \
struct Struct_Name_ { \
FARM_STRUCT_DETAILS_BASE(Num_Fields_, Field_Seq_) \
FARM_STRUCT_DETAILS_BASE(Struct_Name_, Num_Fields_, Field_Seq_) \
}

/// Takes in a struct name and a tuple of fields and generates a struct.
Expand Down
19 changes: 19 additions & 0 deletions cpp/farm_ng/core/struct/struct_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,30 @@ TEST(struct_test, unit) {
"static std::array<std::string_view, kNumFields> constexpr kFieldNames "
"= { \"i\" , \"d\" }; "
"using FieldTypes = std::tuple<int , double >; "
"static Foo fromTuple(FieldTypes&& tuple) noexcept { "
"Foo s; "
"s.i = std::move(std::get<0>(tuple)); "
"s.d = std::move(std::get<1>(tuple)); "
"return s; "
"} "
"auto toTuple() const noexcept -> FieldTypes { "
"return std::make_tuple(this->i , this->d ); "
"} "
"int i {1}; "
"double d {0.5}; "
"}");
// clang-format on
EXPECT_EQ(
FARM_PP_STRINGIZE(FARM_STRUCT(Foo, ((int, i, {1}), (double, d, {0.5})))),
expected_string);

StructExample1 instance;
std::tuple<int, float> tuple = instance.toTuple();
FARM_ASSERT_EQ(std::get<0>(tuple), instance.integer);
FARM_ASSERT_EQ(std::get<1>(tuple), instance.f);
tuple = std::make_tuple(-1, 0.25);
StructExample1 instance2 = StructExample1::fromTuple(std::move(tuple));

FARM_ASSERT_EQ(std::get<0>(tuple), instance2.integer);
FARM_ASSERT_EQ(std::get<1>(tuple), instance2.f);
}
3 changes: 2 additions & 1 deletion cpp/sophus2/image/image_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,8 @@ struct ImageTraits<Eigen::Matrix<TT, kNumChannelsT, 1>> {
///
/// Precondition: `lhs` and `rhs` are the same size and not empty
template <class TPixel, class TFunc>
auto visit(ImageView<TPixel> lhs, ImageView<TPixel> rhs, TFunc const& user_function) {
auto visit(
ImageView<TPixel> lhs, ImageView<TPixel> rhs, TFunc const& user_function) {
SOPHUS_ASSERT(!lhs.isEmpty());
SOPHUS_ASSERT(!rhs.isEmpty());
SOPHUS_ASSERT_EQ(lhs.imageSize(), rhs.imageSize());
Expand Down

0 comments on commit f25ea36

Please sign in to comment.