Skip to content

Commit e2ce880

Browse files
committed
refactor: Improve byte_span with type safety, flexible construction, and string handling
1 parent 6027d5c commit e2ce880

1 file changed

Lines changed: 97 additions & 81 deletions

File tree

README.md

Lines changed: 97 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,96 @@
1-
# byte_span
1+
# range3::byte_span
22

3-
`byte_span` is a lightweight view class for efficient handling of byte data. Based on the concept of `std::span`, it provides specialized functionality for byte data manipulation.
3+
byte_span is a non-owning view class for byte sequences, similar to std::span.
4+
It provides unified handling of byte-like types (`std::byte`, `char`, `unsigned char`)
5+
and allows viewing any trivially copyable data as a byte sequence.
46

57
## Features
68

7-
- Non-owning view type
9+
- Non-owning view type with zero overhead
810
- Unified handling of byte-like types (`std::byte`, `char`, `unsigned char`)
9-
- View trivially copyable data types as byte sequences
11+
- View any trivially copyable type as byte sequences
12+
- Compatible with any contiguous range (vectors, arrays, C-style arrays)
1013
- Type-safe design using C++20 concepts
11-
- Zero-overhead abstraction
1214

1315
## Basic Usage
1416

15-
### 1. Creating from Byte Arrays
17+
### Creating from Byte-like Types
1618

17-
The most basic usage is creating a `byte_span` from a byte array:
19+
The most common use case is creating a byte view from containers of byte-like types:
1820

1921
```cpp
20-
std::byte data[4] = {
21-
std::byte{0x00}, std::byte{0x01},
22-
std::byte{0x02}, std::byte{0x03}
22+
std::vector<char> chars = {'a', 'b', 'c'};
23+
byte_span view1{chars}; // Deduced as byte_span<std::byte>
24+
25+
unsigned char raw[4] = {0x00, 0x01, 0x02, 0x03};
26+
byte_span view2{raw}; // Deduced as byte_span<std::byte, 4>
27+
28+
std::array<std::byte, 3> bytes = {
29+
std::byte{1}, std::byte{2}, std::byte{3}
2330
};
24-
byte_span view{data}; // Deduced as byte_span<std::byte, 4>
31+
byte_span view3{bytes}; // Deduced as byte_span<std::byte, 3>
2532
```
2633
27-
### 2. Creating from std::array
28-
29-
Easy creation from `std::array`:
34+
### Creating from Any Trivially Copyable Type
35+
View any trivially copyable data as bytes:
3036
3137
```cpp
32-
std::array<std::byte, 4> arr = {
33-
std::byte{0x00}, std::byte{0x01},
34-
std::byte{0x02}, std::byte{0x03}
35-
};
36-
byte_span view{arr}; // Deduced as byte_span<std::byte, 4>
38+
// From vector of integers
39+
std::vector<int> ints = {1, 2, 3};
40+
byte_span view1{ints}; // Deduced as byte_span<std::byte>
41+
assert(view1.size() == sizeof(int) * 3);
42+
43+
// From custom struct
44+
struct Point {
45+
float x, y;
46+
};
47+
Point p{1.0f, 2.0f};
48+
byte_span view2{&p, 1}; // Deduced as byte_span<std::byte>
49+
assert(view2.size() == sizeof(Point)); // sizeof(Point) = 8 bytes (typically)
3750
```
3851

39-
### 3. Creating from std::vector
52+
### Dynamic and Static Extents
53+
```cpp
54+
// Dynamic extent (size known at runtime)
55+
std::vector<std::byte> vec(100);
56+
byte_span view1{vec}; // Deduced as byte_span<std::byte, dynamic_extent>
4057

41-
You can create views from any contiguous container, including `std::vector`:
58+
// Static extent (size known at compile time)
59+
std::array<char, 4> arr = {'a', 'b', 'c', 'd'};
60+
byte_span view2{arr}; // Deduced as byte_span<std::byte, 4>
4261

43-
```cpp
44-
// Integer data
45-
std::vector<int> numbers = {1, 2, 3, 4};
46-
byte_span view{numbers}; // View integers as bytes
62+
// Converting from static to dynamic extent is always possible
63+
byte_view view3 = view2; // OK: byte_view has dynamic extent
4764

