File: Stream.h

package info (click to toggle)
jazz2-native 3.5.0-3
  • links: PTS, VCS
  • area: contrib
  • in suites: forky, sid
  • size: 16,912 kB
  • sloc: cpp: 172,557; xml: 113; python: 36; makefile: 5; sh: 2
file content (152 lines) | stat: -rw-r--r-- 6,212 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#pragma once

#if defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ < 24
//	Android fully supports 64-bit file offsets only for API 24 and above.
#elif !defined(DOXYGEN_GENERATING_OUTPUT)
#	define _FILE_OFFSET_BITS 64
#endif

// Enable newer ABI on Mac OS 10.5 and later, which is needed for struct stat to have birthtime members
#if defined(__APPLE__) || defined(__MACH__)
#	define _DARWIN_USE_64_BIT_INODE 1
#endif

#include "../Common.h"
#include "../Base/IDisposable.h"

#if defined(DEATH_TARGET_BIG_ENDIAN)
#	include "../Base/Memory.h"
#endif

#include <type_traits>

namespace Death { namespace IO {
//###==##====#=====--==~--~=~- --- -- -  -  -   -

	/**
		@brief Specifies the position in a stream to use for seeking
	*/
	enum class SeekOrigin {
		/** @brief Specifies the beginning of a stream */
		Begin,
		/** @brief Specifies the current position within a stream */
		Current,
		/** @brief Specifies the end of a stream */
		End
	};

	/**
		@brief Provides a generic view of a sequence of bytes
	*/
	class Stream : public IDisposable
	{
	public:
		enum {
			/** @brief Returned if @ref Stream doesn't point to valid source */
			Invalid = -1,
			/** @brief Returned if one of the parameters provided to a method is not valid */
			OutOfRange = -2,
			/** @brief Returned if seek operation is not supported by @ref Stream or the stream length is unknown */
			NotSeekable = -3
		};

		/** @brief Whether the stream has been sucessfully opened */
		explicit operator bool() {
			return IsValid();
		}

		/** @brief Closes the stream and releases all assigned resources */
		virtual void Dispose() = 0;
		/** @brief Seeks in an opened stream */
		virtual std::int64_t Seek(std::int64_t offset, SeekOrigin origin) = 0;
		/** @brief Tells the seek position of an opened stream */
		virtual std::int64_t GetPosition() const = 0;
		/** @brief Reads a certain amount of bytes from the stream to a buffer */
		virtual std::int64_t Read(void* destination, std::int64_t bytesToRead) = 0;
		/** @brief Writes a certain amount of bytes from a buffer to the stream */
		virtual std::int64_t Write(const void* source, std::int64_t bytesToWrite) = 0;
		/** @brief Clears all buffers for this stream and causes any buffered data to be written to the underlying device */
		virtual bool Flush() = 0;
		/** @brief Returns `true` if the stream has been sucessfully opened */
		virtual bool IsValid() = 0;

		/** @brief Returns stream size in bytes */
		virtual std::int64_t GetSize() const = 0;
		/** @brief Sets stream size in bytes */
		virtual std::int64_t SetSize(std::int64_t size) = 0;

		/** @brief Reads the bytes from the current stream and writes them to the target stream */
		std::int64_t CopyTo(Stream& targetStream);

		/** @brief Reads a trivial value from the stream */
		template<typename T>
		DEATH_ALWAYS_INLINE T ReadValue()
		{
			static_assert(std::is_trivially_copyable<T>::value, "ReadValue() requires the source type to be trivially copyable");
			static_assert(!std::is_pointer<T>::value && !std::is_reference<T>::value, "ReadValue() must not be used on pointer or reference types");

			T value{};
			Read(&value, sizeof(T));
			return value;
		}

		/** @brief Writes a trivial value to the stream */
		template<typename T>
		DEATH_ALWAYS_INLINE void WriteValue(const T& value)
		{
			static_assert(std::is_trivially_copyable<T>::value, "WriteValue() requires the source type to be trivially copyable");
			static_assert(!std::is_pointer<T>::value && !std::is_reference<T>::value, "WriteValue() must not be used on pointer or reference types");

			Write(&value, sizeof(T));
		}

		/** @brief Reads a trivial value from the stream always as Little-Endian */
		template<typename T>
		DEATH_ALWAYS_INLINE T ReadValueAsLE()
		{
			static_assert(std::is_trivially_copyable<T>::value, "ReadValueAsLE() requires the source type to be trivially copyable");
			static_assert(!std::is_pointer<T>::value && !std::is_reference<T>::value, "ReadValueAsLE() must not be used on pointer or reference types");
			static_assert(sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8, "ReadValueAsLE() requires the source type to be 2, 4 or 8 bytes");

			T value{};
			Read(&value, sizeof(T));
#if defined(DEATH_TARGET_BIG_ENDIAN)
			value = Memory::SwapBytes(value);
#endif
			return value;
		}

		/** @brief Writes a trivial value to the stream always as Little-Endian */
		template<typename T>
		DEATH_ALWAYS_INLINE void WriteValueAsLE(T value)
		{
			static_assert(std::is_trivially_copyable<T>::value, "WriteValueAsLE() requires the source type to be trivially copyable");
			static_assert(!std::is_pointer<T>::value && !std::is_reference<T>::value, "WriteValueAsLE() must not be used on pointer or reference types");
			static_assert(sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8, "WriteValueAsLE() requires the source type to be 2, 4 or 8 bytes");

#if defined(DEATH_TARGET_BIG_ENDIAN)
			value = Memory::SwapBytes(value);
#endif
			Write(&value, sizeof(T));
		}

		/** @brief Reads a 32-bit integer value from the stream using variable-length quantity encoding */
		std::int32_t ReadVariableInt32();
		/** @brief Reads a 64-bit integer value from the stream using variable-length quantity encoding */
		std::int64_t ReadVariableInt64();
		/** @brief Reads a 32-bit unsigned integer value from the stream using variable-length quantity encoding */
		std::uint32_t ReadVariableUint32();
		/** @brief Reads a 64-bit unsigned integer value from the stream using variable-length quantity encoding */
		std::uint64_t ReadVariableUint64();

		/** @brief Writes a 32-bit integer value to the stream using variable-length quantity encoding */
		std::int64_t WriteVariableInt32(std::int32_t value);
		/** @brief Writes a 64-bit integer value to the stream using variable-length quantity encoding */
		std::int64_t WriteVariableInt64(std::int64_t value);
		/** @brief Writes a 32-bit unsigned integer value to the stream using variable-length quantity encoding */
		std::int64_t WriteVariableUint32(std::uint32_t value);
		/** @brief Writes a 64-bit unsigned integer value to the stream using variable-length quantity encoding */
		std::int64_t WriteVariableUint64(std::uint64_t value);
	};

}}