Changed arrays to use vector/tockArrayView

Previously the arrays used the Blitz++ library, but this was not totally satisfactory.  I have therefore resorted (after looking at many different
libraries) to using std::vector (which could perhaps be boost::array instead) coupled with a roll-my-own "array view" class (tockArrayView) that
easily allows all the functionality that we need from arrays (slicing, indexing, copying, unknown dimensions,retyping,reshaping).  I have also
had to introduce a nasty little wrapper class tockBool, because vector<bool> is a specialisation that totally breaks things.  If I do move to
boost::array, I will be able to remove tockBool.
This commit is contained in:
Neil Brown 2007-07-31 21:19:52 +00:00
parent f997b823dc
commit a52d115060
2 changed files with 369 additions and 178 deletions

View File

@ -200,7 +200,7 @@ genInputSizeAssign :: A.InputItem -> CGen()
genInputSizeAssign (A.InVariable _ arr) genInputSizeAssign (A.InVariable _ arr)
= return () = return ()
genInputSizeAssign (A.InCounted _ count arr) genInputSizeAssign (A.InCounted _ count arr)
= genVariable count >> tell [" = "] >> genVariable arr >> tell [" .extent(blitz::firstDim);"] = genVariable count >> tell [" = "] >> genVariable arr >> tell [" .extent(0);"]
--Generates the long boost::tie expression that will be used to get all the data out of a tuple that we have read --Generates the long boost::tie expression that will be used to get all the data out of a tuple that we have read
genInputTupleAssign :: Bool -> String -> [A.InputItem] -> CGen() genInputTupleAssign :: Bool -> String -> [A.InputItem] -> CGen()
@ -338,22 +338,26 @@ genInputItem c (A.InCounted m cv av)
genVariable cv genVariable cv
tell [" = "] tell [" = "]
genVariable av genVariable av
tell [" .extent(blitz::firstDim); "] tell [" .extent(0); "]
genInputItem c (A.InVariable m v) genInputItem c (A.InVariable m v)
= do genVariable c = do genVariable c
tell ["->reader() >> "] tell ["->reader() >> "]
genVariable v genVariable v
tell [";\n"] tell [";\n"]
--If we are sending an array, we use the versionToSend function to coerce away any annoying const tags on the array data:
genJustOutputItem :: A.OutputItem -> CGen() genJustOutputItem :: A.OutputItem -> CGen()
genJustOutputItem (A.OutCounted m ce ae) genJustOutputItem (A.OutCounted m ce ae)
= do genJustOutputItem (A.OutExpression m ae) = do genExpression ae
tell[" (blitz::Range(0,"] tell[" .sliceFor("]
genExpression ce genExpression ce
tell[" - 1)) .copy() "] tell[") .versionToSend() "]
--TODO fill the rest of the dimensions with blitz::Range::all()
genJustOutputItem (A.OutExpression m e) genJustOutputItem (A.OutExpression m e)
= genExpression e = do t <- typeOfExpression e
genExpression e
case t of
(A.Array _ _) -> tell [" .versionToSend() "]
_ -> return ()
genOutputItem :: A.Variable -> A.OutputItem -> CGen () genOutputItem :: A.Variable -> A.OutputItem -> CGen ()
genOutputItem chan item genOutputItem chan item
@ -534,22 +538,47 @@ genProcCall n as
tell [");"] tell [");"]
--Changed from CIF's untyped channels to C++CSP's typed (templated) channels: --Changed from CIF's untyped channels to C++CSP's typed (templated) channels, and changed the declaration type of an array to be a vector:
declareType :: A.Type -> CGen () declareType :: A.Type -> CGen ()
declareType (A.Array ds t)
= do tell [" std::vector< "]
genType t
tell ["/**/>/**/"]
declareType (A.Counted countType valueType)
= do tell [" std::vector< "]
case valueType of
--Don't nest when it's a counted array of arrays:
(A.Array _ t) -> genType t
_ -> genType valueType
tell ["/**/>/**/"]
declareType (A.Chan t) declareType (A.Chan t)
= do tell [" csp::One2OneChannel < "] = do tell [" csp::One2OneChannel < "]
genType t genType t
tell [" > "] tell ["/**/>/**/ "]
declareType t = genType t declareType t = genType t
--Removed the channel part from GenerateC (not necessary in C++CSP, I think), and also changed the arrays: --Removed the channel part from GenerateC (not necessary in C++CSP, I think), and also changed the arrays:
--An array is actually stored as a std::vector, but an array-view object is automatically created with the array
--The vector has the suffix _actual, whereas the array-view is what is actually used in place of the array
--I think it may be possible to use boost::array instead of std::vector (which would be more efficient),
--but I will worry about that later
genDeclaration :: A.Type -> A.Name -> CGen () genDeclaration :: A.Type -> A.Name -> CGen ()
genDeclaration arrType@(A.Array ds t) n genDeclaration arrType@(A.Array ds t) n
= do declareType arrType = do declareType arrType
tell [" "] tell [" "]
genName n genName n
genArraySize ds tell ["_actual ("]
tell [";\n"] genFlatArraySize ds
tell ["); "]
genType arrType
tell [" "]
genName n;
tell ["("]
genName n
tell ["_actual,tockDims("]
genDims ds
tell ["));\n"]
genDeclaration t n genDeclaration t n
= do declareType t = do declareType t
tell [" "] tell [" "]
@ -564,7 +593,7 @@ declareInit m t@(A.Array ds t') var
return (\sub -> Just $ do genVariable (sub var) return (\sub -> Just $ do genVariable (sub var)
tell [" = new "] tell [" = new "]
declareType t' declareType t'
tell ["();\n"] tell [";\n"]
doMaybe $ declareInit m t' (sub var)) doMaybe $ declareInit m t' (sub var))
_ -> return (\sub -> declareInit m t' (sub var)) _ -> return (\sub -> declareInit m t' (sub var))
@ -646,15 +675,6 @@ abbrevExpression am t@(A.Array _ _) e
bad = missing "array expression abbreviation" bad = missing "array expression abbreviation"
abbrevExpression am _ e = genExpression e abbrevExpression am _ e = genExpression e
--Uses the Blitz library for giving array dimensions -- hence the round brackets, which actually are part of a constructor call
genArraySize :: [A.Dimension] -> CGen ()
genArraySize ds
= do tell ["( blitz::shape("]
sequence $ intersperse (tell [" , "])
[case d of A.Dimension n -> tell [show n] | d <- ds]
tell [") )"]
--Used to create boost::variant and boost::tuple types. Both these classes can have a maximum of nine items --Used to create boost::variant and boost::tuple types. Both these classes can have a maximum of nine items
--so if there are more than nine items, we must have variants containing variants, or tuples containing tuples --so if there are more than nine items, we must have variants containing variants, or tuples containing tuples
createChainedType :: String -> CGen() -> [CGen()] -> CGen () createChainedType :: String -> CGen() -> [CGen()] -> CGen ()
@ -686,8 +706,18 @@ tupleExpression useBrackets tupleType items
(firstNine,rest) = splitAt 9 items (firstNine,rest) = splitAt 9 items
--Takes a list of dimensions and outputs a comma-seperated list of the numerical values --Takes a list of dimensions and outputs a comma-seperated list of the numerical values
--Unknown dimensions have value 0 (which is treated specially by the tockArrayView class)
genDims:: [A.Dimension] -> CGen() genDims:: [A.Dimension] -> CGen()
genDims dims = infixComma $ map genDim dims genDims dims = infixComma $ map genDim dims
where
genDim :: A.Dimension -> CGen()
genDim (A.Dimension n) = tell [show n]
genDim (A.UnknownDimension) = tell ["0"]
--Generates an expression that yields the number of total elements in a declared multi-dimensional array
--Using it on arrays with unknown dimensions will cause an error (they should only be abbreviations, not declared as actual variables)
genFlatArraySize:: [A.Dimension] -> CGen()
genFlatArraySize dims = sequence_ $ intersperse (tell ["*"]) $ map genDim dims
where where
genDim :: A.Dimension -> CGen() genDim :: A.Dimension -> CGen()
genDim (A.Dimension n) = tell [show n] genDim (A.Dimension n) = tell [show n]
@ -749,15 +779,15 @@ introduceSpec (A.Specification _ n (A.IsExpr _ am t e))
tell [" ",tmp, " [] = "] tell [" ",tmp, " [] = "]
rhs rhs
tell [" ; "] tell [" ; "]
tell ["const tockArray< "] tell ["const tockArrayView< const "]
genType ts genType ts
tell [" , ",show (length dims)," > "] tell [" , ",show (length dims)," /**/>/**/ "]
genName n genName n
tell ["(("] tell ["(("]
genType ts genType ts
tell [" *)",tmp,",blitz::shape("] tell [" *)",tmp,",tockDims("]
genDims dims genDims dims
tell ["),blitz::duplicateData);\n"] tell ["));\n"]
(A.ValAbbrev, A.Record _, A.Literal _ _ _) -> (A.ValAbbrev, A.Record _, A.Literal _ _ _) ->
-- Record literals are even trickier, because there's no way of -- Record literals are even trickier, because there's no way of
-- directly writing a struct literal in C that you can use -> on. -- directly writing a struct literal in C that you can use -> on.
@ -774,19 +804,15 @@ introduceSpec (A.Specification _ n (A.IsExpr _ am t e))
tell [" = "] tell [" = "]
rhs rhs
tell [";\n"] tell [";\n"]
--TODO check this clause is ok
--We must create the channel array then fill it:
introduceSpec (A.Specification _ n (A.IsChannelArray _ t cs)) introduceSpec (A.Specification _ n (A.IsChannelArray _ t cs))
= do --tell ["tockArray< csp::One2OneChannel< "] = do genDeclaration t n
genType t
--tell [" > * , 1 > "]
tell [" "]
genName n
tell ["(blitz::shape(",show (length cs),"));"]
sequence_ $ map genChanArrayElemInit (zip [0 .. ((length cs) - 1)] cs) sequence_ $ map genChanArrayElemInit (zip [0 .. ((length cs) - 1)] cs)
where where
genChanArrayElemInit (index,var) genChanArrayElemInit (index,var)
= do genName n = do genName n
tell ["(",show index,") = "] tell ["[",show index,"].access() = "] --Use the .access() function to cast a 0-dimension array into a T& for access
genVariable var genVariable var
tell [";"] tell [";"]
--This clause is unchanged from GenerateC: --This clause is unchanged from GenerateC:
@ -817,28 +843,40 @@ introduceSpec (A.Specification _ n (A.ProtocolCase _ caseList))
typedef_genCaseType n (tag, typeList) typedef_genCaseType n (tag, typeList)
= createChainedType "boost::tuple" (genTupleProtocolTagName n tag) ((genProtocolTagName n tag) : (map genType typeList)) = createChainedType "boost::tuple" (genTupleProtocolTagName n tag) ((genProtocolTagName n tag) : (map genType typeList))
--TODO check this clause --Clause changed to handle array retyping
introduceSpec (A.Specification _ n (A.Retypes m am t v)) introduceSpec (A.Specification _ n (A.Retypes m am t v))
= do origT <- typeOfVariable v = do origT <- typeOfVariable v
let rhs = abbrevVariable A.Abbrev origT v let rhs = abbrevVariable A.Abbrev origT v
genDecl am t n genDecl am t n
tell [" = "] tell [" = "]
-- For scalar types that are VAL abbreviations (e.g. VAL INT64), case t of
-- we need to dereference the pointer that abbrevVariable gives us. (A.Array dims _) ->
let deref = case (am, t) of --Arrays need to be handled differently because we need to feed the sizes in, not just perform a straight cast
(_, A.Array _ _) -> False do genDeclType am t
(_, A.Chan _) -> False tell ["("]
(A.ValAbbrev, _) -> True rhs
_ -> False tell [",tockDims("]
when deref $ tell ["*"] genDims dims
tell ["("] tell ["));"]
genDeclType am t _ ->
when deref $ tell [" *"] -- For scalar types that are VAL abbreviations (e.g. VAL INT64),
tell [") "] -- we need to dereference the pointer that abbrevVariable gives us.
rhs do let deref = case (am, t) of
tell [";\n"] (_, A.Array _ _) -> False
--TODO work out what this does (_, A.Chan _) -> False
-- genRetypeSizes m am t n origT v (A.ValAbbrev, _) -> True
_ -> False
when deref $ tell ["*"]
tell ["("]
genDeclType am t
when deref $ tell [" *"]
tell [") ("]
rhs
case origT of
--We must be retyping from an array, but not to an array (so to a primitive type or something):
(A.Array _ _) -> tell [".data()"]
_ -> return ()
tell [");\n"]
--This clause is unchanged from GenerateC: --This clause is unchanged from GenerateC:
introduceSpec n = missing $ "introduceSpec " ++ show n introduceSpec n = missing $ "introduceSpec " ++ show n
@ -851,10 +889,10 @@ genExpression (A.MostPos m t) = genTypeSymbol "mostpos" t
genExpression (A.MostNeg m t) = genTypeSymbol "mostneg" t genExpression (A.MostNeg m t) = genTypeSymbol "mostneg" t
genExpression (A.SizeExpr m e) genExpression (A.SizeExpr m e)
= do genExpression e = do genExpression e
tell [" .extent(blitz::firstDim) "] tell [" .extent(0) "]
genExpression (A.SizeVariable m v) genExpression (A.SizeVariable m v)
= do genVariable v = do genVariable v
tell [" .extent(blitz::firstDim)"] tell [" .extent(0)"]
genExpression (A.Conversion m cm t e) = genConversion m cm t e genExpression (A.Conversion m cm t e) = genConversion m cm t e
genExpression (A.ExprVariable m v) = genVariable v genExpression (A.ExprVariable m v) = genVariable v
genExpression (A.Literal _ _ lr) = genLiteral lr genExpression (A.Literal _ _ lr) = genLiteral lr
@ -875,8 +913,9 @@ genExpression t = missing $ "genExpression " ++ show t
-- | If a type maps to a simple C type, return Just that; else return Nothing. -- | If a type maps to a simple C type, return Just that; else return Nothing.
--Changed from GenerateC to change the A.Timer type to use C++CSP time --Changed from GenerateC to change the A.Timer type to use C++CSP time
--Also changed the bool type, because vector<bool> in C++ is odd, so we hide it from the compiler:
scalarType :: A.Type -> Maybe String scalarType :: A.Type -> Maybe String
scalarType A.Bool = Just "bool" scalarType A.Bool = Just "tockBool"
scalarType A.Byte = Just "uint8_t" scalarType A.Byte = Just "uint8_t"
scalarType A.Int = Just "int" scalarType A.Int = Just "int"
scalarType A.Int16 = Just "int16_t" scalarType A.Int16 = Just "int16_t"
@ -888,19 +927,20 @@ scalarType A.Timer = Just "csp::Time"
scalarType _ = Nothing scalarType _ = Nothing
--Generates an array type, giving the Blitz++ array the correct dimensions --Generates an array type, giving the Blitz++ array the correct dimensions
genArrayType :: A.Type -> Int -> CGen () genArrayType :: Bool -> A.Type -> Int -> CGen ()
genArrayType (A.Array dims t) rank genArrayType const (A.Array dims t) rank
= genArrayType t (rank + (max 1 (length dims))) = genArrayType const t (rank + (max 1 (length dims)))
genArrayType t rank genArrayType const t rank
= do tell [" tockArray< "] = do tell [" tockArrayView< "]
when (const) (tell [" const "])
genType t genType t
tell [" , ",show rank, " > "] tell [" , ",show rank, " > /**/"]
--Changed from GenerateC to change the arrays and the channels --Changed from GenerateC to change the arrays and the channels
--Also changed to add counted arrays and user protocols --Also changed to add counted arrays and user protocols
genType :: A.Type -> CGen () genType :: A.Type -> CGen ()
genType arr@(A.Array _ _) genType arr@(A.Array _ _)
= genArrayType arr 0 = genArrayType False arr 0
genType (A.Record n) = genName n genType (A.Record n) = genName n
genType (A.UserProtocol n) = genProtocolName n genType (A.UserProtocol n) = genProtocolName n
genType (A.Chan t) genType (A.Chan t)
@ -908,7 +948,7 @@ genType (A.Chan t)
genType t genType t
tell [" > * "] tell [" > * "]
genType (A.Counted countType valueType) genType (A.Counted countType valueType)
= genType (A.Array [] valueType) = genType (A.Array [A.UnknownDimension] valueType)
genType (A.Any) genType (A.Any)
= tell [" tockAny "] = tell [" tockAny "]
-- Any -- not used -- Any -- not used
@ -963,13 +1003,11 @@ genSlice _ v ty start count ds
-- We need to disable the index check here because we might be taking -- We need to disable the index check here because we might be taking
-- element 0 of a 0-length array -- which is valid. -- element 0 of a 0-length array -- which is valid.
= do genVariableUnchecked v = do genVariableUnchecked v
tell ["(blitz::Range("] tell [".sliceFromFor("]
genExpression start genExpression start
tell [" , "] tell [" , "]
genExpression start
tell [" + "]
genExpression count genExpression count
tell [" ))"] tell [")"]
--Removed the sizing and the & from GenerateC: --Removed the sizing and the & from GenerateC:
@ -982,9 +1020,7 @@ genArraySubscript :: Bool -> A.Variable -> [A.Expression] -> CGen ()
genArraySubscript checkValid v es genArraySubscript checkValid v es
= do t <- typeOfVariable v = do t <- typeOfVariable v
let numDims = case t of A.Array ds _ -> length ds let numDims = case t of A.Array ds _ -> length ds
tell ["("] sequence_ $ genPlainSub v es [0..(numDims - 1)]
sequence_ $ intersperse (tell [" , "]) $ genPlainSub v es [0..(numDims - 1)]
tell [")"]
where where
-- | Generate the individual offsets that need adding together to find the -- | Generate the individual offsets that need adding together to find the
-- right place in the array. -- right place in the array.
@ -992,14 +1028,14 @@ genArraySubscript checkValid v es
-- smart C compiler should be able to work it out... -- smart C compiler should be able to work it out...
--Subtly changed this function so that empty dimensions have blitz::Range::all() in the C++ version: --Subtly changed this function so that empty dimensions have blitz::Range::all() in the C++ version:
--TODO doc
genPlainSub :: A.Variable -> [A.Expression] -> [Int] -> [CGen ()] genPlainSub :: A.Variable -> [A.Expression] -> [Int] -> [CGen ()]
genPlainSub _ _ [] = [] genPlainSub _ _ [] = []
genPlainSub v [] (sub:subs) = (tell [" blitz::Range::all() "]) : (genPlainSub v [] subs) genPlainSub v [] (sub:subs) = (tell [" "]) : (genPlainSub v [] subs)
genPlainSub v (e:es) (sub:subs) genPlainSub v (e:es) (sub:subs)
= gen : genPlainSub v es subs = (tell ["["] >> genSub >> tell ["]"]) : genPlainSub v es subs
where where
gen = genSub
genSub genSub
= if checkValid = if checkValid
then do tell ["occam_check_index ("] then do tell ["occam_check_index ("]
@ -1106,6 +1142,21 @@ genIfBody ifExc s = genStructured s doC
--}}} --}}}
--Changed to make array VAL abbreviations have constant data:
genDeclType :: A.AbbrevMode -> A.Type -> CGen ()
genDeclType am t
= do case t of
A.Array _ _ -> genArrayType (am == A.ValAbbrev) t 0
_ ->
do when (am == A.ValAbbrev) $ tell ["const "]
genType t
case t of
A.Chan _ -> return ()
A.Record _ -> tell [" *"]
_ -> when (am == A.Abbrev) $ tell [" *"]
{- {-
--------------------------------------------------------------------- ---------------------------------------------------------------------
@ -1380,15 +1431,6 @@ genCheckedConversion m fromT toT exp
--{{{ declarations --{{{ declarations
--All taken verbatim from GenerateC --All taken verbatim from GenerateC
genDeclType :: A.AbbrevMode -> A.Type -> CGen ()
genDeclType am t
= do when (am == A.ValAbbrev) $ tell ["const "]
genType t
case t of
A.Array _ _ -> return ()
A.Chan _ -> return ()
A.Record _ -> tell [" *"]
_ -> when (am == A.Abbrev) $ tell [" *"]
genDecl :: A.AbbrevMode -> A.Type -> A.Name -> CGen () genDecl :: A.AbbrevMode -> A.Type -> A.Name -> CGen ()
genDecl am t n genDecl am t n
@ -1486,6 +1528,10 @@ genVariable' checkValid v
= do let (es, v) = collectSubs sv = do let (es, v) = collectSubs sv
genVariable v genVariable v
genArraySubscript checkValid v es genArraySubscript checkValid v es
t <- typeOfVariable v
--To index an actual element of an array we must use the .access() function
--Only needed when we have applied enough subscripts to get out an element:
case t of A.Array dims _ -> when ((length dims) == (length es)) (tell [" .access() "])
inner (A.SubscriptedVariable _ (A.SubscriptField m n) v) inner (A.SubscriptedVariable _ (A.SubscriptField m n) v)
= do genVariable v = do genVariable v
tell ["->"] tell ["->"]

View File

@ -29,17 +29,11 @@ public:
#include <iostream> #include <iostream>
#include <boost/tuple/tuple.hpp> #include <boost/tuple/tuple.hpp>
#include <boost/variant.hpp> #include <boost/variant.hpp>
#include <boost/mpl/at.hpp>
#include <blitz/array.h>
#include <blitz/tinyvec-et.h>
#include <boost/any.hpp> #include <boost/any.hpp>
#include <vector>
inline blitz::Array<unsigned char, 1> string_to_array(char* c) #include <boost/type_traits/remove_const.hpp>
{ #include <boost/preprocessor/repetition/repeat.hpp>
const size_t n = strlen(c) + 1; #include <boost/preprocessor/repetition/repeat_from_to.hpp>
return blitz::Array<unsigned char, 1>((unsigned char*)c,blitz::shape(n),blitz::neverDeleteData);
}
class StreamWriter : public csp::CSProcess class StreamWriter : public csp::CSProcess
{ {
@ -105,93 +99,244 @@ public:
}; };
template < typename T, unsigned dims > class tockBool
class tockArray : public blitz::Array<T,dims>
{ {
public: private:
inline tockArray(const tockArray<T,dims>& _array) bool b;
: blitz::Array<T,dims>(*(blitz::Array<T,dims>*)&_array) {} public:
inline tockBool() {}
inline tockArray(const tockAny& _any) inline tockBool(bool _b) : b(_b) {}
: blitz::Array<T,dims>(*(blitz::Array<T,dims>*)& (tockArray)_any) {} inline operator bool () const {return b;}
inline void operator = (const bool& _b) {b = _b;}
template <typename U> };
inline tockArray(const tockArray<U,dims>& _diffTypeArray)
: blitz::Array<T,dims>( (T*) (_diffTypeArray.dataFirst()), (_diffTypeArray.shape() * (int)sizeof(U)) / (int)sizeof(T),blitz::neverDeleteData) {} inline std::pair< boost::array<unsigned,1> , unsigned > tockDims(const unsigned d0)
{
template <unsigned D> boost::array<unsigned,1> r;
inline tockArray(const tockArray<T,D>& _diffDimArray) r[0] = d0;
: blitz::Array<T,dims>( (T*) (_diffDimArray.dataFirst()),blitz::shape(_diffDimArray.size()),blitz::neverDeleteData) {} return std::pair< boost::array<unsigned,1> , unsigned >(r,1);
}
template <typename U>
inline tockArray(U* u) /*
: blitz::Array<T,dims>( (T*) u, sizeof(U) / sizeof(T),blitz::neverDeleteData) {} Generates functions like this:
inline std::pair< boost::array<unsigned,2> , unsigned > tockDims(const unsigned d0,const unsigned d1,const unsigned d2)
inline tockArray(T t) : blitz::Array<T,dims>(1) {(*this)(0) = t;} {
boost::array<unsigned,2> r;
r[0] = d0;
template <typename U> r[1] = d1;
inline tockArray(U u) : blitz::Array<T,dims>(u) {} r[2] = d2;
return std::pair< boost::array<unsigned,2> , unsigned >(r,d1 * d2);
template <typename U,typename V> }
inline tockArray(U u,V v) : blitz::Array<T,dims>(u,v) {} */
template <typename U,typename V,typename W> #define TOCKDIMS_ARGS(___z,NUM,___data) ,const unsigned d##NUM
inline tockArray(U u,V v,W w) : blitz::Array<T,dims>(u,v,w) {} #define TOCKDIMS_ASSIGN(___z,NUM,___data) r[ NUM ] = d##NUM ;
#define TOCKDIMS_MULT(___z,NUM,___data) * d##NUM
template <typename U,typename V,typename W,typename X>
inline tockArray(U u,V v,W w,X x) : blitz::Array<T,dims>(u,v,w,x) {} #define TOCKDIMS(___z,NUM,___data) inline std::pair< boost::array<unsigned, NUM >,unsigned> tockDims(\
const unsigned d0 BOOST_PP_REPEAT_FROM_TO(1,NUM,TOCKDIMS_ARGS,0) ) { \
template <typename U,typename V,typename W,typename X,typename Y> boost::array<unsigned, NUM > r; BOOST_PP_REPEAT(NUM,TOCKDIMS_ASSIGN,0) \
inline tockArray(U u,V v,W w,X x,Y y) : blitz::Array<T,dims>(u,v,w,x,y) {} return std::pair< boost::array<unsigned, NUM > , unsigned >(r,1 BOOST_PP_REPEAT_FROM_TO(1,NUM,TOCKDIMS_MULT,0) ); }
template <typename U,typename V,typename W,typename X,typename Y,typename Z> //Up to 12 dimensions:
inline tockArray(U u,V v,W w,X x,Y y,Z z) : blitz::Array<T,dims>(u,v,w,x,y,z) {} BOOST_PP_REPEAT_FROM_TO(2,12,TOCKDIMS,0)
template <typename U,typename V,typename W,typename X,typename Y,typename Z,typename Z0>
inline tockArray(U u,V v,W w,X x,Y y,Z z,Z0 z0) : blitz::Array<T,dims>(u,v,w,x,y,z,z0) {} template < typename T, unsigned DIMS >
class tockArrayView
template <typename U,typename V,typename W,typename X,typename Y,typename Z,typename Z0,typename Z1> {
inline tockArray(U u,V v,W w,X x,Y y,Z z,Z0 z0,Z1 z1) : blitz::Array<T,dims>(u,v,w,x,y,z,z0,z1) {} T* realArray;
boost::array<unsigned,DIMS> dims;
template <typename U,typename V,typename W,typename X,typename Y,typename Z,typename Z0,typename Z1,typename Z2> //dims[1] * dims[2] * dims[3] ...
inline tockArray(U u,V v,W w,X x,Y y,Z z,Z0 z0,Z1 z1,Z2 z2) : blitz::Array<T,dims>(u,v,w,x,y,z,z0,z1,z2) {} //If DIMS is 0 or 1, totalSubDim will be 1
unsigned totalSubDim;
template <typename U,typename V,typename W,typename X,typename Y,typename Z,typename Z0,typename Z1,typename Z2,typename Z3>
inline tockArray(U u,V v,W w,X x,Y y,Z z,Z0 z0,Z1 z1,Z2 z2,Z3 z3) : blitz::Array<T,dims>(u,v,w,x,y,z,z0,z1,z2,z3) {} template <typename U>
inline void operator=(const U&) {}
inline tockArray() {} inline tockArrayView(T* _realArray,const boost::array<unsigned,DIMS+1>& _biggerDims,unsigned _totalSubDim)
: realArray(_realArray),totalSubDim(_totalSubDim)
inline tockArray& operator=(const tockArray<T,dims>& rhs) {
{ memcpy(dims.c_array(),_biggerDims.data() + 1,sizeof(unsigned) * DIMS);
resize(rhs.shape()); }
*((blitz::Array<T,dims>*)this) = *((blitz::Array<T,dims>*)&rhs); friend class tockArrayView<T,DIMS + 1>;
return *this;
} inline void correctDimsRetype(const unsigned totalSourceBytes)
{
inline tockArray& operator=(const tockAny& any) if (totalSubDim == 0)
{ {
return (*this = (tockArray<T,dims>)any); //Can only happen if one of the dimensions is zero, i.e. unknown
} //We must find this dimension and calculate it:
inline tockArray& operator=(const T& t) unsigned zeroDim;
{ unsigned totalDim = 1;
this->resize(blitz::shape(1)); for (unsigned i = 0;i < DIMS;i++)
(*this)(0) = t; {
return *this; if (dims[i] == 0)
} zeroDim = i;
else
template <typename U> totalDim *= dims[i];
operator U* () }
{ //Set the size of the unknown dimension:
return (U*)(void*)(this->dataFirst()); dims[zeroDim] = (totalSourceBytes / totalDim) / sizeof(T);
}
totalSubDim = (totalDim * dims[zeroDim]) / dims[0];
template <typename U> }
operator const U* const ()
{ }
return (const U*)(const void*)(this->dataFirst());
}
public:
inline tockArrayView()
: realArray(NULL)
{
dims.assign(0);
totalSubDim = 0;
}
inline tockArrayView(const tockArrayView& v)
: realArray(v.realArray),
dims(v.dims),
totalSubDim(v.totalSubDim)
{
}
inline tockArrayView(T* _realArray,const std::pair< boost::array<unsigned,DIMS> , unsigned >& _dims)
: realArray(_realArray),dims(_dims.first),totalSubDim(_dims.second)
{
}
inline tockArrayView(std::vector<typename boost::remove_const<T>::type>& _vec,const std::pair< boost::array<unsigned,DIMS> , unsigned >& _dims)
: realArray(_vec.empty() ? NULL : &(_vec.at(0))),dims(_dims.first),totalSubDim(_dims.second)
{
}
//Retyping:
template <typename U>
inline tockArrayView(U* _realArray,const std::pair< boost::array<unsigned,DIMS> , unsigned >& _dims)
: realArray(reinterpret_cast<T*>(_realArray)),dims(_dims.first),totalSubDim(_dims.second)
{
//Assume it's a single U item:
correctDimsRetype(sizeof(U));
}
//Retyping, same number of dims:
template <typename U,unsigned FROMDIMS>
inline tockArrayView(const tockArrayView<U,FROMDIMS>& tav,const std::pair< boost::array<unsigned,DIMS> , unsigned >& _dims)
: realArray(reinterpret_cast<T*>(tav.data())),dims(_dims.first),totalSubDim(_dims.second)
{
correctDimsRetype(tav.size() * sizeof(U));
}
inline tockArrayView<T,DIMS - 1> operator[] (const unsigned index) const
{
return tockArrayView<T,DIMS - 1>(realArray + (totalSubDim * index),dims,totalSubDim / dims[0]);
}
inline tockArrayView<T,DIMS> sliceFor(const unsigned amount) const
{
return sliceFromFor(0,amount);
}
inline tockArrayView<T,DIMS> sliceFrom(const unsigned index) const
{
return sliceFromFor(index,dims[0] - index);
}
inline tockArrayView<T,DIMS> sliceFromFor(const unsigned index,const unsigned amount) const
{
boost::array<unsigned,DIMS> sliceDims = dims;
sliceDims[0] = amount;
return tockArrayView<T,DIMS>(realArray + (totalSubDim * index),std::make_pair(sliceDims,totalSubDim));
}
inline T* data() const
{
return realArray;
}
inline const boost::array<unsigned,DIMS>& getDims() const
{
return dims;
}
inline unsigned getTotalSubDim() const
{
return totalSubDim;
}
inline unsigned size() const
{
return dims[0] * totalSubDim;
}
inline unsigned extent(const unsigned dim) const
{
return dims[dim];
}
inline operator tockArrayView<const T,DIMS>() const
{
return tockArrayView<const T,DIMS>((const T*)realArray,std::make_pair(dims,totalSubDim));
}
inline void updateFromVector(std::vector<typename boost::remove_const<T>::type>& v)
{
realArray = v.empty() ? NULL : &(v.at(0));
}
inline tockArrayView<typename boost::remove_const<T>::type,DIMS> versionToSend()
{
return tockArrayView<typename boost::remove_const<T>::type,DIMS>(const_cast<typename boost::remove_const<T>::type*>(realArray),std::make_pair(dims,totalSubDim));
}
inline const tockArrayView<typename boost::remove_const<T>::type,DIMS> versionToSend() const
{
return tockArrayView<typename boost::remove_const<T>::type,DIMS>(const_cast<typename boost::remove_const<T>::type*>(realArray),std::make_pair(dims,totalSubDim));
}
inline tockArrayView& operator=(const tockArrayView& tav)
{
//TODO investigate speeding up when T is primitive (maybe there's a boost class for that?)
unsigned n = tav.size();
for (unsigned i = 0;i < n;i++)
{
realArray[i] = tav.realArray[i];
}
dims = tav.dims;
totalSubDim = tav.totalSubDim;
return *this;
}
inline tockArrayView& operator=(const tockAny&)
{
//TODO later on
}
};
template <typename T>
class tockArrayView<T,0>
{
T* realArray;
inline tockArrayView(T* _realArray,boost::array<unsigned,1>,unsigned)
: realArray(_realArray)
{
}
friend class tockArrayView<T,1>;
public:
//Should only be used on arrays with zero dimensions:
inline T& access() const
{
return *realArray;
}
}; };