48-
// Access underlying bytes
49-
auto first_byte = view[0];
50-
auto size_in_bytes = view.size(); // size = sizeof(int) * numbers.size()
65+
// Converting from dynamic to static extent requires explicit extent
66+
std::vector<char> vec2(4);
67+
byte_span<std::byte, 4> view4{vec2}; // OK if vec2.size() == 4
5168
```
5269
53-
### 4. Dynamic Size Views
70+
## Advanced Usage
5471
55-
For runtime-sized views, use `dynamic_extent`:
72+
### Using byte_view and cbyte_view
5673
57-
```cpp
58-
std::vector<std::byte> vec(100);
59-
byte_span view{vec}; // Deduced as byte_span<std::byte, dynamic_extent>
60-
```
74+
Two convenient aliases are provided:
75+
- `byte_view`: Alias for `byte_span<std::byte>` (mutable, dynamic_extent)
76+
- `cbyte_view`: Alias for `byte_span<const std::byte>` (immutable, dynamic_extent)
6177
62-
## Advanced Usage
78+
Example:
6379
64-
### 1. Using byte_view and cbyte_view
80+
```cpp
81+
void process_bytes(cbyte_view data) { // Accept any byte-like input
82+
for (auto b : data) {
83+
std::cout << std::format("{:02x} ", std::to_integer<int>(b));
84+
}
85+
}
6586
66-
The library provides two convenient type aliases:
67-
- `byte_view`: Mutable byte span (alias for `byte_span<std::byte>`)
68-
- `cbyte_view`: Immutable byte span (alias for `byte_span<const std::byte>`)
87+
// Works with any byte-like container
88+
std::vector<char> chars = {'a', 'b', 'c'};
89+
process_bytes(chars);
6990
70-
Example usage in functions:
91+
std::array<unsigned char, 4> raw = {0x00, 0x01, 0x02, 0x03};
92+
process_bytes(raw);
93+
```
7194

7295
```cpp
7396
// Function accepting read-only byte view
@@ -90,68 +113,61 @@ fill_pattern(buffer); // Modify buffer
90113
print_hex_dump(buffer); // Read buffer
91114
```
92115
93-
### 2. Trivially Copyable Types as Byte Views
94-
95-
Any trivially copyable type can be viewed as bytes:
116+
### Error Handling
117+
`byte_span` provides safety guarantees at both compile-time and runtime:
96118
97119
```cpp
98-
struct Point {
99-
float x;
100-
float y;
120+
// Compile-time checks
121+
struct non_trivially_copyable {
122+
std::string str; // non-trivially copyable member
101123
};
124+
non_trivially_copyable obj;
125+
byte_span view{obj}; // Compilation error: type requirements not met
102126
103-
Point p{1.0f, 2.0f};
104-
byte_span view{std::span{&p, 1}}; // View Point's bytes
105-
```
106-
107-
### 3. String Data Handling
127+
// Extent mismatch
128+
std::vector<char> vec(3);
129+
byte_span<std::byte, 4> view{vec}; // Runtime assertion failure: size mismatch
108130
109-
String data can be easily handled:
110-
111-
```cpp
112-
std::string str = "Hello, World!";
113-
byte_span view{str}; // View string data as bytes
114-
115-
// Convert to string_view
116-
auto sv = as_sv(view); // Get as std::string_view
131+
std::array<char, 8> arr;
132+
byte_span<std::byte, 4> view{arr}; // Compilation error: static extent mismatch
117133
```
118134

119-
### 4. Implicit Conversion in Function Arguments
120-
121-
Functions can accept various container types through implicit conversion:
135+
### String Handling
136+
Work seamlessly with string types:
122137

123138
```cpp
124-
void process_bytes(byte_span view) {
125-
// Process byte data
126-
}
127-
128-
// Various ways to call
129-
std::vector<std::byte> vec(100);
130-
process_bytes(vec); // OK
139+
std::string str = "Hello";
140+
byte_span view1{str}; // View string data as bytes
131141

132-
std::array<char, 10> arr;
133-
process_bytes(arr); // OK
142+
std::string_view sv = "World";
143+
byte_span view2{sv}; // View string_view data as bytes
144+
// Note: does not include null terminator
134145

135-
unsigned char raw_data[20];
136-
process_bytes(raw_data); // OK
146+
// Convert back to string_view
147+
auto sv2 = as_sv(view1); // Get std::string_view
137148
```
138149
139-
### 5. Data Type Conversions
150+
### Type Conversions
140151
141-
Safe data type conversions:
152+
Safe conversions between types:
142153
143154
```cpp
144155
std::vector<int> numbers = {1, 2, 3, 4};
145156
byte_span view{numbers};
146157
147-
// Read as span of ints
148-
auto int_span = as_span<int>(view);
149-
// Get first value
150-
auto& first_int = as_value<int>(view);
151-
```
158+
// Convert to span of ints
159+
std::span<const int> cint_span = as_span<int>(view);
160+
std::span<int> int_span = as_writable_span<int>(view);
152161
153-
### 6. Creating Sub-views
162+
// Get reference to first value
163+
const int& first = as_value<int>(view);
164+
165+
// Convert to std::span of bytes
166+
std::span<const std::byte> cbyte_std_span = as_bytes(view);
167+
std::span<std::byte> byte_std_span = as_writable_bytes(view);
168+
```
154169

170+
### Sub-views
155171
Create views of specific ranges:
156172

157173
```cpp

0 commit comments

Comments
 (0)