Skip to content

Commit 2d44c10

Browse files
committed
stream_options_manipulator refactor
1 parent b63e0b5 commit 2d44c10

15 files changed

Lines changed: 493 additions & 485 deletions

include/gl/edge_descriptor.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
#include "gl/attributes/force_inline.hpp"
88
#include "gl/constants.hpp"
99
#include "gl/directional_tags.hpp"
10-
#include "gl/io/format.hpp"
1110
#include "gl/io/options.hpp"
11+
#include "gl/io/ranges.hpp"
1212
#include "gl/types/core.hpp"
1313
#include "gl/vertex_descriptor.hpp"
1414

include/gl/graph.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#include "gl/impl/impl_tags.hpp"
1111
#include "gl/io/graph_fmt_traits.hpp"
1212
#include "gl/io/options.hpp"
13-
#include "gl/io/stream_options_manipulator.hpp"
13+
#include "gl/io/options_manip.hpp"
1414
#include "gl/traits.hpp"
1515
#include "gl/util/ranges.hpp"
1616

@@ -636,7 +636,7 @@ class graph final {
636636
friend std::ostream& operator<<(std::ostream& os, const graph& g) {
637637
using io::detail::option_bit;
638638

639-
if (io::is_option_set(os, option_bit::specification_fmt))
639+
if (io::is_option_set(os, option_bit::spec_fmt))
640640
return g._gsf_write(os);
641641

642642
if (io::is_option_set(os, option_bit::verbose))

include/gl/io/graph_fio.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,11 @@ template <traits::c_graph GraphType, detail::c_io_save_mode Mode = write>
9191
void save(
9292
const GraphType& graph,
9393
const std::filesystem::path& path = "graph.gsf",
94-
const std::initializer_list<stream_options_manipulator>& options = {}
94+
const std::initializer_list<options_manip>& options = {}
9595
) {
9696
std::ofstream file = detail::open_outfile<Mode>(path);
9797

98-
file << enable_gsf;
98+
file << spec_fmt;
9999
for (const auto& option : options)
100100
file << option;
101101

@@ -106,7 +106,7 @@ template <traits::c_graph GraphType>
106106
[[nodiscard]] GraphType load(const std::filesystem::path& path = "graph.gsf") {
107107
std::ifstream file = detail::open_infile(path);
108108

109-
file >> enable_gsf;
109+
file >> spec_fmt;
110110

111111
GraphType graph;
112112
file >> graph;

include/gl/io/options.hpp

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,48 +4,51 @@
44

55
#pragma once
66

7-
#include "gl/io/stream_options_manipulator.hpp"
7+
#include "gl/io/options_manip.hpp"
88

99
namespace gl::io {
1010

1111
namespace detail {
1212

1313
enum class option_bit : bit_position_type {
1414
verbose = 0u,
15-
with_vertex_properties = 1u,
16-
with_connection_properties = 2u,
17-
specification_fmt = 3u
15+
spec_fmt = 1u,
16+
with_vertex_properties = 2u,
17+
with_connection_properties = 3u
1818
};
1919

20+
inline constexpr iword_type layout_options_mask =
21+
detail::build_mask(detail::option_bit::verbose, detail::option_bit::spec_fmt);
22+
2023
} // namespace detail
2124

22-
inline const stream_options_manipulator verbose = set_option(detail::option_bit::verbose);
23-
inline const stream_options_manipulator concise = unset_option(detail::option_bit::verbose);
25+
// TODO: add tests
2426

25-
inline const stream_options_manipulator with_vertex_properties =
26-
set_option(detail::option_bit::with_vertex_properties);
27-
inline const stream_options_manipulator without_vertex_properties =
28-
unset_option(detail::option_bit::with_vertex_properties);
27+
inline constexpr options_manip concise{0ul, detail::layout_options_mask};
28+
inline constexpr options_manip verbose{
29+
detail::build_mask(detail::option_bit::verbose), detail::layout_options_mask
30+
};
31+
inline constexpr options_manip spec_fmt{
32+
detail::build_mask(detail::option_bit::spec_fmt), detail::layout_options_mask
33+
};
2934

30-
inline const stream_options_manipulator with_edge_properties =
31-
set_option(detail::option_bit::with_connection_properties);
32-
inline const stream_options_manipulator without_edge_properties =
33-
unset_option(detail::option_bit::with_connection_properties);
35+
inline constexpr options_manip with_vertex_properties =
36+
set_options(detail::option_bit::with_vertex_properties);
37+
inline constexpr options_manip without_vertex_properties =
38+
clear_options(detail::option_bit::with_vertex_properties);
3439

35-
inline const stream_options_manipulator with_properties = set_options(
36-
{detail::option_bit::with_vertex_properties, detail::option_bit::with_connection_properties}
40+
inline constexpr options_manip with_edge_properties =
41+
set_options(detail::option_bit::with_connection_properties);
42+
inline constexpr options_manip without_edge_properties =
43+
clear_options(detail::option_bit::with_connection_properties);
44+
45+
inline constexpr options_manip with_properties = set_options(
46+
detail::option_bit::with_vertex_properties, detail::option_bit::with_connection_properties
3747
);
38-
inline const stream_options_manipulator without_properties = unset_options(
39-
{detail::option_bit::with_vertex_properties, detail::option_bit::with_connection_properties}
48+
inline constexpr options_manip without_properties = clear_options(
49+
detail::option_bit::with_vertex_properties, detail::option_bit::with_connection_properties
4050
);
4151

42-
// TODO: rename to _spec_fmt
43-
inline const stream_options_manipulator enable_gsf =
44-
set_option(detail::option_bit::specification_fmt);
45-
inline const stream_options_manipulator disable_gsf =
46-
unset_option(detail::option_bit::specification_fmt);
47-
48-
inline const stream_options_manipulator default_options =
49-
unset_options(~static_cast<iword_type>(0));
52+
inline constexpr options_manip default_options{0ul, ~static_cast<iword_type>(0)};
5053

5154
} // namespace gl::io

include/gl/io/options_manip.hpp

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
// Copyright (c) 2024-2026 Jakub Musiał
2+
// This file is part of the CPP-GL project (https://github.com/SpectraL519/cpp-gl).
3+
// Licensed under the MIT License. See the LICENSE file in the project root for full license information.
4+
5+
#pragma once
6+
7+
#include "gl/attributes/force_inline.hpp"
8+
#include "gl/traits.hpp"
9+
10+
#include <iostream>
11+
#include <utility>
12+
13+
namespace gl::io {
14+
15+
using index_type = int;
16+
using iword_type = long;
17+
using bit_position_type = unsigned;
18+
19+
inline constexpr iword_type iword_bit = 1ul;
20+
21+
class options_manip {
22+
public:
23+
options_manip() = delete;
24+
25+
constexpr explicit options_manip(iword_type set_mask, iword_type clear_mask = 0ul)
26+
: _set_mask(set_mask), _clear_mask(clear_mask) {}
27+
28+
friend std::ostream& operator<<(std::ostream& os, const options_manip& manip) {
29+
os.iword(_iostream_property_map_index()) &= ~manip._clear_mask;
30+
os.iword(_iostream_property_map_index()) |= manip._set_mask;
31+
return os;
32+
}
33+
34+
friend std::istream& operator>>(std::istream& is, const options_manip& manip) {
35+
is.iword(_iostream_property_map_index()) &= ~manip._clear_mask;
36+
is.iword(_iostream_property_map_index()) |= manip._set_mask;
37+
return is;
38+
}
39+
40+
[[nodiscard]] gl_attr_force_inline static bool is_option_set(
41+
std::ios_base& stream, bit_position_type bit_position
42+
) {
43+
return (stream.iword(_iostream_property_map_index()) & (iword_bit << bit_position)) != 0;
44+
}
45+
46+
[[nodiscard]] gl_attr_force_inline static bool is_option_set(
47+
std::ios_base& stream, traits::c_enum auto bit
48+
) {
49+
return is_option_set(stream, static_cast<bit_position_type>(bit));
50+
}
51+
52+
[[nodiscard]] gl_attr_force_inline static bool are_options_set(
53+
std::ios_base& stream, iword_type bitmask
54+
) {
55+
return (stream.iword(_iostream_property_map_index()) & bitmask) == bitmask;
56+
}
57+
58+
private:
59+
[[nodiscard]] gl_attr_force_inline static index_type _iostream_property_map_index() {
60+
static index_type index = std::ios_base::xalloc();
61+
return index;
62+
}
63+
64+
iword_type _set_mask;
65+
iword_type _clear_mask;
66+
};
67+
68+
namespace detail {
69+
70+
// clang-format off
71+
72+
template <typename... Args>
73+
[[nodiscard]] constexpr iword_type build_mask(Args... bits) {
74+
return ((iword_bit << static_cast<bit_position_type>(bits)) | ...);
75+
}
76+
77+
// clang-format on
78+
79+
template <typename T>
80+
[[nodiscard]] constexpr iword_type build_mask_from(std::initializer_list<T> bits) {
81+
iword_type mask = 0ul;
82+
for (auto b : bits)
83+
mask |= iword_bit << static_cast<bit_position_type>(b);
84+
return mask;
85+
}
86+
87+
} // namespace detail
88+
89+
template <typename... Args>
90+
[[nodiscard]] constexpr options_manip set_options(Args... bits) {
91+
return options_manip{detail::build_mask(bits...), 0ul};
92+
}
93+
94+
template <typename T>
95+
[[nodiscard]] constexpr options_manip set_options(std::initializer_list<T> bits) {
96+
return options_manip{detail::build_mask_from(bits), 0ul};
97+
}
98+
99+
template <typename... Args>
100+
[[nodiscard]] constexpr options_manip clear_options(Args... bits) {
101+
return options_manip{0ul, detail::build_mask(bits...)};
102+
}
103+
104+
template <typename T>
105+
[[nodiscard]] constexpr options_manip clear_options(std::initializer_list<T> bits) {
106+
return options_manip{0ul, detail::build_mask_from(bits)};
107+
}
108+
109+
[[nodiscard]] gl_attr_force_inline bool is_option_set(
110+
std::ios_base& stream, bit_position_type bit_position
111+
) {
112+
return options_manip::is_option_set(stream, bit_position);
113+
}
114+
115+
[[nodiscard]] gl_attr_force_inline bool is_option_set(
116+
std::ios_base& stream, traits::c_enum auto bit
117+
) {
118+
return options_manip::is_option_set(stream, bit);
119+
}
120+
121+
[[nodiscard]] gl_attr_force_inline bool are_options_set(std::ios_base& stream, iword_type bitmask) {
122+
return options_manip::are_options_set(stream, bitmask);
123+
}
124+
125+
template <typename... Args>
126+
[[nodiscard]] gl_attr_force_inline bool are_options_set(std::ios_base& stream, Args... bits) {
127+
return options_manip::are_options_set(stream, detail::build_mask(bits...));
128+
}
129+
130+
template <typename T>
131+
[[nodiscard]] gl_attr_force_inline bool are_options_set(
132+
std::ios_base& stream, std::initializer_list<T> bits
133+
) {
134+
return options_manip::are_options_set(stream, detail::build_mask_from(bits));
135+
}
136+
137+
} // namespace gl::io
Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,11 @@
44

55
#pragma once
66

7-
#include "gl/attributes/force_inline.hpp"
8-
#include "gl/traits.hpp"
9-
107
#include <iostream>
118
#include <ranges>
129

1310
namespace gl::io {
1411

15-
// TODO: add tests
1612
template <std::ranges::range Range>
1713
struct range_formatter {
1814
Range range;
@@ -34,9 +30,21 @@ struct range_formatter {
3430
}
3531
};
3632

33+
// CTAD helpers
34+
3735
template <std::ranges::range R>
3836
range_formatter(R&& r) -> range_formatter<std::views::all_t<R>>;
3937

38+
template <std::ranges::range R>
39+
range_formatter(R&& r, std::string_view) -> range_formatter<std::views::all_t<R>>;
40+
41+
template <std::ranges::range R>
42+
range_formatter(R&& r, std::string_view, std::string_view) -> range_formatter<std::views::all_t<R>>;
43+
44+
template <std::ranges::range R>
45+
range_formatter(R&& r, std::string_view, std::string_view, std::string_view)
46+
-> range_formatter<std::views::all_t<R>>;
47+
4048
template <std::ranges::range R>
4149
auto set_formatter(R&& range, std::string_view sep = ", ") {
4250
using view_type = std::views::all_t<R>;
@@ -52,4 +60,33 @@ auto multiline_set_formatter(R&& range) {
5260
};
5361
}
5462

63+
template <std::integral T>
64+
struct implicit_range_formatter {
65+
T first;
66+
T last; // exclusive
67+
68+
friend std::ostream& operator<<(std::ostream& os, implicit_range_formatter proxy) {
69+
if (proxy.first >= proxy.last)
70+
return os << "{}";
71+
72+
const auto dist = proxy.last - proxy.first;
73+
if (dist == 1)
74+
return os << '{' << proxy.first << '}';
75+
if (dist == 2)
76+
return os << '{' << proxy.first << ", " << proxy.first + 1 << '}';
77+
78+
return os << '{' << proxy.first << ", ..., " << proxy.last - 1 << '}';
79+
}
80+
};
81+
82+
template <std::integral T>
83+
[[nodiscard]] constexpr auto implicit_range(T first, T last, bool inclusive = false) {
84+
return implicit_range_formatter<T>{first, last + static_cast<T>(inclusive)};
85+
}
86+
87+
template <std::integral T>
88+
[[nodiscard]] constexpr auto implicit_range(T last, bool inclusive = false) {
89+
return implicit_range(static_cast<T>(0), last, inclusive);
90+
}
91+
5592
} // namespace gl::io

0 commit comments

Comments
 (0)