File src/fs/fat.cpp changed (mode: 100644) (index a8659ca..2856226) |
... |
... |
using namespace fs; |
7 |
7 |
|
|
8 |
8 |
FAT::FAT(drv::ATA &hd, std::uint32_t partitionOffset) : hd(hd) |
FAT::FAT(drv::ATA &hd, std::uint32_t partitionOffset) : hd(hd) |
9 |
9 |
{ |
{ |
10 |
|
hd.read28(partitionOffset, as_writable_bytes(bpb)); |
|
|
10 |
|
std::uint8_t bpbData[512]; |
|
11 |
|
hd.read28(partitionOffset, bpbData); |
11 |
12 |
|
|
12 |
|
kprint("sectors per cluster: ", bpb.sectorsPerCluster, "\n"); |
|
|
13 |
|
BiosParameterBlock32 bpb(bpbData); |
13 |
14 |
|
|
14 |
15 |
fatStart = partitionOffset + bpb.reservedSectors; |
fatStart = partitionOffset + bpb.reservedSectors; |
15 |
16 |
dataStart = fatStart + bpb.tableSize*bpb.fatCopies; |
dataStart = fatStart + bpb.tableSize*bpb.fatCopies; |
16 |
17 |
rootStart = dataStart + bpb.sectorsPerCluster*(bpb.rootCluster - 2); |
rootStart = dataStart + bpb.sectorsPerCluster*(bpb.rootCluster - 2); |
|
18 |
|
sectorsPerCluster = bpb.sectorsPerCluster; |
|
19 |
|
|
|
20 |
|
kprint("sectors per cluster: ", sectorsPerCluster, "\n"); |
17 |
21 |
} |
} |
18 |
22 |
|
|
19 |
23 |
void |
void |
20 |
24 |
FAT::printFiles() |
FAT::printFiles() |
21 |
25 |
{ |
{ |
22 |
|
DirectoryEntryFat32 dirent[16]; |
|
23 |
|
hd.read28(rootStart, as_writable_bytes(dirent)); |
|
|
26 |
|
std::uint8_t dirData[512]; |
|
27 |
|
hd.read28(rootStart, dirData); |
|
28 |
|
|
|
29 |
|
std::uint8_t *dataPtr = dirData; |
|
30 |
|
Fields<DirectoryEntryFat32, 16> dirent(dataPtr); |
24 |
31 |
|
|
25 |
32 |
for (int i = 0; i < 16; ++i) { |
for (int i = 0; i < 16; ++i) { |
26 |
|
if (dirent[i].name[0] == 0x00) { |
|
|
33 |
|
DirectoryEntryFat32 &ent = dirent[i]; |
|
34 |
|
|
|
35 |
|
if (ent.name[0] == 0x00) { |
27 |
36 |
break; |
break; |
28 |
37 |
} |
} |
29 |
38 |
|
|
30 |
|
if ((dirent[i].attributes & 0x0f) == 0x0f) { |
|
|
39 |
|
if ((ent.attributes & 0x0f) == 0x0f) { |
31 |
40 |
continue; |
continue; |
32 |
41 |
} |
} |
33 |
42 |
|
|
34 |
43 |
char foo[] = " \n"; |
char foo[] = " \n"; |
35 |
44 |
for (int j = 0; j < 8; ++j) { |
for (int j = 0; j < 8; ++j) { |
36 |
|
foo[j] = dirent[i].name[j]; |
|
|
45 |
|
foo[j] = ent.name[j]; |
37 |
46 |
} |
} |
38 |
47 |
kprint(foo); |
kprint(foo); |
39 |
48 |
|
|
40 |
49 |
// Skip directories. |
// Skip directories. |
41 |
|
if (!(dirent[i].attributes & 0x10)) { |
|
42 |
|
printFileContents(dirent[i]); |
|
|
50 |
|
if (!(ent.attributes & 0x10)) { |
|
51 |
|
printFileContents(ent); |
43 |
52 |
} |
} |
44 |
53 |
} |
} |
45 |
54 |
} |
} |
|
... |
... |
FAT::printFileContents(const DirectoryEntryFat32 &ent) const |
56 |
65 |
|
|
57 |
66 |
while (size > 0) { |
while (size > 0) { |
58 |
67 |
std::uint32_t sector = dataStart |
std::uint32_t sector = dataStart |
59 |
|
+ bpb.sectorsPerCluster*(currentCluster - 2); |
|
60 |
|
int sectorOffset = 0; |
|
|
68 |
|
+ sectorsPerCluster*(currentCluster - 2); |
|
69 |
|
std::uint32_t sectorOffset = 0; |
61 |
70 |
|
|
62 |
71 |
while (size > 0) { |
while (size > 0) { |
63 |
72 |
hd.read28(sector + sectorOffset, { buffer, 512 }); |
hd.read28(sector + sectorOffset, { buffer, 512 }); |
|
... |
... |
FAT::printFileContents(const DirectoryEntryFat32 &ent) const |
67 |
76 |
|
|
68 |
77 |
size -= 512; |
size -= 512; |
69 |
78 |
|
|
70 |
|
if (++sectorOffset == bpb.sectorsPerCluster) { |
|
|
79 |
|
if (++sectorOffset == sectorsPerCluster) { |
71 |
80 |
break; |
break; |
72 |
81 |
} |
} |
73 |
82 |
} |
} |
File src/fs/fat.hpp changed (mode: 100644) (index 9c37b88..0256b67) |
3 |
3 |
|
|
4 |
4 |
#include <cstdint> |
#include <cstdint> |
5 |
5 |
|
|
|
6 |
|
#include "utils/struct.hpp" |
|
7 |
|
|
6 |
8 |
namespace drv { |
namespace drv { |
7 |
9 |
class ATA; |
class ATA; |
8 |
10 |
} |
} |
|
... |
... |
namespace fs { |
11 |
13 |
|
|
12 |
14 |
struct BiosParameterBlock32 |
struct BiosParameterBlock32 |
13 |
15 |
{ |
{ |
14 |
|
std::uint8_t jump[3]; |
|
15 |
|
std::uint8_t softName[8]; |
|
16 |
|
std::uint16_t bytesPerSector; |
|
17 |
|
std::uint8_t sectorsPerCluster; |
|
18 |
|
std::uint16_t reservedSectors; |
|
19 |
|
std::uint8_t fatCopies; |
|
20 |
|
std::uint16_t rootDirEntries; |
|
21 |
|
std::uint16_t totalSectors; |
|
22 |
|
std::uint8_t mediaType; |
|
23 |
|
std::uint16_t fatSectorCount; |
|
24 |
|
std::uint16_t sectorsPerTrack; |
|
25 |
|
std::uint16_t headCount; |
|
26 |
|
std::uint32_t hiddenSectors; |
|
27 |
|
std::uint32_t totalSectorCount; |
|
|
16 |
|
Fields<std::uint8_t, 3> jump; |
|
17 |
|
Fields<std::uint8_t, 8> softName; |
|
18 |
|
Field<std::uint16_t> bytesPerSector; |
|
19 |
|
Field<std::uint8_t> sectorsPerCluster; |
|
20 |
|
Field<std::uint16_t> reservedSectors; |
|
21 |
|
Field<std::uint8_t> fatCopies; |
|
22 |
|
Field<std::uint16_t> rootDirEntries; |
|
23 |
|
Field<std::uint16_t> totalSectors; |
|
24 |
|
Field<std::uint8_t> mediaType; |
|
25 |
|
Field<std::uint16_t> fatSectorCount; |
|
26 |
|
Field<std::uint16_t> sectorsPerTrack; |
|
27 |
|
Field<std::uint16_t> headCount; |
|
28 |
|
Field<std::uint32_t> hiddenSectors; |
|
29 |
|
Field<std::uint32_t> totalSectorCount; |
|
30 |
|
|
|
31 |
|
Field<std::uint32_t> tableSize; |
|
32 |
|
Field<std::uint16_t> extFlags; |
|
33 |
|
Field<std::uint16_t> fatVersion; |
|
34 |
|
Field<std::uint32_t> rootCluster; |
|
35 |
|
Field<std::uint16_t> fatInfo; |
|
36 |
|
Field<std::uint16_t> backupSector; |
|
37 |
|
Fields<std::uint8_t, 12> reserved0; |
|
38 |
|
Field<std::uint8_t> driveNumber; |
|
39 |
|
Field<std::uint8_t> reserved; |
|
40 |
|
Field<std::uint8_t> bootSignature; |
|
41 |
|
Field<std::uint32_t> volumeId; |
|
42 |
|
Fields<std::uint8_t, 11> volumeLabel; |
|
43 |
|
Fields<std::uint8_t, 8> fatTypeLabel; |
28 |
44 |
|
|
29 |
|
std::uint32_t tableSize; |
|
30 |
|
std::uint16_t extFlags; |
|
31 |
|
std::uint16_t fatVersion; |
|
32 |
|
std::uint32_t rootCluster; |
|
33 |
|
std::uint16_t fatInfo; |
|
34 |
|
std::uint16_t backupSector; |
|
35 |
|
std::uint8_t reserved0[12]; |
|
36 |
|
std::uint8_t driveNumber; |
|
37 |
|
std::uint8_t reserved; |
|
38 |
|
std::uint8_t bootSignature; |
|
39 |
|
std::uint32_t volumeId; |
|
40 |
|
std::uint8_t volumeLabel[11]; |
|
41 |
|
std::uint8_t fatTypeLabel[8]; |
|
42 |
|
} __attribute__((packed)); |
|
|
45 |
|
explicit BiosParameterBlock32(std::uint8_t data[]) |
|
46 |
|
: jump(data), softName(data), bytesPerSector(data), |
|
47 |
|
sectorsPerCluster(data), reservedSectors(data), fatCopies(data), |
|
48 |
|
rootDirEntries(data), totalSectors(data), mediaType(data), |
|
49 |
|
fatSectorCount(data), sectorsPerTrack(data), headCount(data), |
|
50 |
|
hiddenSectors(data), totalSectorCount(data), tableSize(data), |
|
51 |
|
extFlags(data), fatVersion(data), rootCluster(data), fatInfo(data), |
|
52 |
|
backupSector(data), reserved0(data), driveNumber(data), |
|
53 |
|
reserved(data), bootSignature(data), volumeId(data), |
|
54 |
|
volumeLabel(data), fatTypeLabel(data) |
|
55 |
|
{ |
|
56 |
|
} |
|
57 |
|
}; |
43 |
58 |
|
|
44 |
59 |
struct DirectoryEntryFat32 |
struct DirectoryEntryFat32 |
45 |
60 |
{ |
{ |
46 |
|
std::uint8_t name[8]; |
|
47 |
|
std::uint8_t ext[3]; |
|
48 |
|
std::uint8_t attributes; |
|
49 |
|
std::uint8_t reserved; |
|
50 |
|
std::uint8_t cTimeTenth; |
|
51 |
|
std::uint16_t cTime; |
|
52 |
|
std::uint16_t cDate; |
|
53 |
|
std::uint16_t aTime; |
|
54 |
|
std::uint16_t firstClusterHi; |
|
55 |
|
std::uint16_t wTime; |
|
56 |
|
std::uint16_t wDate; |
|
57 |
|
std::uint16_t firstClusterLow; |
|
58 |
|
std::uint32_t size; |
|
59 |
|
} __attribute__((packed)); |
|
|
61 |
|
Fields<std::uint8_t, 8> name; |
|
62 |
|
Fields<std::uint8_t, 3> ext; |
|
63 |
|
Field<std::uint8_t> attributes; |
|
64 |
|
Field<std::uint8_t> reserved; |
|
65 |
|
Field<std::uint8_t> cTimeTenth; |
|
66 |
|
Field<std::uint16_t> cTime; |
|
67 |
|
Field<std::uint16_t> cDate; |
|
68 |
|
Field<std::uint16_t> aTime; |
|
69 |
|
Field<std::uint16_t> firstClusterHi; |
|
70 |
|
Field<std::uint16_t> wTime; |
|
71 |
|
Field<std::uint16_t> wDate; |
|
72 |
|
Field<std::uint16_t> firstClusterLow; |
|
73 |
|
Field<std::uint32_t> size; |
|
74 |
|
|
|
75 |
|
explicit DirectoryEntryFat32(std::uint8_t *&data) |
|
76 |
|
: name(data), ext(data), attributes(data), reserved(data), |
|
77 |
|
cTimeTenth(data), cTime(data), cDate(data), aTime(data), |
|
78 |
|
firstClusterHi(data), wTime(data), wDate(data), firstClusterLow(data), |
|
79 |
|
size(data) |
|
80 |
|
{ |
|
81 |
|
} |
|
82 |
|
}; |
60 |
83 |
|
|
61 |
84 |
class FAT |
class FAT |
62 |
85 |
{ |
{ |
|
... |
... |
private: |
71 |
94 |
|
|
72 |
95 |
private: |
private: |
73 |
96 |
drv::ATA &hd; |
drv::ATA &hd; |
74 |
|
BiosParameterBlock32 bpb; |
|
75 |
97 |
std::uint32_t fatStart; |
std::uint32_t fatStart; |
76 |
98 |
std::uint32_t dataStart; |
std::uint32_t dataStart; |
77 |
99 |
std::uint32_t rootStart; |
std::uint32_t rootStart; |
|
100 |
|
std::uint32_t sectorsPerCluster; |
78 |
101 |
}; |
}; |
79 |
102 |
|
|
80 |
103 |
} |
} |
File src/fs/mbr.cpp changed (mode: 100644) (index 09c1e21..6c32bc4) |
... |
... |
using namespace fs; |
10 |
10 |
void |
void |
11 |
11 |
MBR::readPartitions(drv::ATA &hd) |
MBR::readPartitions(drv::ATA &hd) |
12 |
12 |
{ |
{ |
13 |
|
MasterBootRecord mbr; |
|
14 |
|
|
|
15 |
13 |
kprint("MBR: "); |
kprint("MBR: "); |
16 |
14 |
|
|
17 |
|
hd.read28(0, as_writable_bytes(mbr)); |
|
|
15 |
|
std::uint8_t mbrSector[512]; |
|
16 |
|
hd.read28(0, mbrSector); |
|
17 |
|
|
|
18 |
|
MasterBootRecord mbr(mbrSector); |
18 |
19 |
|
|
19 |
20 |
if (mbr.magicnumber != 0xAA55) { |
if (mbr.magicnumber != 0xAA55) { |
20 |
21 |
kprint("illegal MBR"); |
kprint("illegal MBR"); |
|
... |
... |
MBR::readPartitions(drv::ATA &hd) |
23 |
24 |
|
|
24 |
25 |
kprint("\n"); |
kprint("\n"); |
25 |
26 |
for (std::uint8_t i = 0; i < 4; ++i) { |
for (std::uint8_t i = 0; i < 4; ++i) { |
26 |
|
if (mbr.primaryPartition[i].partition_id == 0x00) { |
|
|
27 |
|
const std::uint8_t id = mbr.primaryPartition[i]->partition_id; |
|
28 |
|
if (id == 0x00) { |
27 |
29 |
continue; |
continue; |
28 |
30 |
} |
} |
29 |
31 |
|
|
30 |
|
const char *is = mbr.primaryPartition[i].bootable == 0x80 ? "" : " not"; |
|
31 |
|
kprint(" Partition ", i, is, " bootable. Type 0x", |
|
32 |
|
mbr.primaryPartition[i].partition_id, ".\n"); |
|
|
32 |
|
const char *is = mbr.primaryPartition[i]->bootable == 0x80 ? "" |
|
33 |
|
: " not"; |
|
34 |
|
kprint(" Partition ", i, is, " bootable. Type 0x", id, ".\n"); |
33 |
35 |
|
|
34 |
|
FAT fat(hd, mbr.primaryPartition[i].start_lba); |
|
|
36 |
|
FAT fat(hd, mbr.primaryPartition[i]->start_lba); |
35 |
37 |
fat.printFiles(); |
fat.printFiles(); |
36 |
38 |
} |
} |
37 |
39 |
} |
} |
File src/fs/mbr.hpp changed (mode: 100644) (index 45749e7..d0adde5) |
3 |
3 |
|
|
4 |
4 |
#include <cstdint> |
#include <cstdint> |
5 |
5 |
|
|
|
6 |
|
#include "utils/struct.hpp" |
|
7 |
|
|
6 |
8 |
namespace drv { |
namespace drv { |
7 |
9 |
class ATA; |
class ATA; |
8 |
10 |
} |
} |
|
... |
... |
namespace fs { |
11 |
13 |
|
|
12 |
14 |
struct PartitionTableEntry |
struct PartitionTableEntry |
13 |
15 |
{ |
{ |
14 |
|
std::uint8_t bootable; |
|
15 |
|
|
|
16 |
|
std::uint8_t start_head; |
|
17 |
|
std::uint8_t start_sector : 6; |
|
18 |
|
std::uint16_t start_cylinder : 10; |
|
19 |
|
|
|
20 |
|
std::uint8_t partition_id; |
|
21 |
|
|
|
22 |
|
std::uint8_t end_head; |
|
23 |
|
std::uint8_t end_sector : 6; |
|
24 |
|
std::uint16_t end_cylinder : 10; |
|
25 |
|
|
|
26 |
|
std::uint32_t start_lba; |
|
27 |
|
std::uint32_t length; |
|
28 |
|
} __attribute__((packed)); |
|
|
16 |
|
Field<std::uint8_t> bootable; |
|
17 |
|
Field<std::uint32_t, 3> startCHS; |
|
18 |
|
Field<std::uint8_t> partition_id; |
|
19 |
|
Field<std::uint32_t, 3> endCHS; |
|
20 |
|
Field<std::uint32_t> start_lba; |
|
21 |
|
Field<std::uint32_t> length; |
|
22 |
|
|
|
23 |
|
explicit PartitionTableEntry(std::uint8_t *&data) |
|
24 |
|
: bootable(data), startCHS(data), partition_id(data), endCHS(data), |
|
25 |
|
start_lba(data), length(data) |
|
26 |
|
{ |
|
27 |
|
} |
|
28 |
|
|
|
29 |
|
static constexpr std::ptrdiff_t size() |
|
30 |
|
{ |
|
31 |
|
return 16; |
|
32 |
|
} |
|
33 |
|
}; |
29 |
34 |
|
|
30 |
35 |
struct MasterBootRecord |
struct MasterBootRecord |
31 |
36 |
{ |
{ |
32 |
|
std::uint8_t bootloader[440]; |
|
33 |
|
std::uint32_t signature; |
|
34 |
|
std::uint16_t unused; |
|
|
37 |
|
Fields<std::uint8_t, 440> bootloader; |
|
38 |
|
Field<std::uint32_t> signature; |
|
39 |
|
Field<std::uint16_t> unused; |
35 |
40 |
|
|
36 |
|
PartitionTableEntry primaryPartition[4]; |
|
|
41 |
|
Fields<PartitionTableEntry, 4> primaryPartition; |
37 |
42 |
|
|
38 |
|
std::uint16_t magicnumber; |
|
39 |
|
} __attribute__((packed)); |
|
|
43 |
|
Field<std::uint16_t> magicnumber; |
|
44 |
|
|
|
45 |
|
explicit MasterBootRecord(std::uint8_t data[]) |
|
46 |
|
: bootloader(data), signature(data), unused(data), |
|
47 |
|
primaryPartition(data), magicnumber(data) |
|
48 |
|
{ |
|
49 |
|
} |
|
50 |
|
}; |
40 |
51 |
|
|
41 |
52 |
class MBR |
class MBR |
42 |
53 |
{ |
{ |
File src/utils/struct.hpp changed (mode: 100644) (index 3bdf2c4..2b5005c) |
... |
... |
private: |
91 |
91 |
NetOrder<T> cached; |
NetOrder<T> cached; |
92 |
92 |
}; |
}; |
93 |
93 |
|
|
|
94 |
|
template <typename T, std::size_t N = sizeof(T)> |
|
95 |
|
class Field |
|
96 |
|
{ |
|
97 |
|
static_assert(std::is_integral<T>::value, |
|
98 |
|
"Field accepts only integral types!"); |
|
99 |
|
static_assert(!std::is_signed<T>::value, |
|
100 |
|
"Field accepts only unsigned types!"); |
|
101 |
|
static_assert(N <= sizeof(T), |
|
102 |
|
"Field width can't be bigger than size of the type!"); |
|
103 |
|
static_assert(N > 0U, |
|
104 |
|
"Field can't handle field of zero width!"); |
|
105 |
|
|
|
106 |
|
public: |
|
107 |
|
static constexpr std::size_t size = N; |
|
108 |
|
|
|
109 |
|
public: |
|
110 |
|
explicit Field(std::uint8_t *&data) : ptr(data), cached() |
|
111 |
|
{ |
|
112 |
|
for (std::size_t i = N; i != 0U; --i) { |
|
113 |
|
cached = (cached << 8) | ptr[i - 1U]; |
|
114 |
|
} |
|
115 |
|
data += N; |
|
116 |
|
} |
|
117 |
|
|
|
118 |
|
// Fields aren't supposed to be copied or assigned in any way. |
|
119 |
|
Field(Field &&rhs) = delete; |
|
120 |
|
Field & operator=(Field &&rhs) = delete; |
|
121 |
|
|
|
122 |
|
public: |
|
123 |
|
Field & operator=(T value) |
|
124 |
|
{ |
|
125 |
|
cached = value; |
|
126 |
|
for (std::size_t i = 0; i < N; ++i) { |
|
127 |
|
ptr[i] = value & 0xff; |
|
128 |
|
value >>= 8; |
|
129 |
|
} |
|
130 |
|
return *this; |
|
131 |
|
} |
|
132 |
|
|
|
133 |
|
operator T() const |
|
134 |
|
{ |
|
135 |
|
return cached; |
|
136 |
|
} |
|
137 |
|
|
|
138 |
|
private: |
|
139 |
|
std::uint8_t *ptr; |
|
140 |
|
T cached; |
|
141 |
|
}; |
|
142 |
|
|
|
143 |
|
template <typename T, bool = std::is_integral<T>::value> |
|
144 |
|
class ArrayField |
|
145 |
|
{ |
|
146 |
|
public: |
|
147 |
|
static constexpr std::size_t N = T::size(); |
|
148 |
|
static constexpr std::size_t size = N; |
|
149 |
|
|
|
150 |
|
public: |
|
151 |
|
explicit ArrayField(std::uint8_t *&data) : field(data) |
|
152 |
|
{ |
|
153 |
|
} |
|
154 |
|
|
|
155 |
|
// Fields aren't supposed to be copied or assigned in any way. |
|
156 |
|
ArrayField(ArrayField &&rhs) = delete; |
|
157 |
|
ArrayField & operator=(ArrayField &&rhs) = delete; |
|
158 |
|
|
|
159 |
|
public: |
|
160 |
|
operator T&() |
|
161 |
|
{ |
|
162 |
|
return field; |
|
163 |
|
} |
|
164 |
|
|
|
165 |
|
T * operator->() |
|
166 |
|
{ |
|
167 |
|
return &field; |
|
168 |
|
} |
|
169 |
|
|
|
170 |
|
private: |
|
171 |
|
T field; |
|
172 |
|
}; |
|
173 |
|
|
|
174 |
|
template <typename T> |
|
175 |
|
class ArrayField<T, true> |
|
176 |
|
{ |
|
177 |
|
static_assert(!std::is_signed<T>::value, |
|
178 |
|
"ArrayField accepts only unsigned types!"); |
|
179 |
|
|
|
180 |
|
public: |
|
181 |
|
static constexpr std::size_t N = sizeof(T); |
|
182 |
|
static constexpr std::size_t size = N; |
|
183 |
|
|
|
184 |
|
public: |
|
185 |
|
explicit ArrayField(std::uint8_t *&data) : ptr(data), cached() |
|
186 |
|
{ |
|
187 |
|
for (std::size_t i = N; i != 0U; --i) { |
|
188 |
|
cached = (cached << 8) | ptr[i - 1U]; |
|
189 |
|
} |
|
190 |
|
data += N; |
|
191 |
|
} |
|
192 |
|
|
|
193 |
|
// Fields aren't supposed to be copied or assigned in any way. |
|
194 |
|
ArrayField(ArrayField &&rhs) = delete; |
|
195 |
|
ArrayField & operator=(ArrayField &&rhs) = delete; |
|
196 |
|
|
|
197 |
|
public: |
|
198 |
|
ArrayField & operator=(T value) |
|
199 |
|
{ |
|
200 |
|
cached = value; |
|
201 |
|
for (std::size_t i = 0; i < N; ++i) { |
|
202 |
|
ptr[i] = value & 0xff; |
|
203 |
|
value >>= 8; |
|
204 |
|
} |
|
205 |
|
return *this; |
|
206 |
|
} |
|
207 |
|
|
|
208 |
|
operator T() const |
|
209 |
|
{ |
|
210 |
|
return cached; |
|
211 |
|
} |
|
212 |
|
|
|
213 |
|
private: |
|
214 |
|
std::uint8_t *ptr; |
|
215 |
|
T cached; |
|
216 |
|
}; |
|
217 |
|
|
|
218 |
|
template <typename T, std::size_t C> |
|
219 |
|
class Fields |
|
220 |
|
{ |
|
221 |
|
static_assert(C > 0U, "Fields can't have zero size!"); |
|
222 |
|
|
|
223 |
|
public: |
|
224 |
|
static constexpr std::size_t size = C*ArrayField<T>::size(); |
|
225 |
|
|
|
226 |
|
public: |
|
227 |
|
explicit Fields(std::uint8_t *&data) |
|
228 |
|
{ |
|
229 |
|
for (std::size_t i = 0U; i < C; ++i) { |
|
230 |
|
fields[i] = new(&datas[i].field) ArrayField<T>(data); |
|
231 |
|
} |
|
232 |
|
} |
|
233 |
|
|
|
234 |
|
~Fields() |
|
235 |
|
{ |
|
236 |
|
for (Data &field : datas) { |
|
237 |
|
field.field.~ArrayField(); |
|
238 |
|
} |
|
239 |
|
} |
|
240 |
|
|
|
241 |
|
// Fields aren't supposed to be copied or assigned in any way. |
|
242 |
|
Fields(Fields &&rhs) = delete; |
|
243 |
|
Fields & operator=(Fields &&rhs) = delete; |
|
244 |
|
|
|
245 |
|
public: |
|
246 |
|
ArrayField<T> & operator[](std::size_t idx) |
|
247 |
|
{ |
|
248 |
|
return *fields[idx]; |
|
249 |
|
} |
|
250 |
|
|
|
251 |
|
private: |
|
252 |
|
union Data { |
|
253 |
|
ArrayField<T> field; |
|
254 |
|
|
|
255 |
|
Data() {} |
|
256 |
|
~Data() {} |
|
257 |
|
}; |
|
258 |
|
Data datas[C]; |
|
259 |
|
|
|
260 |
|
ArrayField<T> *fields[C]; |
|
261 |
|
}; |
|
262 |
|
|
94 |
263 |
#endif // TOS__UTILS__STRUCT_HPP__ |
#endif // TOS__UTILS__STRUCT_HPP__ |