@@ -215,12 +215,40 @@ unpin arr@(MutableByteArray marr#) =
215215
216216-- XXX generate error if the size is < 1
217217
218+-- = Design notes =
219+--
220+-- == Fixed length data types ==
221+--
222+-- The main goal of the Unbox type class is to be used in arrays. Invariants
223+-- for the sizeOf value required for use in arrays:
224+--
225+-- * size is independent of the value, it is determined by the type only. So
226+-- that we can store values of the same type in fixed length array cells.
227+-- * recursive data types cannot be fixed length, therefore, cannot be
228+-- serialized using this type class.
229+-- * size cannot be zero. So that the length of an array storing the element
230+-- and the number of elements can be related.
231+--
232+-- Note, for general serializable types the size cannot be fixed e.g. we may
233+-- want to serialize a list. This type class can be considered a special case
234+-- of a more general serialization type class.
235+--
236+-- == Stream vs Array ==
237+--
218238-- In theory we could convert a type to and from a byte stream and use that
219−-- to implement boxing, unboxing. But that would be inefficient. This type
220−-- class allows each primitive type to have its own specific efficient
221−-- implementation to read and write the type to memory.
239+-- to implement boxing, unboxing. But composing a stream from parts of the
240+-- structure is much more inefficient than writing them to a memory location.
241+-- However, it should be possible to efficiently parse a Haskell type from an
242+-- array using chunk folds.
222243--
223−-- This is a typeclass that uses MutableByteArray but could use ForeignPtr or
244+-- Also, this type class allows each primitive type to have its own specific
245+-- efficient implementation to read and write the type to the mutable byte
246+-- array using special GHC byte array operations. For example, see the Unbox
247+-- instances of Char, Int, Word types.
248+--
249+-- == MutableByteArray vs ForeignPtr ==
250+--
251+-- The Unbox typeclass uses MutableByteArray but could use ForeignPtr or
224252-- any other representation of memory. We could make this a multiparameter type
225253-- class if necessary.
226254--
@@ -231,38 +259,33 @@ unpin arr@(MutableByteArray marr#) =
231259-- ArrayContents, though it would require all instances to support reading from
232260-- a Ptr.
233261--
262+-- == Byte Offset vs Element Index ==
263+--
234264-- There is a reason for using byte offset instead of element index in read and
235−-- write operations in the type class. If we use element index slicing of the
265+-- write operations in the type class. If we use element index, slicing of the
236266-- array becomes rigid. We can only slice the array at addresses that are
237267-- aligned with the type, therefore, we cannot slice at misaligned location and
238−-- then cast the slice into another type which does not ncessarily align with
268+-- then cast the slice into another type which does not necessarily align with
239269-- the original type.
240270--
271+-- == Alignment ==
272+--
241273-- As a side note, there seem to be no performance advantage of alignment
242274-- anymore, see
243275-- https://lemire.me/blog/2012/05/31/data-alignment-for-speed-myth-or-reality/
244276--
245277
246−-- The main goal of the Unbox type class is to be used in arrays. Invariants
247−-- for the sizeOf value required for use in arrays:
278+-- | The 'Unbox' type class provides operations for serialization (unboxing)
279+-- and deserialization (boxing) of a fixed-length, non-recursive Haskell data
280+-- type to and from its unboxed byte representation in a mutable byte array.
248281--
249−-- * size is independent of the value, it is determined by the type only. So
250−-- that we can store values of the same type in fixed length array cells.
251−-- * size cannot be zero. So that the length of an array storing the element
252−-- and the number of elements can be related.
253−--
254−-- Note, for general serializable types the size cannot be fixed e.g. we may
255−-- want to serialize a list. This type class can be considered a special case
256−-- of a more general serialization type class.
257−
258−-- | A type implementing the 'Unbox' interface supplies operations for reading
259−-- and writing the type from and to a mutable byte array (an unboxed
260−-- representation of the type) in memory. The read operation 'peekByteIndex'
261−-- deserializes the boxed type from the mutable byte array. The write operation
262−-- 'pokeByteIndex' serializes the boxed type to the mutable byte array.
282+-- The 'peekByteIndex' read operation converts a Haskell type from its unboxed
283+-- representation stored in a mutable byte array, while the 'pokeByteIndex'
284+-- write operation serializes a Haskell data type to its byte representation in
285+-- the mutable byte array.
263286--
264−-- Instances can be derived via Generics or Template Haskell. Note that the data
265−-- type must be non-recursive.
287+-- Instances can be derived via Generics or Template Haskell. Note that the
288+-- data type must be non-recursive.
266289--
267290-- Here is an example, for deriving an instance of this type class using
268291-- generics: