From 116eed3ebd48bd96292af786a09bb67c124bb3e9 Mon Sep 17 00:00:00 2001 From: Binh-Minh Ribler Date: Tue, 8 Mar 2016 07:23:54 -0500 Subject: =?UTF-8?q?[svn-r29340]=20Purpose:=20Code=20cleanup=20Description:?= =?UTF-8?q?=20=20=20=20=20-=20Removed=20many=20warnings:=20=20=20=20=20=20?= =?UTF-8?q?=20=20=20warning:=20use=20of=20old-style=20cast=20=20=20=20=20?= =?UTF-8?q?=20=20=20=20warning:=20enumeration=20value=20=E2=80=98H5D=5FVIR?= =?UTF-8?q?TUAL=E2=80=99=20not=20handled=20in=20switch=20=20=20=20=20=20?= =?UTF-8?q?=20=20=20warning:=20comparison=20between=20signed=20and=20unsig?= =?UTF-8?q?ned=20=20=20=20=20=20=20There=20are=20others=20of=20the=20same?= =?UTF-8?q?=20warnings=20and=20they=20will=20be=20taken=20care=20of=20=20?= =?UTF-8?q?=20=20=20=20=20in=20the=20next=20release.=20=20=20=20=20-=20Mad?= =?UTF-8?q?e=20some=20code=20reuse=20between=20overloads=20Platforms=20tes?= =?UTF-8?q?ted:=20=20=20=20=20Linux/32=202.6=20(jam)=20=20=20=20=20Linux/6?= =?UTF-8?q?4=20(platypus)=20=20=20=20=20Darwin=20(osx1010test)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- c++/src/H5ArrayType.cpp | 5 +--- c++/src/H5Attribute.cpp | 2 +- c++/src/H5CommonFG.cpp | 73 +++++++++++++++++++++++++------------------------ c++/src/H5DataSet.cpp | 3 +- c++/src/H5DataSpace.cpp | 2 +- c++/src/H5DataType.cpp | 6 ++-- c++/src/H5FaccProp.cpp | 4 +-- c++/src/H5Location.cpp | 10 +++---- c++/src/H5Object.cpp | 2 +- c++/src/H5PropList.cpp | 2 +- c++/test/dsets.cpp | 56 ++++++++++++++++++------------------- c++/test/h5cpputil.cpp | 2 +- 12 files changed, 84 insertions(+), 83 deletions(-) diff --git a/c++/src/H5ArrayType.cpp b/c++/src/H5ArrayType.cpp index 5792467..9731a13 100644 --- a/c++/src/H5ArrayType.cpp +++ b/c++/src/H5ArrayType.cpp @@ -54,11 +54,8 @@ ArrayType::ArrayType( const hid_t existing_id ) : DataType( existing_id ) ///\brief Copy constructor: makes a copy of the original ArrayType object. // Programmer Binh-Minh Ribler - May 2004 //-------------------------------------------------------------------------- -ArrayType::ArrayType( const ArrayType& original ) : DataType( original ) +ArrayType::ArrayType( const ArrayType& original ) : DataType( original ), rank(original.rank) { - // Copy the rank of the original array - rank = original.rank; - // Allocate space then copy the dimensions from the original array dimensions = new hsize_t[rank]; for (int i = 0; i < rank; i++) diff --git a/c++/src/H5Attribute.cpp b/c++/src/H5Attribute.cpp index dcb424a..34489fa 100644 --- a/c++/src/H5Attribute.cpp +++ b/c++/src/H5Attribute.cpp @@ -567,7 +567,7 @@ void Attribute::p_read_fixed_len(const DataType& mem_type, H5std_string& strg) c // If there is data, allocate buffer and read it. if (attr_size > 0) { - char *strg_C = new char[(size_t)attr_size+1]; + char *strg_C = new char[attr_size+1]; herr_t ret_value = H5Aread(id, mem_type.getId(), strg_C); if( ret_value < 0 ) { diff --git a/c++/src/H5CommonFG.cpp b/c++/src/H5CommonFG.cpp index 85a4906..339af54 100644 --- a/c++/src/H5CommonFG.cpp +++ b/c++/src/H5CommonFG.cpp @@ -68,21 +68,21 @@ using namespace std; /// then a default size is chosen. // Programmer Binh-Minh Ribler - 2000 //-------------------------------------------------------------------------- -Group CommonFG::createGroup( const char* name, size_t size_hint ) const + Group CommonFG::createGroup( const char* name, size_t size_hint ) const { - // Group creation property list for size_hint - hid_t gcpl_id = 0; - - // Set the local heap size hint - if(!(size_hint == (size_t)-1 || size_hint == 0)) { + // Group creation property list for size hint + hid_t gcpl_id = 0; + // Set the local heap size hint + if (size_hint > 0) + { // If the creation of the property list failed, throw an exception - if((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) throwException("createGroup", "H5Pcreate failed"); - if( H5Pset_local_heap_size_hint(gcpl_id, size_hint) < 0) { + if (H5Pset_local_heap_size_hint(gcpl_id, size_hint) < 0) { H5Pclose(gcpl_id); - throwException("createGroup", "H5Pset_local_heap_size failed"); + throwException("createGroup", "H5Pset_local_heap_size_hint failed"); } } @@ -269,6 +269,9 @@ void CommonFG::link( H5L_type_t link_type, const char* curr_name, const char* ne ret_value = H5Lcreate_soft( curr_name, getLocId(), new_name, H5P_DEFAULT, H5P_DEFAULT ); break; + case H5L_TYPE_ERROR: + case H5L_TYPE_EXTERNAL: + case H5L_TYPE_MAX: default: throwException("link", "unknown link type"); break; @@ -510,7 +513,7 @@ void CommonFG::mount(const char* name, const H5File& child, const PropList& plis //-------------------------------------------------------------------------- void CommonFG::mount(const char* name, H5File& child, PropList& plist) const { - mount(name, (const H5File)child, (const PropList)plist); + mount(name, child, plist); } //-------------------------------------------------------------------------- @@ -536,7 +539,7 @@ void CommonFG::mount(const H5std_string& name, const H5File& child, const PropLi //-------------------------------------------------------------------------- void CommonFG::mount(const H5std_string& name, H5File& child, PropList& plist) const { - mount(name.c_str(), (const H5File)child, (const PropList)plist); + mount(name.c_str(), child, plist); } //-------------------------------------------------------------------------- @@ -1040,6 +1043,8 @@ H5O_type_t CommonFG::childObjType(const char* objname) const case H5O_TYPE_NAMED_DATATYPE: objtype = objinfo.type; break; + case H5O_TYPE_UNKNOWN: + case H5O_TYPE_NTYPES: default: throwException("childObjType", "Unknown type of object"); } @@ -1113,6 +1118,8 @@ H5O_type_t CommonFG::childObjType(hsize_t index, H5_index_t index_type, H5_iter_ case H5O_TYPE_NAMED_DATATYPE: objtype = objinfo.type; break; + case H5O_TYPE_UNKNOWN: + case H5O_TYPE_NTYPES: default: throwException("childObjType", "Unknown type of object"); } @@ -1201,21 +1208,13 @@ H5G_obj_t CommonFG::getObjTypeByIdx(hsize_t idx) const ///\return Object type ///\exception H5::FileIException or H5::GroupIException // Programmer Binh-Minh Ribler - May, 2010 +// Modification +// Modified to use the other function. -BMR, 2016/03/07 //-------------------------------------------------------------------------- H5G_obj_t CommonFG::getObjTypeByIdx(hsize_t idx, char* type_name) const { - H5G_obj_t obj_type = H5Gget_objtype_by_idx(getLocId(), idx); - switch (obj_type) - { - case H5G_LINK: HDstrcpy(type_name, "symbolic link"); break; - case H5G_GROUP: HDstrcpy(type_name, "group"); break; - case H5G_DATASET: HDstrcpy(type_name, "dataset"); break; - case H5G_TYPE: HDstrcpy(type_name, "datatype"); break; - case H5G_UNKNOWN: - default: - throwException("getObjTypeByIdx", "H5Gget_objtype_by_idx failed"); - } - return (obj_type); + H5std_string stype_name(type_name); + return(getObjTypeByIdx(idx, stype_name)); } //-------------------------------------------------------------------------- // Function: CommonFG::getObjTypeByIdx @@ -1230,18 +1229,22 @@ H5G_obj_t CommonFG::getObjTypeByIdx(hsize_t idx, char* type_name) const //-------------------------------------------------------------------------- H5G_obj_t CommonFG::getObjTypeByIdx(hsize_t idx, H5std_string& type_name) const { - H5G_obj_t obj_type = H5Gget_objtype_by_idx(getLocId(), idx); - switch (obj_type) - { - case H5G_LINK: type_name = H5std_string("symbolic link"); break; - case H5G_GROUP: type_name = H5std_string("group"); break; - case H5G_DATASET: type_name = H5std_string("dataset"); break; - case H5G_TYPE: type_name = H5std_string("datatype"); break; - case H5G_UNKNOWN: - default: - throwException("getObjTypeByIdx", "H5Gget_objtype_by_idx failed"); - } - return (obj_type); + H5G_obj_t obj_type = H5Gget_objtype_by_idx(getLocId(), idx); + switch (obj_type) + { + case H5G_LINK: type_name = H5std_string("symbolic link"); break; + case H5G_GROUP: type_name = H5std_string("group"); break; + case H5G_DATASET: type_name = H5std_string("dataset"); break; + case H5G_TYPE: type_name = H5std_string("datatype"); break; + case H5G_UNKNOWN: + case H5G_UDLINK: + case H5G_RESERVED_5: + case H5G_RESERVED_6: + case H5G_RESERVED_7: + default: + throwException("getObjTypeByIdx", "H5Gget_objtype_by_idx failed"); + } + return (obj_type); } #endif // DOXYGEN_SHOULD_SKIP_THIS diff --git a/c++/src/H5DataSet.cpp b/c++/src/H5DataSet.cpp index a2e5c74..c5ecf0a 100644 --- a/c++/src/H5DataSet.cpp +++ b/c++/src/H5DataSet.cpp @@ -335,7 +335,8 @@ hsize_t DataSet::getVlenBufSize(const DataType& type, const DataSpace& space ) c //-------------------------------------------------------------------------- hsize_t DataSet::getVlenBufSize( DataType& type, DataSpace& space ) const { - return(getVlenBufSize((const DataType)type, (const DataSpace)space)); + return(getVlenBufSize(type, space)); + //return(getVlenBufSize(static_cast(type), static_cast(space))); } //-------------------------------------------------------------------------- diff --git a/c++/src/H5DataSpace.cpp b/c++/src/H5DataSpace.cpp index 8ef8791..690f328 100644 --- a/c++/src/H5DataSpace.cpp +++ b/c++/src/H5DataSpace.cpp @@ -352,7 +352,7 @@ void DataSpace::extentCopy (const DataSpace& dest_space) const //-------------------------------------------------------------------------- void DataSpace::extentCopy( DataSpace& dest_space ) const { - extentCopy((const DataSpace)dest_space); + extentCopy(dest_space); } //-------------------------------------------------------------------------- diff --git a/c++/src/H5DataType.cpp b/c++/src/H5DataType.cpp index 1502033..3e5ad0f 100644 --- a/c++/src/H5DataType.cpp +++ b/c++/src/H5DataType.cpp @@ -362,10 +362,10 @@ void DataType::commit(H5Location& loc, const H5std_string& name) bool DataType::committed() const { // Call C function to determine if a datatype is a named one - htri_t committed = H5Tcommitted( id ); - if( committed > 0 ) + htri_t is_committed = H5Tcommitted( id ); + if (is_committed > 0) return true; - else if( committed == 0 ) + else if (is_committed == 0) return false; else { diff --git a/c++/src/H5FaccProp.cpp b/c++/src/H5FaccProp.cpp index d8b06f2..c284500 100644 --- a/c++/src/H5FaccProp.cpp +++ b/c++/src/H5FaccProp.cpp @@ -345,7 +345,7 @@ void FileAccPropList::setSplit(const FileAccPropList& meta_plist, const FileAccP //-------------------------------------------------------------------------- void FileAccPropList::setSplit(FileAccPropList& meta_plist, FileAccPropList& raw_plist, const char* meta_ext, const char* raw_ext ) const { - setSplit((const FileAccPropList)meta_plist, (const FileAccPropList)raw_plist, meta_ext, raw_ext); + setSplit(meta_plist, raw_plist, meta_ext, raw_ext); } //-------------------------------------------------------------------------- @@ -380,7 +380,7 @@ void FileAccPropList::setSplit(const FileAccPropList& meta_plist, const FileAccP //-------------------------------------------------------------------------- void FileAccPropList::setSplit(FileAccPropList& meta_plist, FileAccPropList& raw_plist, const H5std_string& meta_ext, const H5std_string& raw_ext ) const { - setSplit((const FileAccPropList)meta_plist, (const FileAccPropList)raw_plist, meta_ext.c_str(), raw_ext.c_str() ); + setSplit(meta_plist, raw_plist, meta_ext.c_str(), raw_ext.c_str() ); } // Stream Virtual File Driver had been removed from the main library. diff --git a/c++/src/H5Location.cpp b/c++/src/H5Location.cpp index b4c88ed..337aa6f 100644 --- a/c++/src/H5Location.cpp +++ b/c++/src/H5Location.cpp @@ -190,7 +190,7 @@ Attribute H5Location::openAttribute( const H5std_string& name ) const Attribute H5Location::openAttribute( const unsigned int idx ) const { hid_t attr_id = H5Aopen_by_idx(getId(), ".", H5_INDEX_CRT_ORDER, - H5_ITER_INC, (hsize_t)idx, H5P_DEFAULT, H5P_DEFAULT); + H5_ITER_INC, static_cast(idx), H5P_DEFAULT, H5P_DEFAULT); if( attr_id > 0 ) { Attribute attr; @@ -232,7 +232,7 @@ int H5Location::iterateAttrs( attr_operator_t user_op, unsigned *_idx, void *op_ // call the C library routine H5Aiterate2 to iterate the attributes hsize_t idx = _idx ? (hsize_t)*_idx : 0; int ret_value = H5Aiterate2(getId(), H5_INDEX_NAME, H5_ITER_INC, &idx, - userAttrOpWrpr, (void *) userData); + userAttrOpWrpr, static_cast(userData)); // release memory delete userData; @@ -240,7 +240,7 @@ int H5Location::iterateAttrs( attr_operator_t user_op, unsigned *_idx, void *op_ if( ret_value >= 0 ) { /* Pass back update index value to calling code */ if (_idx) - *_idx = (unsigned)idx; + *_idx = static_cast(idx); return( ret_value ); } @@ -262,7 +262,7 @@ int H5Location::getNumAttrs() const if(H5Oget_info(getId(), &oinfo) < 0) throw AttributeIException(inMemFunc("getNumAttrs"), "H5Oget_info failed"); else - return( (int)oinfo.num_attrs ); + return(static_cast(oinfo.num_attrs)); } //-------------------------------------------------------------------------- @@ -517,7 +517,7 @@ ssize_t H5Location::getComment(const char* name, size_t buf_size, char* comment) } // If the comment is longer than the provided buffer size, the C library // will not null terminate it - if ((size_t)comment_len >= buf_size) + if (static_cast(comment_len) >= buf_size) comment[buf_size-1] = '\0'; // Return the actual comment length, which might be different from buf_size diff --git a/c++/src/H5Object.cpp b/c++/src/H5Object.cpp index 35e34b5..3cce9fe 100644 --- a/c++/src/H5Object.cpp +++ b/c++/src/H5Object.cpp @@ -109,7 +109,7 @@ H5std_string H5Object::getObjName() const H5std_string obj_name(""); // object name to return // Preliminary call to get the size of the object name - ssize_t name_size = H5Iget_name(getId(), NULL, (size_t)0); + ssize_t name_size = H5Iget_name(getId(), NULL, static_cast(0)); // If H5Iget_name failed, throw exception if (name_size < 0) diff --git a/c++/src/H5PropList.cpp b/c++/src/H5PropList.cpp index 81bb023..b954191 100644 --- a/c++/src/H5PropList.cpp +++ b/c++/src/H5PropList.cpp @@ -592,7 +592,7 @@ void PropList::setProperty(const char* name, void* value) const //-------------------------------------------------------------------------- void PropList::setProperty(const char* name, const char* charptr) const { - herr_t ret_value = H5Pset(id, name, (void*) charptr); + herr_t ret_value = H5Pset(id, name, (void*)charptr); if (ret_value < 0) { throw PropListIException(inMemFunc("setProperty"), "H5Pset failed"); diff --git a/c++/test/dsets.cpp b/c++/test/dsets.cpp index e57e50e..1837d17 100644 --- a/c++/test/dsets.cpp +++ b/c++/test/dsets.cpp @@ -246,10 +246,10 @@ test_simple_io( H5File& file) DataSet dataset (file.createDataSet (DSET_SIMPLE_IO_NAME, PredType::NATIVE_INT, space)); // Write the data to the dataset - dataset.write ((void*) points, PredType::NATIVE_INT, DataSpace::ALL, DataSpace::ALL, xfer); + dataset.write (static_cast(points), PredType::NATIVE_INT, DataSpace::ALL, DataSpace::ALL, xfer); // Read the dataset back - dataset.read ((void*) check, PredType::NATIVE_INT, DataSpace::ALL, DataSpace::ALL, xfer); + dataset.read (static_cast(check), PredType::NATIVE_INT, DataSpace::ALL, DataSpace::ALL, xfer); // Check that the values read are the same as the values written for (i = 0; i < 100; i++) @@ -395,10 +395,10 @@ test_tconv( H5File& file) DataSet dataset (file.createDataSet (DSET_TCONV_NAME, PredType::STD_I32LE, space)); // Write the data to the dataset - dataset.write ((void*) out, PredType::STD_I32LE); + dataset.write (static_cast(out), PredType::STD_I32LE); // Read data with byte order conversion - dataset.read ((void*) in, PredType::STD_I32BE); + dataset.read (static_cast(in), PredType::STD_I32BE); // Check for (int i = 0; i < 1000000; i++) { @@ -501,7 +501,7 @@ test_compression(H5File& file) for (i = n = 0; i < 100; i++) { for (j = 0; j < 200; j++) { - points[i][j] = (int)n++; + points[i][j] = static_cast(n++); } } char* tconv_buf = new char [1000]; @@ -539,15 +539,15 @@ test_compression(H5File& file) */ SUBTEST("Compression (uninitialized read)"); - dataset->read ((void*) check, PredType::NATIVE_INT, DataSpace::ALL, DataSpace::ALL, xfer); + dataset->read (static_cast(check), PredType::NATIVE_INT, DataSpace::ALL, DataSpace::ALL, xfer); for (i=0; i(i) << "," << + static_cast(j) << endl; throw Exception("test_compression", "Failed in uninitialized read"); } } @@ -565,11 +565,11 @@ test_compression(H5File& file) { for (j=0; j(n++); } } - dataset->write ((void*) points, PredType::NATIVE_INT, DataSpace::ALL, DataSpace::ALL, xfer); + dataset->write (static_cast(points), PredType::NATIVE_INT, DataSpace::ALL, DataSpace::ALL, xfer); PASSED(); @@ -580,7 +580,7 @@ test_compression(H5File& file) SUBTEST("Compression (read)"); // Read the dataset back - dataset->read ((void*)check, PredType::NATIVE_INT, DataSpace::ALL, DataSpace::ALL, xfer); + dataset->read (static_cast(check), PredType::NATIVE_INT, DataSpace::ALL, DataSpace::ALL, xfer); // Check that the values read are the same as the values written for (i = 0; i < size[0]; i++) @@ -609,10 +609,10 @@ test_compression(H5File& file) points[i][j] = rand (); } } - dataset->write ((void*)points, PredType::NATIVE_INT, DataSpace::ALL, DataSpace::ALL, xfer); + dataset->write (static_cast(points), PredType::NATIVE_INT, DataSpace::ALL, DataSpace::ALL, xfer); // Read the dataset back and check it - dataset->read ((void*)check, PredType::NATIVE_INT, DataSpace::ALL, DataSpace::ALL, xfer); + dataset->read (static_cast(check), PredType::NATIVE_INT, DataSpace::ALL, DataSpace::ALL, xfer); // Check that the values read are the same as the values written for (i = 0; i < size[0]; i++) @@ -637,7 +637,7 @@ test_compression(H5File& file) delete dataset; dataset = new DataSet (file.openDataSet (DSET_COMPRESS_NAME)); - dataset->read ((void*)check, PredType::NATIVE_INT, DataSpace::ALL, DataSpace::ALL, xfer); + dataset->read (static_cast(check), PredType::NATIVE_INT, DataSpace::ALL, DataSpace::ALL, xfer); // Check that the values read are the same as the values written for (i = 0; i < size[0]; i++) @@ -667,8 +667,8 @@ test_compression(H5File& file) } } space1.selectHyperslab( H5S_SELECT_SET, hs_size, hs_offset ); - dataset->write ((void*)points, PredType::NATIVE_INT, space1, space1, xfer); - dataset->read ((void*)check, PredType::NATIVE_INT, space1, space1, xfer); + dataset->write (static_cast(points), PredType::NATIVE_INT, space1, space1, xfer); + dataset->read (static_cast(check), PredType::NATIVE_INT, space1, space1, xfer); // Check that the values read are the same as the values written for (i=0; i((hs_offset[0]+i)) << + "," << static_cast((hs_offset[1]+j)) << endl; - cerr << " At original: " << (int)points[hs_offset[0]+i][hs_offset[1]+j] << endl; - cerr << " At returned: " << (int)check[hs_offset[0]+i][hs_offset[1]+j] << endl; + cerr << " At original: " << static_cast(points[hs_offset[0]+i][hs_offset[1]+j]) << endl; + cerr << " At returned: " << static_cast(check[hs_offset[0]+i][hs_offset[1]+j]) << endl; throw Exception("test_compression", "Failed in partial I/O"); } } // for j @@ -714,8 +714,8 @@ test_compression(H5File& file) DataSpace space2 (2, size, NULL); dataset = new DataSet (file.createDataSet (DSET_BOGUS_NAME, PredType::NATIVE_INT, space2, dscreatplist)); - dataset->write ((void*)points, PredType::NATIVE_INT, DataSpace::ALL, DataSpace::ALL, xfer); - dataset->read ((void*)check, PredType::NATIVE_INT, DataSpace::ALL, DataSpace::ALL, xfer); + dataset->write (static_cast(points), PredType::NATIVE_INT, DataSpace::ALL, DataSpace::ALL, xfer); + dataset->read (static_cast(check), PredType::NATIVE_INT, DataSpace::ALL, DataSpace::ALL, xfer); // Check that the values read are the same as the values written for (i = 0; i < size[0]; i++) @@ -812,8 +812,8 @@ test_multiopen (H5File& file) space->getSimpleExtentDims (tmp_size); if (cur_size[0]!=tmp_size[0]) { - cerr << " Got " << (int)tmp_size[0] << " instead of " - << (int)cur_size[0] << "!" << endl; + cerr << " Got " << static_cast(tmp_size[0]) << " instead of " + << static_cast(cur_size[0]) << "!" << endl; throw Exception("test_multiopen", "Failed in multi-open with extending"); } @@ -897,7 +897,7 @@ test_types(H5File& file) // Fill buffer for (i=0; i(0xff) ^ static_cast(i); // Write data from buf using all default dataspaces and property list dset->write (buf, type); @@ -926,7 +926,7 @@ test_types(H5File& file) // Fill buffer for (i=0; i(0xff) ^ static_cast(i); // Write data from buf using all default dataspaces and property // list; if writing fails, deallocate dset and return. @@ -959,7 +959,7 @@ test_types(H5File& file) // Fill buffer for (i=0; i(0xff) ^ static_cast(i); // Write data from buf using all default dataspaces and property // list; if writing fails, deallocate dset and return. @@ -992,7 +992,7 @@ test_types(H5File& file) // Fill buffer for (i=0; i(0xff) ^ static_cast(i); // Write data from buf using all default dataspaces and property // list; if writing fails, deallocate dset and return. diff --git a/c++/test/h5cpputil.cpp b/c++/test/h5cpputil.cpp index 40e81cc..9bbb183 100644 --- a/c++/test/h5cpputil.cpp +++ b/c++/test/h5cpputil.cpp @@ -195,7 +195,7 @@ void verify_val(const char* x, const char* value, const char* where, int line, c cerr << "*** UNEXPECTED VALUE from " << where << " should be " << value << ", but is " << x << " at line " << line << " in " << file_name << endl; - IncTestNumErrs(); + //IncTestNumErrs(); throw TestFailedException(where, ""); } } -- cgit v0.12