Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
L
libcifpp
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
open
libcifpp
Commits
8b2e02e1
Unverified
Commit
8b2e02e1
authored
Sep 06, 2023
by
Maarten L. Hekkelman
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
documented row
parent
1addd2be
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
108 additions
and
0 deletions
+108
-0
include/cif++/row.hpp
+108
-0
No files found.
include/cif++/row.hpp
View file @
8b2e02e1
...
@@ -30,6 +30,51 @@
...
@@ -30,6 +30,51 @@
#include <array>
#include <array>
/**
* @file row.hpp
*
* The class cif::row should be an opaque type. It is used to store the
* internal data per row in a category. You should use cif::row_handle
* to get access to the contents in a row.
*
* One could think of rows as vectors of cif::item. But internally
* that's not the case.
*
* You can access the values of stored items by name or index.
* The return value of operator[] is an cif::item_handle object.
*
* @code {.cpp}
* cif::category &atom_site = my_db["atom_site"];
* cif::row_handle rh = atom_site.front();
*
* // by name:
* std::string name = rh["label_atom_id"].as<std::string>();
*
* // by index:
* uint16_t ix = atom_site.get_column_ix("label_atom_id");
* assert(rh[ix].as<std::string() == name);
* @endcode
*
* There some template magic here to allow easy extracting of data
* from rows. This can be done using cif::tie e.g.:
*
* @code {.cpp}
* std::string name;
* float x, y, z;
*
* cif::tie(name, x, y, z) = rh.get("label_atom_id", "cartn_x", "cartn_y", "cartn_z");
* @endcode
*
* However, a more modern way uses structured binding:
*
* @code {.cpp}
* const auto &[name, x, y, z] = rh.get<std::string,float,float,float>("label_atom_id", "cartn_x", "cartn_y", "cartn_z");
* @endcode
*
*
*
*/
namespace
cif
namespace
cif
{
{
...
@@ -96,6 +141,8 @@ namespace detail
...
@@ -96,6 +141,8 @@ namespace detail
}
// namespace detail
}
// namespace detail
/// \brief similar to std::tie, assign values to each element in @a v from the
/// result of a get on a row_handle.
template
<
typename
...
Ts
>
template
<
typename
...
Ts
>
auto
tie
(
Ts
&
...
v
)
auto
tie
(
Ts
&
...
v
)
{
{
...
@@ -150,6 +197,7 @@ class row : public std::vector<item_value>
...
@@ -150,6 +197,7 @@ class row : public std::vector<item_value>
class
row_handle
class
row_handle
{
{
public
:
public
:
/** @cond */
friend
struct
item_handle
;
friend
struct
item_handle
;
friend
class
category
;
friend
class
category
;
friend
class
category_index
;
friend
class
category_index
;
...
@@ -163,79 +211,119 @@ class row_handle
...
@@ -163,79 +211,119 @@ class row_handle
row_handle
&
operator
=
(
const
row_handle
&
)
=
default
;
row_handle
&
operator
=
(
const
row_handle
&
)
=
default
;
row_handle
&
operator
=
(
row_handle
&&
)
=
default
;
row_handle
&
operator
=
(
row_handle
&&
)
=
default
;
/** @endcond */
/// \brief constructor taking a category @a cat and a row @a r
row_handle
(
const
category
&
cat
,
const
row
&
r
)
row_handle
(
const
category
&
cat
,
const
row
&
r
)
:
m_category
(
const_cast
<
category
*>
(
&
cat
))
:
m_category
(
const_cast
<
category
*>
(
&
cat
))
,
m_row
(
const_cast
<
row
*>
(
&
r
))
,
m_row
(
const_cast
<
row
*>
(
&
r
))
{
{
}
}
/// \brief return the category this row belongs to
const
category
&
get_category
()
const
const
category
&
get_category
()
const
{
{
return
*
m_category
;
return
*
m_category
;
}
}
/// \brief Return true if the row is empty or uninitialised
bool
empty
()
const
bool
empty
()
const
{
{
return
m_category
==
nullptr
or
m_row
==
nullptr
;
return
m_category
==
nullptr
or
m_row
==
nullptr
;
}
}
/// \brief convenience method to test for empty()
explicit
operator
bool
()
const
explicit
operator
bool
()
const
{
{
return
not
empty
();
return
not
empty
();
}
}
/// \brief return a cif::item_handle to the item in column @a column_ix
item_handle
operator
[](
uint16_t
column_ix
)
item_handle
operator
[](
uint16_t
column_ix
)
{
{
return
empty
()
?
item_handle
::
s_null_item
:
item_handle
(
column_ix
,
*
this
);
return
empty
()
?
item_handle
::
s_null_item
:
item_handle
(
column_ix
,
*
this
);
}
}
/// \brief return a const cif::item_handle to the item in column @a column_ix
const
item_handle
operator
[](
uint16_t
column_ix
)
const
const
item_handle
operator
[](
uint16_t
column_ix
)
const
{
{
return
empty
()
?
item_handle
::
s_null_item
:
item_handle
(
column_ix
,
const_cast
<
row_handle
&>
(
*
this
));
return
empty
()
?
item_handle
::
s_null_item
:
item_handle
(
column_ix
,
const_cast
<
row_handle
&>
(
*
this
));
}
}
/// \brief return a cif::item_handle to the item in the column named @a column_name
item_handle
operator
[](
std
::
string_view
column_name
)
item_handle
operator
[](
std
::
string_view
column_name
)
{
{
return
empty
()
?
item_handle
::
s_null_item
:
item_handle
(
add_column
(
column_name
),
*
this
);
return
empty
()
?
item_handle
::
s_null_item
:
item_handle
(
add_column
(
column_name
),
*
this
);
}
}
/// \brief return a const cif::item_handle to the item in the column named @a column_name
const
item_handle
operator
[](
std
::
string_view
column_name
)
const
const
item_handle
operator
[](
std
::
string_view
column_name
)
const
{
{
return
empty
()
?
item_handle
::
s_null_item
:
item_handle
(
get_column_ix
(
column_name
),
const_cast
<
row_handle
&>
(
*
this
));
return
empty
()
?
item_handle
::
s_null_item
:
item_handle
(
get_column_ix
(
column_name
),
const_cast
<
row_handle
&>
(
*
this
));
}
}
/// \brief Return an object that can be used in combination with cif::tie
/// to assign the values for the columns @a columns
template
<
typename
...
C
>
template
<
typename
...
C
>
auto
get
(
C
...
columns
)
const
auto
get
(
C
...
columns
)
const
{
{
return
detail
::
get_row_result
<
C
...
>
(
*
this
,
{
get_column_ix
(
columns
)...
});
return
detail
::
get_row_result
<
C
...
>
(
*
this
,
{
get_column_ix
(
columns
)...
});
}
}
/// \brief Return a tuple of values of types @a Ts for the columns @a columns
template
<
typename
...
Ts
,
typename
...
C
,
std
::
enable_if_t
<
sizeof
...(
Ts
)
==
sizeof
...(
C
)
and
sizeof
...(
C
)
!=
1
,
int
>
=
0
>
template
<
typename
...
Ts
,
typename
...
C
,
std
::
enable_if_t
<
sizeof
...(
Ts
)
==
sizeof
...(
C
)
and
sizeof
...(
C
)
!=
1
,
int
>
=
0
>
std
::
tuple
<
Ts
...
>
get
(
C
...
columns
)
const
std
::
tuple
<
Ts
...
>
get
(
C
...
columns
)
const
{
{
return
detail
::
get_row_result
<
Ts
...
>
(
*
this
,
{
get_column_ix
(
columns
)...
});
return
detail
::
get_row_result
<
Ts
...
>
(
*
this
,
{
get_column_ix
(
columns
)...
});
}
}
/// \brief Get the value of column @a column cast to type @a T
template
<
typename
T
>
template
<
typename
T
>
T
get
(
const
char
*
column
)
const
T
get
(
const
char
*
column
)
const
{
{
return
operator
[](
get_column_ix
(
column
)).
template
as
<
T
>
();
return
operator
[](
get_column_ix
(
column
)).
template
as
<
T
>
();
}
}
/// \brief assign each of the columns named in @a values to their respective value
void
assign
(
const
std
::
vector
<
item
>
&
values
)
void
assign
(
const
std
::
vector
<
item
>
&
values
)
{
{
for
(
auto
&
value
:
values
)
for
(
auto
&
value
:
values
)
assign
(
value
,
true
);
assign
(
value
,
true
);
}
}
/** \brief assign the value @a value to the column named @a name
*
* If updateLinked it true, linked records are updated as well.
* That means that if column @name is part of the link definition
* and the link results in a linked record in another category
* this record in the linked category is updated as well.
*
* If validate is true, which is default, the assigned value is
* checked to see if it conforms to the rules defined in the dictionary
*/
void
assign
(
std
::
string_view
name
,
std
::
string_view
value
,
bool
updateLinked
,
bool
validate
=
true
)
void
assign
(
std
::
string_view
name
,
std
::
string_view
value
,
bool
updateLinked
,
bool
validate
=
true
)
{
{
assign
(
add_column
(
name
),
value
,
updateLinked
,
validate
);
assign
(
add_column
(
name
),
value
,
updateLinked
,
validate
);
}
}
/** \brief assign the value @a value to column at index @a column
*
* If updateLinked it true, linked records are updated as well.
* That means that if column @a column is part of the link definition
* and the link results in a linked record in another category
* this record in the linked category is updated as well.
*
* If validate is true, which is default, the assigned value is
* checked to see if it conforms to the rules defined in the dictionary
*/
void
assign
(
uint16_t
column
,
std
::
string_view
value
,
bool
updateLinked
,
bool
validate
=
true
);
void
assign
(
uint16_t
column
,
std
::
string_view
value
,
bool
updateLinked
,
bool
validate
=
true
);
/// \brief compare two rows
bool
operator
==
(
const
row_handle
&
rhs
)
const
{
return
m_category
==
rhs
.
m_category
and
m_row
==
rhs
.
m_row
;
}
bool
operator
==
(
const
row_handle
&
rhs
)
const
{
return
m_category
==
rhs
.
m_category
and
m_row
==
rhs
.
m_row
;
}
/// \brief compare two rows
bool
operator
!=
(
const
row_handle
&
rhs
)
const
{
return
m_category
!=
rhs
.
m_category
or
m_row
!=
rhs
.
m_row
;
}
bool
operator
!=
(
const
row_handle
&
rhs
)
const
{
return
m_category
!=
rhs
.
m_category
or
m_row
!=
rhs
.
m_row
;
}
private
:
private
:
...
@@ -267,9 +355,17 @@ class row_handle
...
@@ -267,9 +355,17 @@ class row_handle
// --------------------------------------------------------------------
// --------------------------------------------------------------------
/**
* @brief The class row_initializer is a list of cif::item's.
*
* This class is used to construct new rows, it allows to
* group a list of item name and value pairs and pass it
* in one go to the constructing function.
*/
class
row_initializer
:
public
std
::
vector
<
item
>
class
row_initializer
:
public
std
::
vector
<
item
>
{
{
public
:
public
:
/** @cond */
friend
class
category
;
friend
class
category
;
row_initializer
()
=
default
;
row_initializer
()
=
default
;
...
@@ -278,26 +374,38 @@ class row_initializer : public std::vector<item>
...
@@ -278,26 +374,38 @@ class row_initializer : public std::vector<item>
row_initializer
&
operator
=
(
const
row_initializer
&
)
=
default
;
row_initializer
&
operator
=
(
const
row_initializer
&
)
=
default
;
row_initializer
&
operator
=
(
row_initializer
&&
)
=
default
;
row_initializer
&
operator
=
(
row_initializer
&&
)
=
default
;
/** @endcond */
/// \brief constructor taking a std::initializer_list of items
row_initializer
(
std
::
initializer_list
<
item
>
items
)
row_initializer
(
std
::
initializer_list
<
item
>
items
)
:
std
::
vector
<
item
>
(
items
)
:
std
::
vector
<
item
>
(
items
)
{
{
}
}
/// \brief constructor taking a range of items
template
<
typename
ItemIter
,
std
::
enable_if_t
<
std
::
is_same_v
<
typename
ItemIter
::
value_type
,
item
>
,
int
>
=
0
>
template
<
typename
ItemIter
,
std
::
enable_if_t
<
std
::
is_same_v
<
typename
ItemIter
::
value_type
,
item
>
,
int
>
=
0
>
row_initializer
(
ItemIter
b
,
ItemIter
e
)
row_initializer
(
ItemIter
b
,
ItemIter
e
)
:
std
::
vector
<
item
>
(
b
,
e
)
:
std
::
vector
<
item
>
(
b
,
e
)
{
{
}
}
/// \brief constructor taking the values of an existing row
row_initializer
(
row_handle
rh
);
row_initializer
(
row_handle
rh
);
/// \brief set the value for item name @a name to @a value
void
set_value
(
std
::
string_view
name
,
std
::
string_view
value
);
void
set_value
(
std
::
string_view
name
,
std
::
string_view
value
);
/// \brief set the value for item based on @a i
void
set_value
(
const
item
&
i
)
void
set_value
(
const
item
&
i
)
{
{
set_value
(
i
.
name
(),
i
.
value
());
set_value
(
i
.
name
(),
i
.
value
());
}
}
/// \brief set the value for item name @a name to @a value, but only if the item did not have a value already
void
set_value_if_empty
(
std
::
string_view
name
,
std
::
string_view
value
);
void
set_value_if_empty
(
std
::
string_view
name
,
std
::
string_view
value
);
/// \brief set the value for item @a i, but only if the item did not have a value already
void
set_value_if_empty
(
const
item
&
i
)
void
set_value_if_empty
(
const
item
&
i
)
{
{
set_value_if_empty
(
i
.
name
(),
i
.
value
());
set_value_if_empty
(
i
.
name
(),
i
.
value
());
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment