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
345c4778
Unverified
Commit
345c4778
authored
Sep 08, 2021
by
Maarten L. Hekkelman
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
start structure-test unit test
added compare functions for Datablock and Category
parent
0ccb2f88
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
2083 additions
and
1608 deletions
+2083
-1608
CMakeLists.txt
+1
-0
include/cif++/Cif++.hpp
+859
-745
include/cif++/Structure.hpp
+22
-7
src/Cif++.cpp
+998
-812
src/Structure.cpp
+78
-42
test/structure-test.cpp
+124
-0
test/unit-test.cpp
+1
-2
No files found.
CMakeLists.txt
View file @
345c4778
...
@@ -385,6 +385,7 @@ if(CIFPP_BUILD_TESTS)
...
@@ -385,6 +385,7 @@ if(CIFPP_BUILD_TESTS)
list
(
APPEND CIFPP_tests
list
(
APPEND CIFPP_tests
# pdb2cif
# pdb2cif
rename-compound
rename-compound
structure
unit
)
unit
)
foreach
(
CIFPP_TEST IN LISTS CIFPP_tests
)
foreach
(
CIFPP_TEST IN LISTS CIFPP_tests
)
...
...
include/cif++/Cif++.hpp
View file @
345c4778
...
@@ -28,14 +28,14 @@
...
@@ -28,14 +28,14 @@
#include <string>
#include <string>
#include <regex>
#include <array>
#include <functional>
#include <iostream>
#include <iostream>
#include <sstream>
#include <set>
#include <list>
#include <list>
#include <array>
#include <optional>
#include <optional>
#include <functional>
#include <regex>
#include <set>
#include <sstream>
#include "cif++/CifUtils.hpp"
#include "cif++/CifUtils.hpp"
...
@@ -117,7 +117,7 @@ CIFPP_EXPORT extern int VERBOSE;
...
@@ -117,7 +117,7 @@ CIFPP_EXPORT extern int VERBOSE;
class
File
;
class
File
;
class
Datablock
;
class
Datablock
;
class
Category
;
class
Category
;
class
Row
;
// a flyweight class that references data in categories
class
Row
;
// a flyweight class that references data in categories
class
RowSet
;
class
RowSet
;
class
Item
;
class
Item
;
class
Validator
;
class
Validator
;
...
@@ -141,43 +141,57 @@ class Item
...
@@ -141,43 +141,57 @@ class Item
public
:
public
:
Item
()
{}
Item
()
{}
template
<
typename
T
,
std
::
enable_if_t
<
std
::
is_arithmetic_v
<
T
>
,
int
>
=
0
>
template
<
typename
T
,
std
::
enable_if_t
<
std
::
is_arithmetic_v
<
T
>
,
int
>
=
0
>
Item
(
const
std
::
string
&
name
,
const
T
&
value
)
Item
(
const
std
::
string
&
name
,
const
T
&
value
)
:
mName
(
name
),
mValue
(
std
::
to_string
(
value
))
{}
:
mName
(
name
)
,
mValue
(
std
::
to_string
(
value
))
{
}
Item
(
const
std
::
string
&
name
,
const
std
::
string
&
value
)
Item
(
const
std
::
string
&
name
,
const
std
::
string
&
value
)
:
mName
(
name
),
mValue
(
value
)
{}
:
mName
(
name
)
,
mValue
(
value
)
{
}
Item
(
const
Item
&
rhs
)
:
mName
(
rhs
.
mName
),
mValue
(
rhs
.
mValue
)
{}
Item
(
const
Item
&
rhs
)
Item
(
Item
&&
rhs
)
noexcept
:
mName
(
std
::
move
(
rhs
.
mName
)),
mValue
(
std
::
move
(
rhs
.
mValue
))
{}
:
mName
(
rhs
.
mName
)
,
mValue
(
rhs
.
mValue
)
{
}
Item
(
Item
&&
rhs
)
noexcept
:
mName
(
std
::
move
(
rhs
.
mName
))
,
mValue
(
std
::
move
(
rhs
.
mValue
))
{
}
Item
&
operator
=
(
const
Item
&
rhs
)
Item
&
operator
=
(
const
Item
&
rhs
)
{
{
if
(
this
!=
&
rhs
)
if
(
this
!=
&
rhs
)
{
{
mName
=
rhs
.
mName
;
mName
=
rhs
.
mName
;
mValue
=
rhs
.
mValue
;
mValue
=
rhs
.
mValue
;
}
}
return
*
this
;
return
*
this
;
}
}
Item
&
operator
=
(
Item
&&
rhs
)
noexcept
Item
&
operator
=
(
Item
&&
rhs
)
noexcept
{
{
if
(
this
!=
&
rhs
)
if
(
this
!=
&
rhs
)
{
{
mName
=
std
::
move
(
rhs
.
mName
);
mName
=
std
::
move
(
rhs
.
mName
);
mValue
=
std
::
move
(
rhs
.
mValue
);
mValue
=
std
::
move
(
rhs
.
mValue
);
}
}
return
*
this
;
return
*
this
;
}
}
const
std
::
string
&
name
()
const
{
return
mName
;
}
const
std
::
string
&
value
()
const
{
return
mValue
;
}
void
value
(
const
std
::
string
&
v
)
{
mValue
=
v
;
}
const
std
::
string
&
name
()
const
{
return
mName
;
}
const
std
::
string
&
value
()
const
{
return
mValue
;
}
void
value
(
const
std
::
string
&
v
)
{
mValue
=
v
;
}
// empty means either null or unknown
// empty means either null or unknown
bool
empty
()
const
;
bool
empty
()
const
;
...
@@ -187,12 +201,12 @@ class Item
...
@@ -187,12 +201,12 @@ class Item
// is_unknown means the field contains '?'
// is_unknown means the field contains '?'
bool
is_unknown
()
const
;
bool
is_unknown
()
const
;
size_t
length
()
const
{
return
mValue
.
length
();
}
size_t
length
()
const
{
return
mValue
.
length
();
}
const
char
*
c_str
()
const
{
return
mValue
.
c_str
();
}
const
char
*
c_str
()
const
{
return
mValue
.
c_str
();
}
private
:
private
:
std
::
string
mName
;
std
::
string
mName
;
std
::
string
mValue
;
std
::
string
mValue
;
};
};
// --------------------------------------------------------------------
// --------------------------------------------------------------------
...
@@ -202,54 +216,58 @@ class Datablock
...
@@ -202,54 +216,58 @@ class Datablock
{
{
public
:
public
:
friend
class
File
;
friend
class
File
;
using
CategoryList
=
std
::
list
<
Category
>
;
using
CategoryList
=
std
::
list
<
Category
>
;
using
iterator
=
CategoryList
::
iterator
;
using
iterator
=
CategoryList
::
iterator
;
using
const_iterator
=
CategoryList
::
const_iterator
;
using
const_iterator
=
CategoryList
::
const_iterator
;
Datablock
(
const
std
::
string
&
name
);
Datablock
(
const
std
::
string
&
name
);
~
Datablock
();
~
Datablock
();
Datablock
(
const
Datablock
&
)
=
delete
;
Datablock
(
const
Datablock
&
)
=
delete
;
Datablock
&
operator
=
(
const
Datablock
&
)
=
delete
;
Datablock
&
operator
=
(
const
Datablock
&
)
=
delete
;
std
::
string
getName
()
const
{
return
mName
;
}
std
::
string
getName
()
const
{
return
mName
;
}
void
setName
(
const
std
::
string
&
n
)
{
mName
=
n
;
}
void
setName
(
const
std
::
string
&
n
)
{
mName
=
n
;
}
std
::
string
firstItem
(
const
std
::
string
&
tag
)
const
;
iterator
begin
()
{
return
mCategories
.
begin
();
}
std
::
string
firstItem
(
const
std
::
string
&
tag
)
const
;
iterator
end
()
{
return
mCategories
.
end
();
}
const_iterator
begin
()
const
{
return
mCategories
.
begin
();
}
iterator
begin
()
{
return
mCategories
.
begin
();
}
const_iterator
end
()
const
{
return
mCategories
.
end
();
}
iterator
end
()
{
return
mCategories
.
end
();
}
Category
&
operator
[](
const
std
::
string
&
name
);
const_iterator
begin
()
const
{
return
mCategories
.
begin
();
}
const_iterator
end
()
const
{
return
mCategories
.
end
();
}
Category
&
operator
[](
const
std
::
string
&
name
);
std
::
tuple
<
iterator
,
bool
>
emplace
(
const
std
::
string
&
name
);
std
::
tuple
<
iterator
,
bool
>
emplace
(
const
std
::
string
&
name
);
bool
isValid
();
bool
isValid
();
void
validateLinks
()
const
;
void
validateLinks
()
const
;
void
setValidator
(
Validator
*
v
);
void
setValidator
(
Validator
*
v
);
// this one only looks up a Category, returns nullptr if it does not exist
// this one only looks up a Category, returns nullptr if it does not exist
Category
*
get
(
const
std
::
string
&
name
);
const
Category
*
get
(
const
std
::
string
&
name
)
const
;
Category
*
get
(
const
std
::
string
&
name
);
void
getTagOrder
(
std
::
vector
<
std
::
string
>
&
tags
)
const
;
void
write
(
std
::
ostream
&
os
,
const
std
::
vector
<
std
::
string
>
&
order
);
void
write
(
std
::
ostream
&
os
);
void
getTagOrder
(
std
::
vector
<
std
::
string
>&
tags
)
const
;
void
write
(
std
::
ostream
&
os
,
const
std
::
vector
<
std
::
string
>&
order
);
void
write
(
std
::
ostream
&
os
);
// convenience function, add a line to the software category
// convenience function, add a line to the software category
void
add_software
(
const
std
::
string
&
name
,
const
std
::
string
&
classification
,
void
add_software
(
const
std
::
string
&
name
,
const
std
::
string
&
classification
,
const
std
::
string
&
versionNr
,
const
std
::
string
&
versionDate
);
const
std
::
string
&
versionNr
,
const
std
::
string
&
versionDate
);
private
:
friend
bool
operator
==
(
const
Datablock
&
lhs
,
const
Datablock
&
rhs
);
std
::
list
<
Category
>
mCategories
;
friend
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
Datablock
&
data
);
std
::
string
mName
;
Validator
*
mValidator
;
private
:
Datablock
*
mNext
;
std
::
list
<
Category
>
mCategories
;
std
::
string
mName
;
Validator
*
mValidator
;
Datablock
*
mNext
;
};
};
// --------------------------------------------------------------------
// --------------------------------------------------------------------
...
@@ -264,20 +282,19 @@ namespace detail
...
@@ -264,20 +282,19 @@ namespace detail
class
ItemReference
class
ItemReference
{
{
public
:
public
:
// conversion helper class
// conversion helper class
template
<
typename
T
,
typename
=
void
>
template
<
typename
T
,
typename
=
void
>
struct
item_value_as
;
struct
item_value_as
;
template
<
typename
T
,
std
::
enable_if_t
<
std
::
is_arithmetic_v
<
T
>
,
int
>
=
0
>
template
<
typename
T
,
std
::
enable_if_t
<
std
::
is_arithmetic_v
<
T
>
,
int
>
=
0
>
ItemReference
&
operator
=
(
const
T
&
value
)
ItemReference
&
operator
=
(
const
T
&
value
)
{
{
this
->
operator
=
(
std
::
to_string
(
value
));
this
->
operator
=
(
std
::
to_string
(
value
));
return
*
this
;
return
*
this
;
}
}
template
<
typename
T
>
template
<
typename
T
>
ItemReference
&
operator
=
(
const
std
::
optional
<
T
>&
value
)
ItemReference
&
operator
=
(
const
std
::
optional
<
T
>
&
value
)
{
{
if
(
value
)
if
(
value
)
this
->
operator
=
(
*
value
);
this
->
operator
=
(
*
value
);
...
@@ -286,34 +303,34 @@ namespace detail
...
@@ -286,34 +303,34 @@ namespace detail
return
*
this
;
return
*
this
;
}
}
ItemReference
&
operator
=
(
const
std
::
string
&
value
);
ItemReference
&
operator
=
(
const
std
::
string
&
value
);
template
<
typename
...
Ts
>
template
<
typename
...
Ts
>
void
os
(
const
Ts
&
...
v
)
void
os
(
const
Ts
&
...
v
)
{
{
std
::
ostringstream
ss
;
std
::
ostringstream
ss
;
((
ss
<<
v
),
...);
((
ss
<<
v
),
...);
this
->
operator
=
(
ss
.
str
());
this
->
operator
=
(
ss
.
str
());
}
}
void
swap
(
ItemReference
&
b
);
void
swap
(
ItemReference
&
b
);
template
<
typename
T
=
std
::
string
>
template
<
typename
T
=
std
::
string
>
auto
as
()
const
auto
as
()
const
{
{
using
value_type
=
std
::
remove_cv_t
<
std
::
remove_reference_t
<
T
>>
;
using
value_type
=
std
::
remove_cv_t
<
std
::
remove_reference_t
<
T
>>
;
return
item_value_as
<
value_type
>::
convert
(
*
this
);
return
item_value_as
<
value_type
>::
convert
(
*
this
);
}
}
template
<
typename
T
>
template
<
typename
T
>
int
compare
(
const
T
&
value
,
bool
icase
)
const
int
compare
(
const
T
&
value
,
bool
icase
)
const
{
{
return
item_value_as
<
T
>::
compare
(
*
this
,
value
,
icase
);
return
item_value_as
<
T
>::
compare
(
*
this
,
value
,
icase
);
}
}
// empty means either null or unknown
// empty means either null or unknown
bool
empty
()
const
;
bool
empty
()
const
;
explicit
operator
bool
()
const
{
return
not
empty
();
}
explicit
operator
bool
()
const
{
return
not
empty
();
}
// is_null means the field contains '.'
// is_null means the field contains '.'
bool
is_null
()
const
;
bool
is_null
()
const
;
...
@@ -321,36 +338,45 @@ namespace detail
...
@@ -321,36 +338,45 @@ namespace detail
// is_unknown means the field contains '?'
// is_unknown means the field contains '?'
bool
is_unknown
()
const
;
bool
is_unknown
()
const
;
const
char
*
c_str
()
const
;
const
char
*
c_str
()
const
;
// the following returns the defaultValue from either the parameter
// the following returns the defaultValue from either the parameter
// or, if specified, the value from _item_default.value in the dictionary
// or, if specified, the value from _item_default.value in the dictionary
const
char
*
c_str
(
const
char
*
defaultValue
)
const
;
const
char
*
c_str
(
const
char
*
defaultValue
)
const
;
bool
operator
!=
(
const
std
::
string
&
s
)
const
{
return
s
!=
c_str
();
}
bool
operator
!=
(
const
std
::
string
&
s
)
const
{
return
s
!=
c_str
();
}
bool
operator
==
(
const
std
::
string
&
s
)
const
{
return
s
==
c_str
();
}
bool
operator
==
(
const
std
::
string
&
s
)
const
{
return
s
==
c_str
();
}
private
:
private
:
friend
class
::
cif
::
Row
;
friend
class
::
cif
::
Row
;
ItemReference
(
const
char
*
name
,
size_t
column
,
Row
&
row
)
ItemReference
(
const
char
*
name
,
size_t
column
,
Row
&
row
)
:
mName
(
name
),
mColumn
(
column
),
mRow
(
row
)
{}
:
mName
(
name
)
,
mColumn
(
column
)
,
mRow
(
row
)
{
}
ItemReference
(
const
char
*
name
,
size_t
column
,
const
Row
&
row
)
ItemReference
(
const
char
*
name
,
size_t
column
,
const
Row
&
row
)
:
mName
(
name
),
mColumn
(
column
),
mRow
(
const_cast
<
Row
&>
(
row
)),
mConst
(
true
)
{}
:
mName
(
name
)
,
mColumn
(
column
)
,
mRow
(
const_cast
<
Row
&>
(
row
))
,
mConst
(
true
)
{
}
const
char
*
mName
;
const
char
*
mName
;
size_t
mColumn
;
size_t
mColumn
;
Row
&
mRow
;
Row
&
mRow
;
bool
mConst
=
false
;
bool
mConst
=
false
;
};
};
template
<
typename
T
>
template
<
typename
T
>
struct
ItemReference
::
item_value_as
<
T
,
std
::
enable_if_t
<
std
::
is_floating_point_v
<
T
>>>
struct
ItemReference
::
item_value_as
<
T
,
std
::
enable_if_t
<
std
::
is_floating_point_v
<
T
>>>
{
{
using
value_type
=
std
::
remove_reference_t
<
std
::
remove_cv_t
<
T
>>
;
using
value_type
=
std
::
remove_reference_t
<
std
::
remove_cv_t
<
T
>>
;
static
value_type
convert
(
const
ItemReference
&
ref
)
static
value_type
convert
(
const
ItemReference
&
ref
)
{
{
value_type
result
=
{};
value_type
result
=
{};
if
(
not
ref
.
empty
())
if
(
not
ref
.
empty
())
...
@@ -358,11 +384,11 @@ namespace detail
...
@@ -358,11 +384,11 @@ namespace detail
return
result
;
return
result
;
}
}
static
int
compare
(
const
ItemReference
&
ref
,
double
value
,
bool
icase
)
static
int
compare
(
const
ItemReference
&
ref
,
double
value
,
bool
icase
)
{
{
int
result
=
0
;
int
result
=
0
;
const
char
*
s
=
ref
.
c_str
();
const
char
*
s
=
ref
.
c_str
();
if
(
s
==
nullptr
or
*
s
==
0
)
if
(
s
==
nullptr
or
*
s
==
0
)
result
=
1
;
result
=
1
;
...
@@ -383,15 +409,15 @@ namespace detail
...
@@ -383,15 +409,15 @@ namespace detail
result
=
1
;
result
=
1
;
}
}
}
}
return
result
;
return
result
;
}
}
};
};
template
<
typename
T
>
template
<
typename
T
>
struct
ItemReference
::
item_value_as
<
T
,
std
::
enable_if_t
<
std
::
is_integral_v
<
T
>
and
std
::
is_unsigned_v
<
T
>
and
not
std
::
is_same_v
<
T
,
bool
>>>
struct
ItemReference
::
item_value_as
<
T
,
std
::
enable_if_t
<
std
::
is_integral_v
<
T
>
and
std
::
is_unsigned_v
<
T
>
and
not
std
::
is_same_v
<
T
,
bool
>>>
{
{
static
T
convert
(
const
ItemReference
&
ref
)
static
T
convert
(
const
ItemReference
&
ref
)
{
{
T
result
=
{};
T
result
=
{};
if
(
not
ref
.
empty
())
if
(
not
ref
.
empty
())
...
@@ -399,11 +425,11 @@ namespace detail
...
@@ -399,11 +425,11 @@ namespace detail
return
result
;
return
result
;
}
}
static
int
compare
(
const
ItemReference
&
ref
,
unsigned
long
value
,
bool
icase
)
static
int
compare
(
const
ItemReference
&
ref
,
unsigned
long
value
,
bool
icase
)
{
{
int
result
=
0
;
int
result
=
0
;
const
char
*
s
=
ref
.
c_str
();
const
char
*
s
=
ref
.
c_str
();
if
(
s
==
nullptr
or
*
s
==
0
)
if
(
s
==
nullptr
or
*
s
==
0
)
result
=
1
;
result
=
1
;
...
@@ -424,15 +450,15 @@ namespace detail
...
@@ -424,15 +450,15 @@ namespace detail
result
=
1
;
result
=
1
;
}
}
}
}
return
result
;
return
result
;
}
}
};
};
template
<
typename
T
>
template
<
typename
T
>
struct
ItemReference
::
item_value_as
<
T
,
std
::
enable_if_t
<
std
::
is_integral_v
<
T
>
and
std
::
is_signed_v
<
T
>
and
not
std
::
is_same_v
<
T
,
bool
>>>
struct
ItemReference
::
item_value_as
<
T
,
std
::
enable_if_t
<
std
::
is_integral_v
<
T
>
and
std
::
is_signed_v
<
T
>
and
not
std
::
is_same_v
<
T
,
bool
>>>
{
{
static
T
convert
(
const
ItemReference
&
ref
)
static
T
convert
(
const
ItemReference
&
ref
)
{
{
T
result
=
{};
T
result
=
{};
if
(
not
ref
.
empty
())
if
(
not
ref
.
empty
())
...
@@ -440,11 +466,11 @@ namespace detail
...
@@ -440,11 +466,11 @@ namespace detail
return
result
;
return
result
;
}
}
static
int
compare
(
const
ItemReference
&
ref
,
long
value
,
bool
icase
)
static
int
compare
(
const
ItemReference
&
ref
,
long
value
,
bool
icase
)
{
{
int
result
=
0
;
int
result
=
0
;
const
char
*
s
=
ref
.
c_str
();
const
char
*
s
=
ref
.
c_str
();
if
(
s
==
nullptr
or
*
s
==
0
)
if
(
s
==
nullptr
or
*
s
==
0
)
result
=
1
;
result
=
1
;
...
@@ -465,15 +491,15 @@ namespace detail
...
@@ -465,15 +491,15 @@ namespace detail
result
=
1
;
result
=
1
;
}
}
}
}
return
result
;
return
result
;
}
}
};
};
template
<
typename
T
>
template
<
typename
T
>
struct
ItemReference
::
item_value_as
<
std
::
optional
<
T
>>
struct
ItemReference
::
item_value_as
<
std
::
optional
<
T
>>
{
{
static
std
::
optional
<
T
>
convert
(
const
ItemReference
&
ref
)
static
std
::
optional
<
T
>
convert
(
const
ItemReference
&
ref
)
{
{
std
::
optional
<
T
>
result
;
std
::
optional
<
T
>
result
;
if
(
ref
)
if
(
ref
)
...
@@ -481,11 +507,11 @@ namespace detail
...
@@ -481,11 +507,11 @@ namespace detail
return
result
;
return
result
;
}
}
static
int
compare
(
const
ItemReference
&
ref
,
std
::
optional
<
T
>
value
,
bool
icase
)
static
int
compare
(
const
ItemReference
&
ref
,
std
::
optional
<
T
>
value
,
bool
icase
)
{
{
if
(
ref
.
empty
()
and
not
value
)
if
(
ref
.
empty
()
and
not
value
)
return
0
;
return
0
;
if
(
ref
.
empty
())
if
(
ref
.
empty
())
return
-
1
;
return
-
1
;
else
if
(
not
value
)
else
if
(
not
value
)
...
@@ -495,10 +521,10 @@ namespace detail
...
@@ -495,10 +521,10 @@ namespace detail
}
}
};
};
template
<
typename
T
>
template
<
typename
T
>
struct
ItemReference
::
item_value_as
<
T
,
std
::
enable_if_t
<
std
::
is_same_v
<
T
,
bool
>>>
struct
ItemReference
::
item_value_as
<
T
,
std
::
enable_if_t
<
std
::
is_same_v
<
T
,
bool
>>>
{
{
static
bool
convert
(
const
ItemReference
&
ref
)
static
bool
convert
(
const
ItemReference
&
ref
)
{
{
bool
result
=
false
;
bool
result
=
false
;
if
(
not
ref
.
empty
())
if
(
not
ref
.
empty
())
...
@@ -506,110 +532,114 @@ namespace detail
...
@@ -506,110 +532,114 @@ namespace detail
return
result
;
return
result
;
}
}
static
int
compare
(
const
ItemReference
&
ref
,
bool
value
,
bool
icase
)
static
int
compare
(
const
ItemReference
&
ref
,
bool
value
,
bool
icase
)
{
{
bool
rv
=
convert
(
ref
);
bool
rv
=
convert
(
ref
);
return
value
&&
rv
?
0
return
value
&&
rv
?
0
:
(
rv
<
value
?
-
1
:
1
);
:
(
rv
<
value
?
-
1
:
1
);
}
}
};
};
template
<
size_t
N
>
template
<
size_t
N
>
struct
ItemReference
::
item_value_as
<
char
[
N
]
>
struct
ItemReference
::
item_value_as
<
char
[
N
]
>
{
{
static
int
compare
(
const
ItemReference
&
ref
,
const
char
(
&
value
)[
N
],
bool
icase
)
static
int
compare
(
const
ItemReference
&
ref
,
const
char
(
&
value
)[
N
],
bool
icase
)
{
{
return
icase
?
cif
::
icompare
(
ref
.
c_str
(),
value
)
:
std
::
strcmp
(
ref
.
c_str
(),
value
);
return
icase
?
cif
::
icompare
(
ref
.
c_str
(),
value
)
:
std
::
strcmp
(
ref
.
c_str
(),
value
);
}
}
};
};
template
<>
template
<>
struct
ItemReference
::
item_value_as
<
const
char
*>
struct
ItemReference
::
item_value_as
<
const
char
*>
{
{
static
const
char
*
convert
(
const
ItemReference
&
ref
)
static
const
char
*
convert
(
const
ItemReference
&
ref
)
{
{
return
ref
.
c_str
();
return
ref
.
c_str
();
}
}
static
int
compare
(
const
ItemReference
&
ref
,
const
char
*
value
,
bool
icase
)
static
int
compare
(
const
ItemReference
&
ref
,
const
char
*
value
,
bool
icase
)
{
{
return
icase
?
cif
::
icompare
(
ref
.
c_str
(),
value
)
:
std
::
strcmp
(
ref
.
c_str
(),
value
);
return
icase
?
cif
::
icompare
(
ref
.
c_str
(),
value
)
:
std
::
strcmp
(
ref
.
c_str
(),
value
);
}
}
};
};
template
<>
template
<>
struct
ItemReference
::
item_value_as
<
std
::
string
>
struct
ItemReference
::
item_value_as
<
std
::
string
>
{
{
static
std
::
string
convert
(
const
ItemReference
&
ref
)
static
std
::
string
convert
(
const
ItemReference
&
ref
)
{
{
return
ref
.
c_str
();
return
ref
.
c_str
();
}
}
static
int
compare
(
const
ItemReference
&
ref
,
const
std
::
string
&
value
,
bool
icase
)
static
int
compare
(
const
ItemReference
&
ref
,
const
std
::
string
&
value
,
bool
icase
)
{
{
return
icase
?
cif
::
icompare
(
ref
.
c_str
(),
value
)
:
std
::
strcmp
(
ref
.
c_str
(),
value
.
c_str
());
return
icase
?
cif
::
icompare
(
ref
.
c_str
(),
value
)
:
std
::
strcmp
(
ref
.
c_str
(),
value
.
c_str
());
}
}
};
};
// some helper classes to help create tuple result types
// some helper classes to help create tuple result types
template
<
typename
...
C
>
template
<
typename
...
C
>
struct
getRowResult
struct
getRowResult
{
{
static
constexpr
size_t
N
=
sizeof
...(
C
);
static
constexpr
size_t
N
=
sizeof
...(
C
);
getRowResult
(
const
Row
&
r
,
std
::
array
<
size_t
,
N
>&&
columns
)
getRowResult
(
const
Row
&
r
,
std
::
array
<
size_t
,
N
>
&&
columns
)
:
mRow
(
r
),
mColumns
(
std
::
move
(
columns
))
:
mRow
(
r
)
,
mColumns
(
std
::
move
(
columns
))
{
{
}
}
const
ItemReference
operator
[](
size_t
ix
)
const
const
ItemReference
operator
[](
size_t
ix
)
const
{
{
return
mRow
[
mColumns
[
ix
]];
return
mRow
[
mColumns
[
ix
]];
}
}
template
<
typename
...
Ts
,
std
::
enable_if_t
<
N
==
sizeof
...(
Ts
),
int
>
=
0
>
template
<
typename
...
Ts
,
std
::
enable_if_t
<
N
==
sizeof
...(
Ts
),
int
>
=
0
>
operator
std
::
tuple
<
Ts
...
>
()
const
operator
std
::
tuple
<
Ts
...
>
()
const
{
{
return
get
<
Ts
...
>
(
std
::
index_sequence_for
<
Ts
...
>
{});
return
get
<
Ts
...
>
(
std
::
index_sequence_for
<
Ts
...
>
{});
}
}
template
<
typename
...
Ts
,
std
::
size_t
...
Is
>
template
<
typename
...
Ts
,
std
::
size_t
...
Is
>
std
::
tuple
<
Ts
...
>
get
(
std
::
index_sequence
<
Is
...
>
)
const
std
::
tuple
<
Ts
...
>
get
(
std
::
index_sequence
<
Is
...
>
)
const
{
{
return
std
::
tuple
<
Ts
...
>
{
mRow
[
mColumns
[
Is
]].
template
as
<
Ts
>
()...};
return
std
::
tuple
<
Ts
...
>
{
mRow
[
mColumns
[
Is
]].
template
as
<
Ts
>
()...};
}
}
const
Row
&
mRow
;
const
Row
&
mRow
;
std
::
array
<
size_t
,
N
>
mColumns
;
std
::
array
<
size_t
,
N
>
mColumns
;
};
};
// we want to be able to tie some variables to a RowResult, for this we use tiewraps
// we want to be able to tie some variables to a RowResult, for this we use tiewraps
template
<
typename
...
Ts
>
template
<
typename
...
Ts
>
struct
tieWrap
struct
tieWrap
{
{
tieWrap
(
Ts
...
args
)
:
mVal
(
args
...)
{}
tieWrap
(
Ts
...
args
)
:
mVal
(
args
...)
{
}
template
<
typename
RR
>
template
<
typename
RR
>
void
operator
=
(
const
RR
&&
rr
)
void
operator
=
(
const
RR
&&
rr
)
{
{
// getRowResult will do the conversion, but only if the types
// getRowResult will do the conversion, but only if the types
// are compatible. That means the number of parameters to the get()
// are compatible. That means the number of parameters to the get()
// of the row should be equal to the number of items in the tuple
// of the row should be equal to the number of items in the tuple
// you are trying to tie.
// you are trying to tie.
using
RType
=
std
::
tuple
<
typename
std
::
remove_reference
<
Ts
>::
type
...
>
;
using
RType
=
std
::
tuple
<
typename
std
::
remove_reference
<
Ts
>::
type
...
>
;
mVal
=
static_cast
<
RType
>
(
rr
);
mVal
=
static_cast
<
RType
>
(
rr
);
}
}
std
::
tuple
<
Ts
...
>
mVal
;
std
::
tuple
<
Ts
...
>
mVal
;
};
};
}
}
// namespace detail
template
<
typename
...
Ts
>
template
<
typename
...
Ts
>
auto
tie
(
Ts
&
...
v
)
auto
tie
(
Ts
&
...
v
)
{
{
return
detail
::
tieWrap
<
Ts
&
...
>
(
std
::
forward
<
Ts
&>
(
v
)...);
return
detail
::
tieWrap
<
Ts
&
...
>
(
std
::
forward
<
Ts
&>
(
v
)...);
}
}
class
Row
class
Row
...
@@ -622,19 +652,26 @@ class Row
...
@@ -622,19 +652,26 @@ class Row
friend
class
RowSet
;
friend
class
RowSet
;
Row
()
Row
()
:
mData
(
nullptr
)
{}
:
mData
(
nullptr
)
{
}
Row
(
ItemRow
*
data
)
Row
(
ItemRow
*
data
)
:
mData
(
data
)
{}
:
mData
(
data
)
{
}
Row
(
const
ItemRow
*
data
)
Row
(
const
ItemRow
*
data
)
:
mData
(
const_cast
<
ItemRow
*>
(
data
)),
mCascade
(
false
)
{}
:
mData
(
const_cast
<
ItemRow
*>
(
data
))
,
mCascade
(
false
)
{
}
Row
(
const
Row
&
rhs
);
Row
(
const
Row
&
rhs
);
Row
&
operator
=
(
const
Row
&
rhs
);
Row
&
operator
=
(
const
Row
&
rhs
);
Row
(
Row
&&
rhs
);
Row
(
Row
&&
rhs
);
Row
&
operator
=
(
Row
&&
rhs
);
Row
&
operator
=
(
Row
&&
rhs
);
~
Row
();
~
Row
();
...
@@ -643,49 +680,53 @@ class Row
...
@@ -643,49 +680,53 @@ class Row
mCascade
=
cascade
;
mCascade
=
cascade
;
}
}
void
next
();
///< make this row point to the next ItemRow
void
next
();
///< make this row point to the next ItemRow
struct
const_iterator
struct
const_iterator
{
{
using
iterator_category
=
std
::
forward_iterator_tag
;
using
iterator_category
=
std
::
forward_iterator_tag
;
using
value_type
=
const
Item
;
using
value_type
=
const
Item
;
using
difference_type
=
std
::
ptrdiff_t
;
using
difference_type
=
std
::
ptrdiff_t
;
using
pointer
=
value_type
*
;
using
pointer
=
value_type
*
;
using
reference
=
value_type
&
;
using
reference
=
value_type
&
;
const_iterator
(
ItemRow
*
data
,
ItemValue
*
ptr
);
const_iterator
(
ItemRow
*
data
,
ItemValue
*
ptr
);
reference
operator
*
()
{
return
mCurrent
;
}
reference
operator
*
()
{
return
mCurrent
;
}
pointer
operator
->
()
{
return
&
mCurrent
;
}
pointer
operator
->
()
{
return
&
mCurrent
;
}
const_iterator
&
operator
++
();
const_iterator
operator
++
(
int
)
{
const_iterator
result
(
*
this
);
this
->
operator
++
();
return
result
;
}
bool
operator
==
(
const
const_iterator
&
rhs
)
const
{
return
mPtr
==
rhs
.
mPtr
;
}
bool
operator
!=
(
const
const_iterator
&
rhs
)
const
{
return
mPtr
!=
rhs
.
mPtr
;
}
private
:
const_iterator
&
operator
++
();
const_iterator
operator
++
(
int
)
{
const_iterator
result
(
*
this
);
this
->
operator
++
();
return
result
;
}
bool
operator
==
(
const
const_iterator
&
rhs
)
const
{
return
mPtr
==
rhs
.
mPtr
;
}
bool
operator
!=
(
const
const_iterator
&
rhs
)
const
{
return
mPtr
!=
rhs
.
mPtr
;
}
private
:
void
fetch
();
void
fetch
();
ItemRow
*
mData
;
ItemRow
*
mData
;
ItemValue
*
mPtr
;
ItemValue
*
mPtr
;
Item
mCurrent
;
Item
mCurrent
;
};
};
// checks for an initialized Row:
// checks for an initialized Row:
explicit
operator
bool
()
const
{
return
mData
!=
nullptr
;
}
explicit
operator
bool
()
const
{
return
mData
!=
nullptr
;
}
// for debugging
// for debugging
uint32_t
lineNr
()
const
;
uint32_t
lineNr
()
const
;
void
lineNr
(
uint32_t
l
);
void
lineNr
(
uint32_t
l
);
bool
empty
()
const
;
bool
empty
()
const
;
const_iterator
begin
()
const
;
const_iterator
begin
()
const
;
const_iterator
end
()
const
;
const_iterator
end
()
const
;
// TODO: implement real const version?
// TODO: implement real const version?
friend
class
detail
::
ItemReference
;
friend
class
detail
::
ItemReference
;
const
detail
::
ItemReference
operator
[](
size_t
column
)
const
const
detail
::
ItemReference
operator
[](
size_t
column
)
const
...
@@ -693,32 +734,32 @@ class Row
...
@@ -693,32 +734,32 @@ class Row
return
detail
::
ItemReference
(
"<anonymous column>"
,
column
,
*
this
);
return
detail
::
ItemReference
(
"<anonymous column>"
,
column
,
*
this
);
}
}
const
detail
::
ItemReference
operator
[](
const
char
*
itemTag
)
const
const
detail
::
ItemReference
operator
[](
const
char
*
itemTag
)
const
{
{
size_t
column
=
ColumnForItemTag
(
itemTag
);
size_t
column
=
ColumnForItemTag
(
itemTag
);
return
detail
::
ItemReference
(
itemTag
,
column
,
*
this
);
return
detail
::
ItemReference
(
itemTag
,
column
,
*
this
);
}
}
detail
::
ItemReference
operator
[](
const
char
*
itemTag
)
detail
::
ItemReference
operator
[](
const
char
*
itemTag
)
{
{
size_t
column
=
ColumnForItemTag
(
itemTag
);
size_t
column
=
ColumnForItemTag
(
itemTag
);
return
detail
::
ItemReference
(
itemTag
,
column
,
*
this
);
return
detail
::
ItemReference
(
itemTag
,
column
,
*
this
);
}
}
const
detail
::
ItemReference
operator
[](
const
std
::
string
&
itemTag
)
const
const
detail
::
ItemReference
operator
[](
const
std
::
string
&
itemTag
)
const
{
{
size_t
column
=
ColumnForItemTag
(
itemTag
.
c_str
());
size_t
column
=
ColumnForItemTag
(
itemTag
.
c_str
());
return
detail
::
ItemReference
(
itemTag
.
c_str
(),
column
,
*
this
);
return
detail
::
ItemReference
(
itemTag
.
c_str
(),
column
,
*
this
);
}
}
detail
::
ItemReference
operator
[](
const
std
::
string
&
itemTag
)
detail
::
ItemReference
operator
[](
const
std
::
string
&
itemTag
)
{
{
size_t
column
=
ColumnForItemTag
(
itemTag
.
c_str
());
size_t
column
=
ColumnForItemTag
(
itemTag
.
c_str
());
return
detail
::
ItemReference
(
itemTag
.
c_str
(),
column
,
*
this
);
return
detail
::
ItemReference
(
itemTag
.
c_str
(),
column
,
*
this
);
}
}
template
<
typename
...
Ts
,
size_t
N
>
template
<
typename
...
Ts
,
size_t
N
>
std
::
tuple
<
Ts
...
>
get
(
char
const
*
const
(
&
columns
)[
N
])
const
std
::
tuple
<
Ts
...
>
get
(
char
const
*
const
(
&
columns
)[
N
])
const
{
{
static_assert
(
sizeof
...(
Ts
)
==
N
,
"Number of columns should be equal to number of types to return"
);
static_assert
(
sizeof
...(
Ts
)
==
N
,
"Number of columns should be equal to number of types to return"
);
...
@@ -728,46 +769,45 @@ class Row
...
@@ -728,46 +769,45 @@ class Row
return
detail
::
getRowResult
<
Ts
...
>
(
*
this
,
std
::
move
(
cix
));
return
detail
::
getRowResult
<
Ts
...
>
(
*
this
,
std
::
move
(
cix
));
}
}
template
<
typename
...
C
>
template
<
typename
...
C
>
auto
get
(
C
...
columns
)
const
auto
get
(
C
...
columns
)
const
{
{
return
detail
::
getRowResult
<
C
...
>
(
*
this
,
{
ColumnForItemTag
(
columns
)...
});
return
detail
::
getRowResult
<
C
...
>
(
*
this
,
{
ColumnForItemTag
(
columns
)...
});
}
}
void
assign
(
const
std
::
vector
<
Item
>&
values
);
void
assign
(
const
std
::
string
&
name
,
const
std
::
string
&
value
,
bool
updateLinked
);
bool
operator
==
(
const
Row
&
rhs
)
const
void
assign
(
const
std
::
vector
<
Item
>
&
values
);
void
assign
(
const
std
::
string
&
name
,
const
std
::
string
&
value
,
bool
updateLinked
);
bool
operator
==
(
const
Row
&
rhs
)
const
{
{
return
mData
==
rhs
.
mData
;
return
mData
==
rhs
.
mData
;
}
}
bool
operator
!=
(
const
Row
&
rhs
)
const
bool
operator
!=
(
const
Row
&
rhs
)
const
{
{
return
mData
!=
rhs
.
mData
;
return
mData
!=
rhs
.
mData
;
}
}
ItemRow
*
data
()
const
{
return
mData
;
}
ItemRow
*
data
()
const
{
return
mData
;
}
void
swap
(
Row
&
rhs
)
void
swap
(
Row
&
rhs
)
{
{
std
::
swap
(
mData
,
rhs
.
mData
);
std
::
swap
(
mData
,
rhs
.
mData
);
}
}
friend
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
Row
&
row
);
friend
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
Row
&
row
);
private
:
private
:
void
assign
(
size_t
column
,
const
std
::
string
&
value
,
bool
updateLinked
);
void
assign
(
const
Item
&
i
,
bool
updateLinked
);
void
assign
(
size_t
column
,
const
std
::
string
&
value
,
bool
updateLinked
);
static
void
swap
(
size_t
column
,
ItemRow
*
a
,
ItemRow
*
b
);
void
assign
(
const
Item
&
i
,
bool
updateLinked
);
static
void
swap
(
size_t
column
,
ItemRow
*
a
,
ItemRow
*
b
);
size_t
ColumnForItemTag
(
const
char
*
itemTag
)
const
;
size_t
ColumnForItemTag
(
const
char
*
itemTag
)
const
;
ItemRow
*
mData
;
ItemRow
*
mData
;
uint32_t
mLineNr
=
0
;
uint32_t
mLineNr
=
0
;
bool
mCascade
=
true
;
bool
mCascade
=
true
;
};
};
// --------------------------------------------------------------------
// --------------------------------------------------------------------
...
@@ -776,45 +816,50 @@ class Row
...
@@ -776,45 +816,50 @@ class Row
namespace
detail
namespace
detail
{
{
struct
ConditionImpl
struct
ConditionImpl
{
{
virtual
~
ConditionImpl
()
{}
virtual
~
ConditionImpl
()
{}
virtual
void
prepare
(
const
Category
&
c
)
{}
virtual
bool
test
(
const
Category
&
c
,
const
Row
&
r
)
const
=
0
;
virtual
void
str
(
std
::
ostream
&
os
)
const
=
0
;
};
struct
AllConditionImpl
:
public
ConditionImpl
virtual
void
prepare
(
const
Category
&
c
)
{}
{
virtual
bool
test
(
const
Category
&
c
,
const
Row
&
r
)
const
=
0
;
virtual
bool
test
(
const
Category
&
c
,
const
Row
&
r
)
const
{
return
true
;
}
virtual
void
str
(
std
::
ostream
&
os
)
const
=
0
;
virtual
void
str
(
std
::
ostream
&
os
)
const
{
os
<<
"*"
;
}
};
};
struct
OrConditionImpl
;
struct
AllConditionImpl
:
public
ConditionImpl
struct
AndConditionImpl
;
{
struct
NotConditionImpl
;
virtual
bool
test
(
const
Category
&
c
,
const
Row
&
r
)
const
{
return
true
;
}
virtual
void
str
(
std
::
ostream
&
os
)
const
{
os
<<
"*"
;
}
};
}
struct
OrConditionImpl
;
struct
AndConditionImpl
;
struct
NotConditionImpl
;
}
// namespace detail
class
Condition
class
Condition
{
{
public
:
public
:
Condition
()
:
mImpl
(
nullptr
)
{
}
Condition
(
detail
::
ConditionImpl
*
impl
)
:
mImpl
(
impl
)
{
}
Condition
()
:
mImpl
(
nullptr
)
{}
Condition
(
const
Condition
&
)
=
delete
;
Condition
(
detail
::
ConditionImpl
*
impl
)
:
mImpl
(
impl
)
{}
Condition
(
const
Condition
&
)
=
delete
;
Condition
(
Condition
&&
rhs
)
noexcept
Condition
(
Condition
&&
rhs
)
noexcept
:
mImpl
(
nullptr
)
:
mImpl
(
nullptr
)
{
{
std
::
swap
(
mImpl
,
rhs
.
mImpl
);
std
::
swap
(
mImpl
,
rhs
.
mImpl
);
}
}
Condition
&
operator
=
(
const
Condition
&
)
=
delete
;
Condition
&
operator
=
(
const
Condition
&
)
=
delete
;
Condition
&
operator
=
(
Condition
&&
rhs
)
noexcept
Condition
&
operator
=
(
Condition
&&
rhs
)
noexcept
{
{
std
::
swap
(
mImpl
,
rhs
.
mImpl
);
std
::
swap
(
mImpl
,
rhs
.
mImpl
);
return
*
this
;
return
*
this
;
...
@@ -825,44 +870,44 @@ class Condition
...
@@ -825,44 +870,44 @@ class Condition
delete
mImpl
;
delete
mImpl
;
mImpl
=
nullptr
;
mImpl
=
nullptr
;
}
}
void
prepare
(
const
Category
&
c
)
void
prepare
(
const
Category
&
c
)
{
{
if
(
mImpl
)
if
(
mImpl
)
mImpl
->
prepare
(
c
);
mImpl
->
prepare
(
c
);
mPrepared
=
true
;
mPrepared
=
true
;
}
}
bool
operator
()(
const
Category
&
c
,
const
Row
&
r
)
const
bool
operator
()(
const
Category
&
c
,
const
Row
&
r
)
const
{
{
assert
(
mImpl
);
assert
(
mImpl
);
assert
(
mPrepared
);
assert
(
mPrepared
);
return
mImpl
?
mImpl
->
test
(
c
,
r
)
:
false
;
return
mImpl
?
mImpl
->
test
(
c
,
r
)
:
false
;
}
}
bool
empty
()
const
{
return
mImpl
==
nullptr
;
}
friend
Condition
operator
||
(
Condition
&&
a
,
Condition
&&
b
);
bool
empty
()
const
{
return
mImpl
==
nullptr
;
}
friend
Condition
operator
&&
(
Condition
&&
a
,
Condition
&&
b
);
friend
Condition
operator
||
(
Condition
&&
a
,
Condition
&&
b
);
friend
Condition
operator
&&
(
Condition
&&
a
,
Condition
&&
b
);
friend
struct
detail
::
OrConditionImpl
;
friend
struct
detail
::
OrConditionImpl
;
friend
struct
detail
::
AndConditionImpl
;
friend
struct
detail
::
AndConditionImpl
;
friend
struct
detail
::
NotConditionImpl
;
friend
struct
detail
::
NotConditionImpl
;
void
swap
(
Condition
&
rhs
)
void
swap
(
Condition
&
rhs
)
{
{
std
::
swap
(
mImpl
,
rhs
.
mImpl
);
std
::
swap
(
mImpl
,
rhs
.
mImpl
);
std
::
swap
(
mPrepared
,
rhs
.
mPrepared
);
std
::
swap
(
mPrepared
,
rhs
.
mPrepared
);
}
}
friend
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
Condition
&
cond
);
friend
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
Condition
&
cond
);
private
:
private
:
detail
::
ConditionImpl
*
mImpl
;
detail
::
ConditionImpl
*
mImpl
;
bool
mPrepared
=
false
;
bool
mPrepared
=
false
;
};
};
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
Condition
&
cond
)
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
Condition
&
cond
)
{
{
if
(
cond
.
mImpl
)
if
(
cond
.
mImpl
)
cond
.
mImpl
->
str
(
os
);
cond
.
mImpl
->
str
(
os
);
...
@@ -872,219 +917,235 @@ inline std::ostream& operator<<(std::ostream& os, const Condition& cond)
...
@@ -872,219 +917,235 @@ inline std::ostream& operator<<(std::ostream& os, const Condition& cond)
namespace
detail
namespace
detail
{
{
struct
KeyIsEmptyConditionImpl
:
public
ConditionImpl
struct
KeyIsEmptyConditionImpl
:
public
ConditionImpl
{
KeyIsEmptyConditionImpl
(
const
std
::
string
&
ItemTag
)
:
mItemTag
(
ItemTag
)
{}
virtual
void
prepare
(
const
Category
&
c
);
virtual
bool
test
(
const
Category
&
c
,
const
Row
&
r
)
const
{
{
return
r
[
mItemIx
].
empty
();
KeyIsEmptyConditionImpl
(
const
std
::
string
&
ItemTag
)
}
:
mItemTag
(
ItemTag
)
{
}
virtual
void
str
(
std
::
ostream
&
os
)
const
virtual
void
prepare
(
const
Category
&
c
);
{
os
<<
mItemTag
<<
" IS NULL"
;
}
std
::
string
mItemTag
;
virtual
bool
test
(
const
Category
&
c
,
const
Row
&
r
)
const
size_t
mItemIx
=
0
;
{
};
return
r
[
mItemIx
].
empty
();
}
struct
KeyCompareConditionImpl
:
public
ConditionImpl
virtual
void
str
(
std
::
ostream
&
os
)
const
{
{
template
<
typename
COMP
>
os
<<
mItemTag
<<
" IS NULL"
;
KeyCompareConditionImpl
(
const
std
::
string
&
ItemTag
,
COMP
&&
comp
,
const
std
::
string
&
s
)
}
:
mItemTag
(
ItemTag
),
mComp
(
std
::
move
(
comp
)),
mStr
(
s
)
{}
virtual
void
prepare
(
const
Category
&
c
);
virtual
bool
test
(
const
Category
&
c
,
const
Row
&
r
)
const
{
return
mComp
(
c
,
r
,
mCaseInsensitive
);
}
virtual
void
str
(
std
::
ostream
&
os
)
const
{
os
<<
mItemTag
<<
(
mCaseInsensitive
?
"^ "
:
" "
)
<<
mStr
;
}
std
::
string
mItemTag
;
std
::
string
mItemTag
;
size_t
mItemIx
=
0
;
size_t
mItemIx
=
0
;
bool
mCaseInsensitive
=
false
;
};
std
::
function
<
bool
(
const
Category
&
,
const
Row
&
,
bool
)
>
mComp
;
std
::
string
mStr
;
};
struct
KeyMatchesConditionImpl
:
public
ConditionImpl
struct
KeyCompareConditionImpl
:
public
ConditionImpl
{
KeyMatchesConditionImpl
(
const
std
::
string
&
ItemTag
,
const
std
::
regex
&
rx
)
:
mItemTag
(
ItemTag
),
mItemIx
(
0
),
mRx
(
rx
)
{}
virtual
void
prepare
(
const
Category
&
c
);
virtual
bool
test
(
const
Category
&
c
,
const
Row
&
r
)
const
{
{
return
std
::
regex_match
(
r
[
mItemIx
].
as
<
std
::
string
>
(),
mRx
);
template
<
typename
COMP
>
}
KeyCompareConditionImpl
(
const
std
::
string
&
ItemTag
,
COMP
&&
comp
,
const
std
::
string
&
s
)
:
mItemTag
(
ItemTag
)
,
mComp
(
std
::
move
(
comp
))
,
mStr
(
s
)
{
}
virtual
void
str
(
std
::
ostream
&
os
)
const
virtual
void
prepare
(
const
Category
&
c
);
{
os
<<
mItemTag
<<
" =~ expression"
;
}
std
::
string
mItemTag
;
size_t
mItemIx
;
std
::
regex
mRx
;
};
template
<
typename
T
>
virtual
bool
test
(
const
Category
&
c
,
const
Row
&
r
)
const
struct
AnyIsConditionImpl
:
public
ConditionImpl
{
{
return
mComp
(
c
,
r
,
mCaseInsensitive
);
typedef
T
valueType
;
}
AnyIsConditionImpl
(
const
valueType
&
value
)
:
mValue
(
value
)
{}
virtual
bool
test
(
const
Category
&
c
,
const
Row
&
r
)
const
;
virtual
void
str
(
std
::
ostream
&
os
)
const
{
os
<<
"<any> == "
<<
mValue
;
}
valueType
mValue
;
virtual
void
str
(
std
::
ostream
&
os
)
const
};
{
os
<<
mItemTag
<<
(
mCaseInsensitive
?
"^ "
:
" "
)
<<
mStr
;
}
struct
AnyMatchesConditionImpl
:
public
ConditionImpl
std
::
string
mItemTag
;
{
size_t
mItemIx
=
0
;
AnyMatchesConditionImpl
(
const
std
::
regex
&
rx
)
bool
mCaseInsensitive
=
false
;
:
mRx
(
rx
)
{}
std
::
function
<
bool
(
const
Category
&
,
const
Row
&
,
bool
)
>
mComp
;
std
::
string
mStr
;
virtual
bool
test
(
const
Category
&
c
,
const
Row
&
r
)
const
;
};
virtual
void
str
(
std
::
ostream
&
os
)
const
struct
KeyMatchesConditionImpl
:
public
ConditionImpl
{
{
os
<<
"<any> =~ expression"
;
KeyMatchesConditionImpl
(
const
std
::
string
&
ItemTag
,
const
std
::
regex
&
rx
)
}
:
mItemTag
(
ItemTag
)
,
mItemIx
(
0
)
,
mRx
(
rx
)
{
}
std
::
regex
mRx
;
virtual
void
prepare
(
const
Category
&
c
);
};
struct
AndConditionImpl
:
public
ConditionImpl
virtual
bool
test
(
const
Category
&
c
,
const
Row
&
r
)
const
{
{
AndConditionImpl
(
Condition
&&
a
,
Condition
&&
b
)
return
std
::
regex_match
(
r
[
mItemIx
].
as
<
std
::
string
>
(),
mRx
);
:
mA
(
nullptr
),
mB
(
nullptr
)
}
{
std
::
swap
(
mA
,
a
.
mImpl
);
std
::
swap
(
mB
,
b
.
mImpl
);
}
~
AndConditionImpl
()
{
delete
mA
;
delete
mB
;
}
virtual
void
prepare
(
const
Category
&
c
)
{
mA
->
prepare
(
c
);
mB
->
prepare
(
c
);
}
virtual
bool
test
(
const
Category
&
c
,
const
Row
&
r
)
const
{
return
mA
->
test
(
c
,
r
)
and
mB
->
test
(
c
,
r
);
}
virtual
void
str
(
std
::
ostream
&
os
)
const
virtual
void
str
(
std
::
ostream
&
os
)
const
{
{
os
<<
'('
;
os
<<
mItemTag
<<
" =~ expression"
;
mA
->
str
(
os
);
}
os
<<
") AND ("
;
mB
->
str
(
os
);
os
<<
')'
;
}
ConditionImpl
*
mA
;
std
::
string
mItemTag
;
ConditionImpl
*
mB
;
size_t
mItemIx
;
};
std
::
regex
mRx
;
};
struct
OrConditionImpl
:
public
ConditionImpl
template
<
typename
T
>
{
struct
AnyIsConditionImpl
:
public
ConditionImpl
OrConditionImpl
(
Condition
&&
a
,
Condition
&&
b
)
:
mA
(
nullptr
),
mB
(
nullptr
)
{
std
::
swap
(
mA
,
a
.
mImpl
);
std
::
swap
(
mB
,
b
.
mImpl
);
}
~
OrConditionImpl
()
{
delete
mA
;
delete
mB
;
}
virtual
void
prepare
(
const
Category
&
c
)
{
mA
->
prepare
(
c
);
mB
->
prepare
(
c
);
}
virtual
bool
test
(
const
Category
&
c
,
const
Row
&
r
)
const
{
{
return
mA
->
test
(
c
,
r
)
or
mB
->
test
(
c
,
r
);
typedef
T
valueType
;
}
virtual
void
str
(
std
::
ostream
&
os
)
const
AnyIsConditionImpl
(
const
valueType
&
value
)
{
:
mValue
(
value
)
os
<<
'('
;
{
mA
->
str
(
os
);
}
os
<<
") OR ("
;
mB
->
str
(
os
);
os
<<
')'
;
}
ConditionImpl
*
mA
;
virtual
bool
test
(
const
Category
&
c
,
const
Row
&
r
)
const
;
ConditionImpl
*
mB
;
virtual
void
str
(
std
::
ostream
&
os
)
const
};
{
os
<<
"<any> == "
<<
mValue
;
}
struct
NotConditionImpl
:
public
ConditionImpl
valueType
mValue
;
{
};
NotConditionImpl
(
Condition
&&
a
)
:
mA
(
nullptr
)
struct
AnyMatchesConditionImpl
:
public
ConditionImpl
{
std
::
swap
(
mA
,
a
.
mImpl
);
}
~
NotConditionImpl
()
{
{
delete
mA
;
AnyMatchesConditionImpl
(
const
std
::
regex
&
rx
)
}
:
mRx
(
rx
)
{
virtual
void
prepare
(
const
Category
&
c
)
}
virtual
bool
test
(
const
Category
&
c
,
const
Row
&
r
)
const
;
virtual
void
str
(
std
::
ostream
&
os
)
const
{
os
<<
"<any> =~ expression"
;
}
std
::
regex
mRx
;
};
struct
AndConditionImpl
:
public
ConditionImpl
{
{
mA
->
prepare
(
c
);
AndConditionImpl
(
Condition
&&
a
,
Condition
&&
b
)
}
:
mA
(
nullptr
)
,
mB
(
nullptr
)
virtual
bool
test
(
const
Category
&
c
,
const
Row
&
r
)
const
{
std
::
swap
(
mA
,
a
.
mImpl
);
std
::
swap
(
mB
,
b
.
mImpl
);
}
~
AndConditionImpl
()
{
delete
mA
;
delete
mB
;
}
virtual
void
prepare
(
const
Category
&
c
)
{
mA
->
prepare
(
c
);
mB
->
prepare
(
c
);
}
virtual
bool
test
(
const
Category
&
c
,
const
Row
&
r
)
const
{
return
mA
->
test
(
c
,
r
)
and
mB
->
test
(
c
,
r
);
}
virtual
void
str
(
std
::
ostream
&
os
)
const
{
os
<<
'('
;
mA
->
str
(
os
);
os
<<
") AND ("
;
mB
->
str
(
os
);
os
<<
')'
;
}
ConditionImpl
*
mA
;
ConditionImpl
*
mB
;
};
struct
OrConditionImpl
:
public
ConditionImpl
{
{
return
not
mA
->
test
(
c
,
r
);
OrConditionImpl
(
Condition
&&
a
,
Condition
&&
b
)
}
:
mA
(
nullptr
)
,
mB
(
nullptr
)
{
std
::
swap
(
mA
,
a
.
mImpl
);
std
::
swap
(
mB
,
b
.
mImpl
);
}
~
OrConditionImpl
()
{
delete
mA
;
delete
mB
;
}
virtual
void
prepare
(
const
Category
&
c
)
{
mA
->
prepare
(
c
);
mB
->
prepare
(
c
);
}
virtual
void
str
(
std
::
ostream
&
os
)
const
virtual
bool
test
(
const
Category
&
c
,
const
Row
&
r
)
const
{
return
mA
->
test
(
c
,
r
)
or
mB
->
test
(
c
,
r
);
}
virtual
void
str
(
std
::
ostream
&
os
)
const
{
os
<<
'('
;
mA
->
str
(
os
);
os
<<
") OR ("
;
mB
->
str
(
os
);
os
<<
')'
;
}
ConditionImpl
*
mA
;
ConditionImpl
*
mB
;
};
struct
NotConditionImpl
:
public
ConditionImpl
{
{
os
<<
"NOT ("
;
NotConditionImpl
(
Condition
&&
a
)
mA
->
str
(
os
);
:
mA
(
nullptr
)
os
<<
')'
;
{
}
std
::
swap
(
mA
,
a
.
mImpl
);
}
ConditionImpl
*
mA
;
~
NotConditionImpl
()
};
{
delete
mA
;
}
}
virtual
void
prepare
(
const
Category
&
c
)
{
mA
->
prepare
(
c
);
}
virtual
bool
test
(
const
Category
&
c
,
const
Row
&
r
)
const
{
return
not
mA
->
test
(
c
,
r
);
}
virtual
void
str
(
std
::
ostream
&
os
)
const
{
os
<<
"NOT ("
;
mA
->
str
(
os
);
os
<<
')'
;
}
ConditionImpl
*
mA
;
};
inline
Condition
operator
&&
(
Condition
&&
a
,
Condition
&&
b
)
}
// namespace detail
inline
Condition
operator
&&
(
Condition
&&
a
,
Condition
&&
b
)
{
{
if
(
a
.
mImpl
and
b
.
mImpl
)
if
(
a
.
mImpl
and
b
.
mImpl
)
return
Condition
(
new
detail
::
AndConditionImpl
(
std
::
move
(
a
),
std
::
move
(
b
)));
return
Condition
(
new
detail
::
AndConditionImpl
(
std
::
move
(
a
),
std
::
move
(
b
)));
...
@@ -1093,7 +1154,7 @@ inline Condition operator&&(Condition&& a, Condition&& b)
...
@@ -1093,7 +1154,7 @@ inline Condition operator&&(Condition&& a, Condition&& b)
return
Condition
(
std
::
move
(
b
));
return
Condition
(
std
::
move
(
b
));
}
}
inline
Condition
operator
||
(
Condition
&&
a
,
Condition
&&
b
)
inline
Condition
operator
||
(
Condition
&&
a
,
Condition
&&
b
)
{
{
if
(
a
.
mImpl
and
b
.
mImpl
)
if
(
a
.
mImpl
and
b
.
mImpl
)
return
Condition
(
new
detail
::
OrConditionImpl
(
std
::
move
(
a
),
std
::
move
(
b
)));
return
Condition
(
new
detail
::
OrConditionImpl
(
std
::
move
(
a
),
std
::
move
(
b
)));
...
@@ -1102,38 +1163,50 @@ inline Condition operator||(Condition&& a, Condition&& b)
...
@@ -1102,38 +1163,50 @@ inline Condition operator||(Condition&& a, Condition&& b)
return
Condition
(
std
::
move
(
b
));
return
Condition
(
std
::
move
(
b
));
}
}
struct
Empty
{};
struct
Empty
{
};
struct
Key
struct
Key
{
{
Key
(
const
std
::
string
&
itemTag
)
:
mItemTag
(
itemTag
)
{}
Key
(
const
std
::
string
&
itemTag
)
Key
(
const
char
*
itemTag
)
:
mItemTag
(
itemTag
)
{}
:
mItemTag
(
itemTag
)
{
}
Key
(
const
char
*
itemTag
)
:
mItemTag
(
itemTag
)
{
}
Key
(
const
Key
&
)
=
delete
;
Key
&
operator
=
(
const
Key
&
)
=
delete
;
Key
(
const
Key
&
)
=
delete
;
Key
&
operator
=
(
const
Key
&
)
=
delete
;
std
::
string
mItemTag
;
std
::
string
mItemTag
;
};
};
template
<
typename
T
>
template
<
typename
T
>
Condition
operator
==
(
const
Key
&
key
,
const
T
&
v
)
Condition
operator
==
(
const
Key
&
key
,
const
T
&
v
)
{
{
std
::
ostringstream
s
;
std
::
ostringstream
s
;
s
<<
" == "
<<
v
;
s
<<
" == "
<<
v
;
return
Condition
(
new
detail
::
KeyCompareConditionImpl
(
key
.
mItemTag
,
[
tag
=
key
.
mItemTag
,
v
](
const
Category
&
c
,
const
Row
&
r
,
bool
icase
)
return
Condition
(
new
detail
::
KeyCompareConditionImpl
(
{
return
r
[
tag
].
template
compare
<
T
>
(
v
,
icase
)
==
0
;
},
s
.
str
()));
key
.
mItemTag
,
[
tag
=
key
.
mItemTag
,
v
](
const
Category
&
c
,
const
Row
&
r
,
bool
icase
)
{
return
r
[
tag
].
template
compare
<
T
>
(
v
,
icase
)
==
0
;
},
s
.
str
()));
}
}
inline
Condition
operator
==
(
const
Key
&
key
,
const
char
*
value
)
inline
Condition
operator
==
(
const
Key
&
key
,
const
char
*
value
)
{
{
if
(
value
!=
nullptr
and
*
value
!=
0
)
if
(
value
!=
nullptr
and
*
value
!=
0
)
{
{
std
::
ostringstream
s
;
std
::
ostringstream
s
;
s
<<
" == "
<<
value
;
s
<<
" == "
<<
value
;
return
Condition
(
new
detail
::
KeyCompareConditionImpl
(
key
.
mItemTag
,
[
tag
=
key
.
mItemTag
,
value
](
const
Category
&
c
,
const
Row
&
r
,
bool
icase
)
return
Condition
(
new
detail
::
KeyCompareConditionImpl
(
{
return
r
[
tag
].
compare
(
value
,
icase
)
==
0
;
},
s
.
str
()));
key
.
mItemTag
,
[
tag
=
key
.
mItemTag
,
value
](
const
Category
&
c
,
const
Row
&
r
,
bool
icase
)
{
return
r
[
tag
].
compare
(
value
,
icase
)
==
0
;
},
s
.
str
()));
}
}
else
else
return
Condition
(
new
detail
::
KeyIsEmptyConditionImpl
(
key
.
mItemTag
));
return
Condition
(
new
detail
::
KeyIsEmptyConditionImpl
(
key
.
mItemTag
));
...
@@ -1148,169 +1221,181 @@ inline Condition operator==(const Key& key, const char *value)
...
@@ -1148,169 +1221,181 @@ inline Condition operator==(const Key& key, const char *value)
// { return r[tag].template compare<(v, icase) == 0; }));
// { return r[tag].template compare<(v, icase) == 0; }));
// }
// }
inline
Condition
operator
==
(
const
Key
&
key
,
const
Empty
&
)
inline
Condition
operator
==
(
const
Key
&
key
,
const
Empty
&
)
{
{
return
Condition
(
new
detail
::
KeyIsEmptyConditionImpl
(
key
.
mItemTag
));
return
Condition
(
new
detail
::
KeyIsEmptyConditionImpl
(
key
.
mItemTag
));
}
}
template
<
typename
T
>
template
<
typename
T
>
Condition
operator
!=
(
const
Key
&
key
,
const
T
&
v
)
Condition
operator
!=
(
const
Key
&
key
,
const
T
&
v
)
{
{
return
Condition
(
new
detail
::
NotConditionImpl
(
operator
==
(
key
,
v
)));
return
Condition
(
new
detail
::
NotConditionImpl
(
operator
==
(
key
,
v
)));
}
}
inline
Condition
operator
!=
(
const
Key
&
key
,
const
char
*
v
)
inline
Condition
operator
!=
(
const
Key
&
key
,
const
char
*
v
)
{
{
std
::
string
value
(
v
?
v
:
""
);
std
::
string
value
(
v
?
v
:
""
);
return
Condition
(
new
detail
::
NotConditionImpl
(
operator
==
(
key
,
value
)));
return
Condition
(
new
detail
::
NotConditionImpl
(
operator
==
(
key
,
value
)));
}
}
template
<
typename
T
>
template
<
typename
T
>
Condition
operator
>
(
const
Key
&
key
,
const
T
&
v
)
Condition
operator
>
(
const
Key
&
key
,
const
T
&
v
)
{
{
std
::
ostringstream
s
;
std
::
ostringstream
s
;
s
<<
" > "
<<
v
;
s
<<
" > "
<<
v
;
return
Condition
(
new
detail
::
KeyCompareConditionImpl
(
key
.
mItemTag
,
[
tag
=
key
.
mItemTag
,
v
](
const
Category
&
c
,
const
Row
&
r
,
bool
icase
)
return
Condition
(
new
detail
::
KeyCompareConditionImpl
(
{
return
r
[
tag
].
template
compare
<
T
>
(
v
,
icase
)
>
0
;
},
s
.
str
()));
key
.
mItemTag
,
[
tag
=
key
.
mItemTag
,
v
](
const
Category
&
c
,
const
Row
&
r
,
bool
icase
)
{
return
r
[
tag
].
template
compare
<
T
>
(
v
,
icase
)
>
0
;
},
s
.
str
()));
}
}
template
<
typename
T
>
template
<
typename
T
>
Condition
operator
>=
(
const
Key
&
key
,
const
T
&
v
)
Condition
operator
>=
(
const
Key
&
key
,
const
T
&
v
)
{
{
std
::
ostringstream
s
;
std
::
ostringstream
s
;
s
<<
" >= "
<<
v
;
s
<<
" >= "
<<
v
;
return
Condition
(
new
detail
::
KeyCompareConditionImpl
(
key
.
mItemTag
,
[
tag
=
key
.
mItemTag
,
v
](
const
Category
&
c
,
const
Row
&
r
,
bool
icase
)
return
Condition
(
new
detail
::
KeyCompareConditionImpl
(
{
return
r
[
tag
].
template
compare
<
T
>
(
v
,
icase
)
>=
0
;
},
s
.
str
()));
key
.
mItemTag
,
[
tag
=
key
.
mItemTag
,
v
](
const
Category
&
c
,
const
Row
&
r
,
bool
icase
)
{
return
r
[
tag
].
template
compare
<
T
>
(
v
,
icase
)
>=
0
;
},
s
.
str
()));
}
}
template
<
typename
T
>
template
<
typename
T
>
Condition
operator
<
(
const
Key
&
key
,
const
T
&
v
)
Condition
operator
<
(
const
Key
&
key
,
const
T
&
v
)
{
{
std
::
ostringstream
s
;
std
::
ostringstream
s
;
s
<<
" < "
<<
v
;
s
<<
" < "
<<
v
;
return
Condition
(
new
detail
::
KeyCompareConditionImpl
(
key
.
mItemTag
,
[
tag
=
key
.
mItemTag
,
v
](
const
Category
&
c
,
const
Row
&
r
,
bool
icase
)
return
Condition
(
new
detail
::
KeyCompareConditionImpl
(
{
return
r
[
tag
].
template
compare
<
T
>
(
v
,
icase
)
<
0
;
},
s
.
str
()));
key
.
mItemTag
,
[
tag
=
key
.
mItemTag
,
v
](
const
Category
&
c
,
const
Row
&
r
,
bool
icase
)
{
return
r
[
tag
].
template
compare
<
T
>
(
v
,
icase
)
<
0
;
},
s
.
str
()));
}
}
template
<
typename
T
>
template
<
typename
T
>
Condition
operator
<=
(
const
Key
&
key
,
const
T
&
v
)
Condition
operator
<=
(
const
Key
&
key
,
const
T
&
v
)
{
{
std
::
ostringstream
s
;
std
::
ostringstream
s
;
s
<<
" <= "
<<
v
;
s
<<
" <= "
<<
v
;
return
Condition
(
new
detail
::
KeyCompareConditionImpl
(
key
.
mItemTag
,
[
tag
=
key
.
mItemTag
,
v
](
const
Category
&
c
,
const
Row
&
r
,
bool
icase
)
return
Condition
(
new
detail
::
KeyCompareConditionImpl
(
{
return
r
[
tag
].
template
compare
<
T
>
(
v
,
icase
)
<=
0
;
},
s
.
str
()));
key
.
mItemTag
,
[
tag
=
key
.
mItemTag
,
v
](
const
Category
&
c
,
const
Row
&
r
,
bool
icase
)
{
return
r
[
tag
].
template
compare
<
T
>
(
v
,
icase
)
<=
0
;
},
s
.
str
()));
}
}
template
<>
template
<>
inline
inline
Condition
operator
==
(
const
Key
&
key
,
const
std
::
regex
&
rx
)
Condition
operator
==
(
const
Key
&
key
,
const
std
::
regex
&
rx
)
{
{
return
Condition
(
new
detail
::
KeyMatchesConditionImpl
(
key
.
mItemTag
,
rx
));
return
Condition
(
new
detail
::
KeyMatchesConditionImpl
(
key
.
mItemTag
,
rx
));
}
}
template
<>
template
<>
inline
inline
Condition
operator
==
(
const
Key
&
key
,
const
Empty
&
)
Condition
operator
==
(
const
Key
&
key
,
const
Empty
&
)
{
{
return
Condition
(
new
detail
::
KeyIsEmptyConditionImpl
(
key
.
mItemTag
));
return
Condition
(
new
detail
::
KeyIsEmptyConditionImpl
(
key
.
mItemTag
));
}
}
struct
any
struct
any
{
{
template
<
typename
T
>
template
<
typename
T
>
Condition
operator
==
(
const
T
&
v
)
const
Condition
operator
==
(
const
T
&
v
)
const
{
{
return
Condition
(
new
detail
::
AnyIsConditionImpl
<
T
>
(
v
));
return
Condition
(
new
detail
::
AnyIsConditionImpl
<
T
>
(
v
));
}
}
};
};
template
<>
template
<>
inline
inline
Condition
any
::
operator
==
(
const
std
::
regex
&
rx
)
const
Condition
any
::
operator
==
(
const
std
::
regex
&
rx
)
const
{
{
return
Condition
(
new
detail
::
AnyMatchesConditionImpl
(
rx
));
return
Condition
(
new
detail
::
AnyMatchesConditionImpl
(
rx
));
}
}
inline
Condition
All
()
inline
Condition
All
()
{
{
return
Condition
(
new
detail
::
AllConditionImpl
());
return
Condition
(
new
detail
::
AllConditionImpl
());
}
}
inline
Condition
Not
(
Condition
&&
cond
)
inline
Condition
Not
(
Condition
&&
cond
)
{
{
return
Condition
(
new
detail
::
NotConditionImpl
(
std
::
move
(
cond
)));
return
Condition
(
new
detail
::
NotConditionImpl
(
std
::
move
(
cond
)));
}
}
namespace
literals
namespace
literals
{
{
inline
Key
operator
""
_key
(
const
char
*
text
,
size_t
length
)
inline
Key
operator
""
_key
(
const
char
*
text
,
size_t
length
)
{
{
return
Key
(
std
::
string
(
text
,
length
));
return
Key
(
std
::
string
(
text
,
length
));
}
}
inline
constexpr
Empty
Null
=
Empty
();
}
inline
constexpr
Empty
Null
=
Empty
();
}
// namespace literals
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// iterators
// iterators
template
<
typename
RowType
,
typename
...
Ts
>
template
<
typename
RowType
,
typename
...
Ts
>
class
iterator_impl
class
iterator_impl
{
{
public
:
public
:
template
<
typename
,
typename
...
>
friend
class
iterator_impl
;
template
<
typename
,
typename
...
>
friend
class
iterator_impl
;
static
constexpr
size_t
N
=
sizeof
...(
Ts
);
static
constexpr
size_t
N
=
sizeof
...(
Ts
);
using
iterator_category
=
std
::
forward_iterator_tag
;
using
iterator_category
=
std
::
forward_iterator_tag
;
using
value_type
=
std
::
conditional_t
<
N
==
0
,
RowType
,
std
::
tuple
<
Ts
...
>>
;
using
value_type
=
std
::
conditional_t
<
N
==
0
,
RowType
,
std
::
tuple
<
Ts
...
>>
;
using
difference_type
=
std
::
ptrdiff_t
;
using
difference_type
=
std
::
ptrdiff_t
;
using
pointer
=
value_type
*
;
using
pointer
=
value_type
*
;
using
reference
=
value_type
&
;
using
reference
=
value_type
&
;
friend
class
Category
;
friend
class
Category
;
// default constructor, equal to end()
// default constructor, equal to end()
iterator_impl
()
{}
iterator_impl
()
{}
iterator_impl
(
const
iterator_impl
&
rhs
)
iterator_impl
(
const
iterator_impl
&
rhs
)
:
mCurrent
(
rhs
.
mCurrent
),
mValue
(
rhs
.
mValue
),
mCix
(
rhs
.
mCix
)
:
mCurrent
(
rhs
.
mCurrent
)
,
mValue
(
rhs
.
mValue
)
,
mCix
(
rhs
.
mCix
)
{
{
}
}
iterator_impl
(
ItemRow
*
data
)
iterator_impl
(
ItemRow
*
data
)
:
mCurrent
(
data
)
:
mCurrent
(
data
)
{
{
static_assert
(
N
==
0
,
"Only valid if this is a row iterator, not a row<xxx> iterator"
);
static_assert
(
N
==
0
,
"Only valid if this is a row iterator, not a row<xxx> iterator"
);
}
}
iterator_impl
(
ItemRow
*
data
,
const
std
::
array
<
size_t
,
N
>&
cix
)
iterator_impl
(
ItemRow
*
data
,
const
std
::
array
<
size_t
,
N
>
&
cix
)
:
mCurrent
(
data
),
mCix
(
cix
)
{}
:
mCurrent
(
data
)
,
mCix
(
cix
)
{
}
template
<
typename
IRowType
>
template
<
typename
IRowType
>
iterator_impl
(
iterator_impl
<
IRowType
,
Ts
...
>&
rhs
)
iterator_impl
(
iterator_impl
<
IRowType
,
Ts
...
>
&
rhs
)
:
mCurrent
(
rhs
.
mCurrent
),
mCix
(
rhs
.
mCix
)
:
mCurrent
(
rhs
.
mCurrent
)
,
mCix
(
rhs
.
mCix
)
{
{
if
constexpr
(
N
>
0
)
if
constexpr
(
N
>
0
)
mValue
=
get
(
mCurrent
,
std
::
make_index_sequence
<
N
>
());
mValue
=
get
(
mCurrent
,
std
::
make_index_sequence
<
N
>
());
}
}
template
<
typename
IRowType
>
template
<
typename
IRowType
>
iterator_impl
(
const
iterator_impl
<
IRowType
>&
rhs
,
const
std
::
array
<
size_t
,
N
>&
cix
)
iterator_impl
(
const
iterator_impl
<
IRowType
>
&
rhs
,
const
std
::
array
<
size_t
,
N
>
&
cix
)
:
mCurrent
(
rhs
.
mCurrent
),
mCix
(
cix
)
:
mCurrent
(
rhs
.
mCurrent
)
,
mCix
(
cix
)
{
{
if
constexpr
(
N
>
0
)
if
constexpr
(
N
>
0
)
mValue
=
get
(
mCurrent
,
std
::
make_index_sequence
<
N
>
());
mValue
=
get
(
mCurrent
,
std
::
make_index_sequence
<
N
>
());
}
}
iterator_impl
&
operator
=
(
const
iterator_impl
&
i
)
iterator_impl
&
operator
=
(
const
iterator_impl
&
i
)
{
{
mCurrent
=
i
.
mCurrent
;
mCurrent
=
i
.
mCurrent
;
if
constexpr
(
N
!=
0
)
if
constexpr
(
N
!=
0
)
...
@@ -1343,8 +1428,8 @@ class iterator_impl
...
@@ -1343,8 +1428,8 @@ class iterator_impl
{
{
return
mCurrent
;
return
mCurrent
;
}
}
iterator_impl
&
operator
++
()
iterator_impl
&
operator
++
()
{
{
mCurrent
.
next
();
mCurrent
.
next
();
...
@@ -1359,26 +1444,25 @@ class iterator_impl
...
@@ -1359,26 +1444,25 @@ class iterator_impl
iterator_impl
result
(
*
this
);
iterator_impl
result
(
*
this
);
this
->
operator
++
();
this
->
operator
++
();
return
result
;
return
result
;
}
}
bool
operator
==
(
const
iterator_impl
&
rhs
)
const
{
return
mCurrent
==
rhs
.
mCurrent
;
}
bool
operator
==
(
const
iterator_impl
&
rhs
)
const
{
return
mCurrent
==
rhs
.
mCurrent
;
}
bool
operator
!=
(
const
iterator_impl
&
rhs
)
const
{
return
mCurrent
!=
rhs
.
mCurrent
;
}
bool
operator
!=
(
const
iterator_impl
&
rhs
)
const
{
return
mCurrent
!=
rhs
.
mCurrent
;
}
template
<
typename
IRowType
,
typename
...
ITs
>
template
<
typename
IRowType
,
typename
...
ITs
>
bool
operator
==
(
const
iterator_impl
<
IRowType
,
ITs
...
>
&
rhs
)
const
bool
operator
==
(
const
iterator_impl
<
IRowType
,
ITs
...
>
&
rhs
)
const
{
{
return
mCurrent
==
rhs
.
mCurrent
;
return
mCurrent
==
rhs
.
mCurrent
;
}
}
template
<
typename
IRowType
,
typename
...
ITs
>
template
<
typename
IRowType
,
typename
...
ITs
>
bool
operator
!=
(
const
iterator_impl
<
IRowType
,
ITs
...
>
&
rhs
)
const
bool
operator
!=
(
const
iterator_impl
<
IRowType
,
ITs
...
>
&
rhs
)
const
{
{
return
mCurrent
!=
rhs
.
mCurrent
;
return
mCurrent
!=
rhs
.
mCurrent
;
}
}
private
:
private
:
template
<
std
::
size_t
...
Is
>
template
<
std
::
size_t
...
Is
>
std
::
tuple
<
Ts
...
>
get
(
Row
row
,
std
::
index_sequence
<
Is
...
>
)
const
std
::
tuple
<
Ts
...
>
get
(
Row
row
,
std
::
index_sequence
<
Is
...
>
)
const
{
{
if
(
row
)
if
(
row
)
...
@@ -1394,7 +1478,7 @@ class iterator_impl
...
@@ -1394,7 +1478,7 @@ class iterator_impl
// --------------------------------------------------------------------
// --------------------------------------------------------------------
// iterator proxy
// iterator proxy
template
<
typename
RowType
,
typename
...
Ts
>
template
<
typename
RowType
,
typename
...
Ts
>
class
iterator_proxy
class
iterator_proxy
{
{
public
:
public
:
...
@@ -1403,30 +1487,30 @@ class iterator_proxy
...
@@ -1403,30 +1487,30 @@ class iterator_proxy
using
iterator
=
iterator_impl
<
RowType
,
Ts
...
>
;
using
iterator
=
iterator_impl
<
RowType
,
Ts
...
>
;
using
row_iterator
=
iterator_impl
<
RowType
>
;
using
row_iterator
=
iterator_impl
<
RowType
>
;
iterator_proxy
(
Category
&
cat
,
row_iterator
pos
,
char
const
*
const
columns
[
N
]);
iterator_proxy
(
Category
&
cat
,
row_iterator
pos
,
char
const
*
const
columns
[
N
]);
iterator_proxy
(
Category
&
cat
,
row_iterator
pos
,
std
::
initializer_list
<
char
const
*>
columns
);
iterator_proxy
(
Category
&
cat
,
row_iterator
pos
,
std
::
initializer_list
<
char
const
*>
columns
);
iterator_proxy
(
iterator_proxy
&&
p
);
iterator_proxy
(
iterator_proxy
&&
p
);
iterator_proxy
&
operator
=
(
iterator_proxy
&&
p
);
iterator_proxy
&
operator
=
(
iterator_proxy
&&
p
);
iterator_proxy
(
const
iterator_proxy
&
)
=
delete
;
iterator_proxy
(
const
iterator_proxy
&
)
=
delete
;
iterator_proxy
&
operator
=
(
const
iterator_proxy
&
)
=
delete
;
iterator_proxy
&
operator
=
(
const
iterator_proxy
&
)
=
delete
;
iterator
begin
()
const
{
return
iterator
(
mCBegin
,
mCix
);
}
iterator
begin
()
const
{
return
iterator
(
mCBegin
,
mCix
);
}
iterator
end
()
const
{
return
iterator
(
mCEnd
,
mCix
);
}
iterator
end
()
const
{
return
iterator
(
mCEnd
,
mCix
);
}
bool
empty
()
const
{
return
mCBegin
==
mCEnd
;
}
bool
empty
()
const
{
return
mCBegin
==
mCEnd
;
}
explicit
operator
bool
()
const
{
return
not
empty
();
}
explicit
operator
bool
()
const
{
return
not
empty
();
}
size_t
size
()
const
{
return
std
::
distance
(
begin
(),
end
());
}
size_t
size
()
const
{
return
std
::
distance
(
begin
(),
end
());
}
RowType
front
()
{
return
*
begin
();
}
RowType
front
()
{
return
*
begin
();
}
RowType
back
()
{
return
*
(
std
::
prev
(
end
()));
}
RowType
back
()
{
return
*
(
std
::
prev
(
end
()));
}
Category
&
category
()
const
{
return
*
mCat
;
}
Category
&
category
()
const
{
return
*
mCat
;
}
void
swap
(
iterator_proxy
&
rhs
)
void
swap
(
iterator_proxy
&
rhs
)
{
{
std
::
swap
(
mCat
,
rhs
.
mCat
);
std
::
swap
(
mCat
,
rhs
.
mCat
);
std
::
swap
(
mCBegin
,
rhs
.
mCBegin
);
std
::
swap
(
mCBegin
,
rhs
.
mCBegin
);
...
@@ -1435,15 +1519,15 @@ class iterator_proxy
...
@@ -1435,15 +1519,15 @@ class iterator_proxy
}
}
private
:
private
:
Category
*
mCat
;
Category
*
mCat
;
row_iterator
mCBegin
,
mCEnd
;
row_iterator
mCBegin
,
mCEnd
;
std
::
array
<
size_t
,
N
>
mCix
;
std
::
array
<
size_t
,
N
>
mCix
;
};
};
// --------------------------------------------------------------------
// --------------------------------------------------------------------
// conditional iterator proxy
// conditional iterator proxy
template
<
typename
RowType
,
typename
...
Ts
>
template
<
typename
RowType
,
typename
...
Ts
>
class
conditional_iterator_proxy
class
conditional_iterator_proxy
{
{
public
:
public
:
...
@@ -1461,12 +1545,12 @@ class conditional_iterator_proxy
...
@@ -1461,12 +1545,12 @@ class conditional_iterator_proxy
using
iterator_category
=
std
::
forward_iterator_tag
;
using
iterator_category
=
std
::
forward_iterator_tag
;
using
value_type
=
conditional_iterator_proxy
::
value_type
;
using
value_type
=
conditional_iterator_proxy
::
value_type
;
using
difference_type
=
std
::
ptrdiff_t
;
using
difference_type
=
std
::
ptrdiff_t
;
using
pointer
=
value_type
*
;
using
pointer
=
value_type
*
;
using
reference
=
value_type
&
;
using
reference
=
value_type
&
;
conditional_iterator_impl
(
Category
&
cat
,
row_iterator
pos
,
const
Condition
&
cond
,
const
std
::
array
<
size_t
,
N
>&
cix
);
conditional_iterator_impl
(
Category
&
cat
,
row_iterator
pos
,
const
Condition
&
cond
,
const
std
::
array
<
size_t
,
N
>
&
cix
);
conditional_iterator_impl
(
const
conditional_iterator_impl
&
i
)
=
default
;
conditional_iterator_impl
(
const
conditional_iterator_impl
&
i
)
=
default
;
conditional_iterator_impl
&
operator
=
(
const
conditional_iterator_impl
&
i
)
=
default
;
conditional_iterator_impl
&
operator
=
(
const
conditional_iterator_impl
&
i
)
=
default
;
virtual
~
conditional_iterator_impl
()
=
default
;
virtual
~
conditional_iterator_impl
()
=
default
;
...
@@ -1479,14 +1563,14 @@ class conditional_iterator_proxy
...
@@ -1479,14 +1563,14 @@ class conditional_iterator_proxy
{
{
return
&*
mBegin
;
return
&*
mBegin
;
}
}
conditional_iterator_impl
&
operator
++
()
conditional_iterator_impl
&
operator
++
()
{
{
while
(
mBegin
!=
mEnd
)
while
(
mBegin
!=
mEnd
)
{
{
if
(
++
mBegin
==
mEnd
)
if
(
++
mBegin
==
mEnd
)
break
;
break
;
if
((
*
mCondition
)(
*
mCat
,
mBegin
.
row
()))
if
((
*
mCondition
)(
*
mCat
,
mBegin
.
row
()))
break
;
break
;
}
}
...
@@ -1499,58 +1583,57 @@ class conditional_iterator_proxy
...
@@ -1499,58 +1583,57 @@ class conditional_iterator_proxy
conditional_iterator_impl
result
(
*
this
);
conditional_iterator_impl
result
(
*
this
);
this
->
operator
++
();
this
->
operator
++
();
return
result
;
return
result
;
}
}
bool
operator
==
(
const
conditional_iterator_impl
&
rhs
)
const
{
return
mBegin
==
rhs
.
mBegin
;
}
bool
operator
==
(
const
conditional_iterator_impl
&
rhs
)
const
{
return
mBegin
==
rhs
.
mBegin
;
}
bool
operator
!=
(
const
conditional_iterator_impl
&
rhs
)
const
{
return
mBegin
!=
rhs
.
mBegin
;
}
bool
operator
!=
(
const
conditional_iterator_impl
&
rhs
)
const
{
return
mBegin
!=
rhs
.
mBegin
;
}
template
<
typename
IRowType
,
typename
...
ITs
>
template
<
typename
IRowType
,
typename
...
ITs
>
bool
operator
==
(
const
iterator_impl
<
IRowType
,
ITs
...
>
&
rhs
)
const
{
return
mBegin
==
rhs
;
}
bool
operator
==
(
const
iterator_impl
<
IRowType
,
ITs
...
>
&
rhs
)
const
{
return
mBegin
==
rhs
;
}
template
<
typename
IRowType
,
typename
...
ITs
>
template
<
typename
IRowType
,
typename
...
ITs
>
bool
operator
!=
(
const
iterator_impl
<
IRowType
,
ITs
...
>
&
rhs
)
const
{
return
mBegin
!=
rhs
;
}
bool
operator
!=
(
const
iterator_impl
<
IRowType
,
ITs
...
>
&
rhs
)
const
{
return
mBegin
!=
rhs
;
}
private
:
private
:
Category
*
mCat
;
Category
*
mCat
;
base_iterator
mBegin
,
mEnd
;
base_iterator
mBegin
,
mEnd
;
const
Condition
*
mCondition
;
const
Condition
*
mCondition
;
};
};
using
iterator
=
conditional_iterator_impl
;
using
iterator
=
conditional_iterator_impl
;
using
reference
=
typename
iterator
::
reference
;
using
reference
=
typename
iterator
::
reference
;
conditional_iterator_proxy
(
Category
&
cat
,
row_iterator
pos
,
Condition
&&
cond
);
conditional_iterator_proxy
(
Category
&
cat
,
row_iterator
pos
,
Condition
&&
cond
);
template
<
std
::
size_t
TN
=
N
,
std
::
enable_if_t
<
TN
!=
0
,
bool
>
=
true
>
template
<
std
::
size_t
TN
=
N
,
std
::
enable_if_t
<
TN
!=
0
,
bool
>
=
true
>
conditional_iterator_proxy
(
Category
&
cat
,
row_iterator
pos
,
Condition
&&
cond
,
char
const
*
const
columns
[
N
]);
conditional_iterator_proxy
(
Category
&
cat
,
row_iterator
pos
,
Condition
&&
cond
,
char
const
*
const
columns
[
N
]);
conditional_iterator_proxy
(
conditional_iterator_proxy
&&
p
);
conditional_iterator_proxy
(
conditional_iterator_proxy
&&
p
);
conditional_iterator_proxy
&
operator
=
(
conditional_iterator_proxy
&&
p
);
conditional_iterator_proxy
&
operator
=
(
conditional_iterator_proxy
&&
p
);
conditional_iterator_proxy
(
const
conditional_iterator_proxy
&
)
=
delete
;
conditional_iterator_proxy
(
const
conditional_iterator_proxy
&
)
=
delete
;
conditional_iterator_proxy
&
operator
=
(
const
conditional_iterator_proxy
&
)
=
delete
;
conditional_iterator_proxy
&
operator
=
(
const
conditional_iterator_proxy
&
)
=
delete
;
iterator
begin
()
const
;
iterator
begin
()
const
;
iterator
end
()
const
;
iterator
end
()
const
;
bool
empty
()
const
;
bool
empty
()
const
;
explicit
operator
bool
()
const
{
return
not
empty
();
}
explicit
operator
bool
()
const
{
return
not
empty
();
}
size_t
size
()
const
{
return
std
::
distance
(
begin
(),
end
());
}
size_t
size
()
const
{
return
std
::
distance
(
begin
(),
end
());
}
RowType
front
()
{
return
*
begin
();
}
RowType
front
()
{
return
*
begin
();
}
Category
&
category
()
const
{
return
*
mCat
;
}
Category
&
category
()
const
{
return
*
mCat
;
}
void
swap
(
conditional_iterator_proxy
&
rhs
);
void
swap
(
conditional_iterator_proxy
&
rhs
);
private
:
private
:
Category
*
mCat
;
Category
*
mCat
;
Condition
mCondition
;
Condition
mCondition
;
row_iterator
mCBegin
,
mCEnd
;
row_iterator
mCBegin
,
mCEnd
;
std
::
array
<
size_t
,
N
>
mCix
;
std
::
array
<
size_t
,
N
>
mCix
;
};
};
// --------------------------------------------------------------------
// --------------------------------------------------------------------
...
@@ -1723,7 +1806,7 @@ class RowSet
...
@@ -1723,7 +1806,7 @@ class RowSet
};
};
// --------------------------------------------------------------------
// --------------------------------------------------------------------
// class Category acts as an STL container for Row objects
// class Category acts as an STL container for Row objects
class
Category
class
Category
{
{
...
@@ -1732,16 +1815,16 @@ class Category
...
@@ -1732,16 +1815,16 @@ class Category
friend
class
Row
;
friend
class
Row
;
friend
class
detail
::
ItemReference
;
friend
class
detail
::
ItemReference
;
Category
(
Datablock
&
db
,
const
std
::
string
&
name
,
Validator
*
Validator
);
Category
(
Datablock
&
db
,
const
std
::
string
&
name
,
Validator
*
Validator
);
Category
(
const
Category
&
)
=
delete
;
Category
(
const
Category
&
)
=
delete
;
Category
&
operator
=
(
const
Category
&
)
=
delete
;
Category
&
operator
=
(
const
Category
&
)
=
delete
;
~
Category
();
~
Category
();
const
std
::
string
name
()
const
{
return
mName
;
}
const
std
::
string
name
()
const
{
return
mName
;
}
using
iterator
=
iterator_impl
<
Row
>
;
using
iterator
=
iterator_impl
<
Row
>
;
using
const_iterator
=
iterator_impl
<
const
Row
>
;
using
const_iterator
=
iterator_impl
<
const
Row
>
;
iterator
begin
();
iterator
begin
();
iterator
end
();
iterator
end
();
...
@@ -1753,115 +1836,119 @@ class Category
...
@@ -1753,115 +1836,119 @@ class Category
bool
empty
()
const
;
bool
empty
()
const
;
size_t
size
()
const
;
size_t
size
()
const
;
void
clear
();
void
clear
();
Row
front
()
{
return
Row
(
mHead
);
}
Row
back
()
{
return
Row
(
mTail
);
}
Row
operator
[](
Condition
&&
cond
);
template
<
typename
...
Ts
,
size_t
N
>
Row
front
()
{
return
Row
(
mHead
);
}
iterator_proxy
<
Row
,
Ts
...
>
rows
(
char
const
*
const
(
&
columns
)[
N
])
Row
back
()
{
return
Row
(
mTail
);
}
Row
operator
[](
Condition
&&
cond
);
template
<
typename
...
Ts
,
size_t
N
>
iterator_proxy
<
Row
,
Ts
...
>
rows
(
char
const
*
const
(
&
columns
)[
N
])
{
{
static_assert
(
sizeof
...(
Ts
)
==
N
,
"The number of column titles should be equal to the number of types to return"
);
static_assert
(
sizeof
...(
Ts
)
==
N
,
"The number of column titles should be equal to the number of types to return"
);
return
iterator_proxy
<
Row
,
Ts
...
>
(
*
this
,
begin
(),
columns
);
return
iterator_proxy
<
Row
,
Ts
...
>
(
*
this
,
begin
(),
columns
);
}
}
template
<
typename
...
Ts
,
typename
...
Ns
>
template
<
typename
...
Ts
,
typename
...
Ns
>
iterator_proxy
<
Row
,
Ts
...
>
rows
(
Ns
...
names
)
iterator_proxy
<
Row
,
Ts
...
>
rows
(
Ns
...
names
)
{
{
static_assert
(
sizeof
...(
Ts
)
==
sizeof
...(
Ns
),
"The number of column titles should be equal to the number of types to return"
);
static_assert
(
sizeof
...(
Ts
)
==
sizeof
...(
Ns
),
"The number of column titles should be equal to the number of types to return"
);
return
iterator_proxy
<
Row
,
Ts
...
>
(
*
this
,
begin
(),
{
names
...
});
return
iterator_proxy
<
Row
,
Ts
...
>
(
*
this
,
begin
(),
{
names
...
});
}
}
conditional_iterator_proxy
<
Row
>
find
(
Condition
&&
cond
)
conditional_iterator_proxy
<
Row
>
find
(
Condition
&&
cond
)
{
{
return
find
(
cbegin
(),
std
::
forward
<
Condition
>
(
cond
));
return
find
(
cbegin
(),
std
::
forward
<
Condition
>
(
cond
));
}
}
conditional_iterator_proxy
<
Row
>
find
(
const_iterator
pos
,
Condition
&&
cond
)
conditional_iterator_proxy
<
Row
>
find
(
const_iterator
pos
,
Condition
&&
cond
)
{
{
return
{
*
this
,
pos
,
std
::
forward
<
Condition
>
(
cond
)
};
return
{
*
this
,
pos
,
std
::
forward
<
Condition
>
(
cond
)
};
}
}
template
<
typename
...
Ts
,
size_t
N
>
template
<
typename
...
Ts
,
size_t
N
>
conditional_iterator_proxy
<
Row
,
Ts
...
>
find
(
Condition
&&
cond
,
char
const
*
const
(
&
columns
)[
N
])
conditional_iterator_proxy
<
Row
,
Ts
...
>
find
(
Condition
&&
cond
,
char
const
*
const
(
&
columns
)[
N
])
{
{
static_assert
(
sizeof
...(
Ts
)
==
N
,
"The number of column titles should be equal to the number of types to return"
);
static_assert
(
sizeof
...(
Ts
)
==
N
,
"The number of column titles should be equal to the number of types to return"
);
return
find
<
Ts
...
>
(
cbegin
(),
std
::
forward
<
Condition
>
(
cond
),
std
::
forward
<
char
const
*
const
[
N
]
>
(
columns
));
return
find
<
Ts
...
>
(
cbegin
(),
std
::
forward
<
Condition
>
(
cond
),
std
::
forward
<
char
const
*
const
[
N
]
>
(
columns
));
}
}
template
<
typename
...
Ts
,
size_t
N
>
template
<
typename
...
Ts
,
size_t
N
>
conditional_iterator_proxy
<
Row
,
Ts
...
>
find
(
const_iterator
pos
,
Condition
&&
cond
,
char
const
*
const
(
&
columns
)[
N
])
conditional_iterator_proxy
<
Row
,
Ts
...
>
find
(
const_iterator
pos
,
Condition
&&
cond
,
char
const
*
const
(
&
columns
)[
N
])
{
{
static_assert
(
sizeof
...(
Ts
)
==
N
,
"The number of column titles should be equal to the number of types to return"
);
static_assert
(
sizeof
...(
Ts
)
==
N
,
"The number of column titles should be equal to the number of types to return"
);
return
{
*
this
,
pos
,
std
::
forward
<
Condition
>
(
cond
),
columns
};
return
{
*
this
,
pos
,
std
::
forward
<
Condition
>
(
cond
),
columns
};
}
}
// --------------------------------------------------------------------
// --------------------------------------------------------------------
// if you only expect a single row
// if you only expect a single row
Row
find1
(
Condition
&&
cond
)
Row
find1
(
Condition
&&
cond
)
{
{
return
find1
(
cbegin
(),
std
::
forward
<
Condition
>
(
cond
));
return
find1
(
cbegin
(),
std
::
forward
<
Condition
>
(
cond
));
}
}
Row
find1
(
const_iterator
pos
,
Condition
&&
cond
)
Row
find1
(
const_iterator
pos
,
Condition
&&
cond
)
{
{
auto
h
=
find
(
pos
,
std
::
forward
<
Condition
>
(
cond
));
auto
h
=
find
(
pos
,
std
::
forward
<
Condition
>
(
cond
));
if
(
h
.
empty
())
if
(
h
.
empty
())
throw
std
::
runtime_error
(
"No hits found"
);
throw
std
::
runtime_error
(
"No hits found"
);
if
(
h
.
size
()
!=
1
)
if
(
h
.
size
()
!=
1
)
throw
std
::
runtime_error
(
"Hit not unique"
);
throw
std
::
runtime_error
(
"Hit not unique"
);
return
*
h
.
begin
();
return
*
h
.
begin
();
}
}
template
<
typename
...
Ts
,
size_t
N
>
template
<
typename
...
Ts
,
size_t
N
>
std
::
tuple
<
Ts
...
>
find1
(
Condition
&&
cond
,
char
const
*
const
(
&
columns
)[
N
])
std
::
tuple
<
Ts
...
>
find1
(
Condition
&&
cond
,
char
const
*
const
(
&
columns
)[
N
])
{
{
static_assert
(
sizeof
...(
Ts
)
==
N
,
"The number of column titles should be equal to the number of types to return"
);
static_assert
(
sizeof
...(
Ts
)
==
N
,
"The number of column titles should be equal to the number of types to return"
);
return
find1
<
Ts
...
>
(
cbegin
(),
std
::
forward
<
Condition
>
(
cond
),
std
::
forward
<
char
const
*
const
[
N
]
>
(
columns
));
return
find1
<
Ts
...
>
(
cbegin
(),
std
::
forward
<
Condition
>
(
cond
),
std
::
forward
<
char
const
*
const
[
N
]
>
(
columns
));
}
}
template
<
typename
...
Ts
,
size_t
N
>
template
<
typename
...
Ts
,
size_t
N
>
std
::
tuple
<
Ts
...
>
find1
(
const_iterator
pos
,
Condition
&&
cond
,
char
const
*
const
(
&
columns
)[
N
])
std
::
tuple
<
Ts
...
>
find1
(
const_iterator
pos
,
Condition
&&
cond
,
char
const
*
const
(
&
columns
)[
N
])
{
{
static_assert
(
sizeof
...(
Ts
)
==
N
,
"The number of column titles should be equal to the number of types to return"
);
static_assert
(
sizeof
...(
Ts
)
==
N
,
"The number of column titles should be equal to the number of types to return"
);
auto
h
=
find
<
Ts
...
>
(
pos
,
std
::
forward
<
Condition
>
(
cond
),
std
::
forward
<
char
const
*
const
[
N
]
>
(
columns
));
auto
h
=
find
<
Ts
...
>
(
pos
,
std
::
forward
<
Condition
>
(
cond
),
std
::
forward
<
char
const
*
const
[
N
]
>
(
columns
));
if
(
h
.
empty
())
if
(
h
.
empty
())
throw
std
::
runtime_error
(
"No hits found"
);
throw
std
::
runtime_error
(
"No hits found"
);
if
(
h
.
size
()
!=
1
)
if
(
h
.
size
()
!=
1
)
throw
std
::
runtime_error
(
"Hit not unique"
);
throw
std
::
runtime_error
(
"Hit not unique"
);
return
*
h
.
begin
();
return
*
h
.
begin
();
}
}
bool
exists
(
Condition
&&
cond
)
const
;
bool
exists
(
Condition
&&
cond
)
const
;
RowSet
orderBy
(
const
std
::
string
&
Item
)
RowSet
orderBy
(
const
std
::
string
&
Item
)
{
return
orderBy
({
Item
});
}
{
return
orderBy
({
Item
});
}
RowSet
orderBy
(
std
::
initializer_list
<
std
::
string
>
Items
);
RowSet
orderBy
(
std
::
initializer_list
<
std
::
string
>
Items
);
std
::
tuple
<
Row
,
bool
>
emplace
(
Item
value
)
{
return
emplace
({
value
});
}
std
::
tuple
<
Row
,
bool
>
emplace
(
std
::
initializer_list
<
Item
>
values
)
std
::
tuple
<
Row
,
bool
>
emplace
(
Item
value
)
{
return
emplace
({
value
});
}
{
return
emplace
(
values
.
begin
(),
values
.
end
());
}
std
::
tuple
<
Row
,
bool
>
emplace
(
Row
r
);
std
::
tuple
<
Row
,
bool
>
emplace
(
std
::
initializer_list
<
Item
>
values
)
{
template
<
class
Iter
>
return
emplace
(
values
.
begin
(),
values
.
end
());
std
::
tuple
<
Row
,
bool
>
emplace
(
Iter
b
,
Iter
e
);
}
std
::
tuple
<
Row
,
bool
>
emplace
(
Row
r
);
size_t
erase
(
Condition
&&
cond
);
template
<
class
Iter
>
size_t
erase
(
Condition
&&
cond
,
std
::
function
<
void
(
const
Row
&
)
>&&
visit
);
std
::
tuple
<
Row
,
bool
>
emplace
(
Iter
b
,
Iter
e
);
size_t
erase
(
Condition
&&
cond
);
size_t
erase
(
Condition
&&
cond
,
std
::
function
<
void
(
const
Row
&
)
>
&&
visit
);
void
erase
(
Row
r
);
void
erase
(
Row
r
);
iterator
erase
(
iterator
ri
);
iterator
erase
(
iterator
ri
);
...
@@ -1872,67 +1959,67 @@ class Category
...
@@ -1872,67 +1959,67 @@ class Category
// erase without cascade, should only be used when speed is needed
// erase without cascade, should only be used when speed is needed
size_t
erase_nocascade
(
Condition
&&
cond
)
size_t
erase_nocascade
(
Condition
&&
cond
)
{
{
return
erase_nocascade
(
std
::
forward
<
Condition
>
(
cond
),
[](
auto
r
){});
return
erase_nocascade
(
std
::
forward
<
Condition
>
(
cond
),
[](
auto
r
)
{});
}
}
size_t
erase_nocascade
(
Condition
&&
cond
,
std
::
function
<
void
(
const
Row
&
)
>&&
visit
)
size_t
erase_nocascade
(
Condition
&&
cond
,
std
::
function
<
void
(
const
Row
&
)
>
&&
visit
)
{
{
auto
savedValidator
=
mValidator
;
auto
savedValidator
=
mValidator
;
mValidator
=
nullptr
;
mValidator
=
nullptr
;
auto
result
=
erase
(
std
::
forward
<
Condition
>
(
cond
),
std
::
forward
<
std
::
function
<
void
(
const
Row
&
)
>>
(
visit
));
auto
result
=
erase
(
std
::
forward
<
Condition
>
(
cond
),
std
::
forward
<
std
::
function
<
void
(
const
Row
&
)
>>
(
visit
));
mValidator
=
savedValidator
;
mValidator
=
savedValidator
;
return
result
;
return
result
;
}
}
void
eraseOrphans
(
Condition
&&
cond
);
void
eraseOrphans
(
Condition
&&
cond
);
/// an orphan is a row that is the child side of one or more
/// an orphan is a row that is the child side of one or more
/// links and for which there is no single parent left.
/// links and for which there is no single parent left.
bool
isOrphan
(
Row
r
);
bool
isOrphan
(
Row
r
);
bool
hasParent
(
Row
r
,
const
Category
&
parentCat
,
const
ValidateLink
&
link
)
const
;
bool
hasParent
(
Row
r
,
const
Category
&
parentCat
,
const
ValidateLink
&
link
)
const
;
bool
hasChildren
(
Row
r
)
const
;
bool
hasChildren
(
Row
r
)
const
;
bool
hasParents
(
Row
r
)
const
;
bool
hasParents
(
Row
r
)
const
;
RowSet
getChildren
(
Row
r
,
Category
&
childCat
);
RowSet
getChildren
(
Row
r
,
Category
&
childCat
);
RowSet
getChildren
(
Row
r
,
const
char
*
childCat
);
RowSet
getChildren
(
Row
r
,
const
char
*
childCat
);
RowSet
getParents
(
Row
r
,
Category
&
parentCat
);
RowSet
getParents
(
Row
r
,
Category
&
parentCat
);
RowSet
getParents
(
Row
r
,
const
char
*
parentCat
);
RowSet
getParents
(
Row
r
,
const
char
*
parentCat
);
RowSet
getLinked
(
Row
r
,
Category
&
cat
);
RowSet
getLinked
(
Row
r
,
Category
&
cat
);
RowSet
getLinked
(
Row
r
,
const
char
*
cat
);
RowSet
getLinked
(
Row
r
,
const
char
*
cat
);
bool
isValid
();
bool
isValid
();
void
validateLinks
()
const
;
void
validateLinks
()
const
;
const
Validator
&
getValidator
()
const
;
const
Validator
&
getValidator
()
const
;
const
ValidateCategory
*
getCatValidator
()
const
{
return
mCatValidator
;
}
const
ValidateCategory
*
getCatValidator
()
const
{
return
mCatValidator
;
}
Datablock
&
db
()
{
return
mDb
;
}
Datablock
&
db
()
{
return
mDb
;
}
void
setValidator
(
Validator
*
v
);
void
setValidator
(
Validator
*
v
);
iset
fields
()
const
;
iset
fields
()
const
;
iset
mandatoryFields
()
const
;
iset
mandatoryFields
()
const
;
iset
keyFields
()
const
;
iset
keyFields
()
const
;
std
::
set
<
size_t
>
keyFieldsByIndex
()
const
;
std
::
set
<
size_t
>
keyFieldsByIndex
()
const
;
void
drop
(
const
std
::
string
&
field
);
void
getTagOrder
(
std
::
vector
<
std
::
string
>&
tags
)
const
;
void
drop
(
const
std
::
string
&
field
);
void
getTagOrder
(
std
::
vector
<
std
::
string
>
&
tags
)
const
;
// return index for known column, or the next available column index
// return index for known column, or the next available column index
size_t
getColumnIndex
(
const
std
::
string
&
name
)
const
;
size_t
getColumnIndex
(
const
std
::
string
&
name
)
const
;
bool
hasColumn
(
const
std
::
string
&
name
)
const
;
bool
hasColumn
(
const
std
::
string
&
name
)
const
;
const
std
::
string
&
getColumnName
(
size_t
columnIndex
)
const
;
const
std
::
string
&
getColumnName
(
size_t
columnIndex
)
const
;
std
::
vector
<
std
::
string
>
getColumnNames
()
const
;
std
::
vector
<
std
::
string
>
getColumnNames
()
const
;
void
reorderByIndex
();
void
reorderByIndex
();
void
sort
(
std
::
function
<
int
(
const
Row
&
,
const
Row
&
)
>
comparator
);
void
sort
(
std
::
function
<
int
(
const
Row
&
,
const
Row
&
)
>
comparator
);
// --------------------------------------------------------------------
// --------------------------------------------------------------------
/// Rename a single column in the rows that match \a cond to value \a value
/// Rename a single column in the rows that match \a cond to value \a value
...
@@ -1942,7 +2029,7 @@ class Category
...
@@ -1942,7 +2029,7 @@ class Category
void
update_value
(
Condition
&&
cond
,
const
std
::
string
&
tag
,
const
std
::
string
&
value
)
void
update_value
(
Condition
&&
cond
,
const
std
::
string
&
tag
,
const
std
::
string
&
value
)
{
{
update_value
(
RowSet
{
*
this
,
std
::
move
(
cond
)
},
tag
,
value
);
update_value
(
RowSet
{
*
this
,
std
::
move
(
cond
)
},
tag
,
value
);
}
}
void
update_value
(
RowSet
&&
rows
,
const
std
::
string
&
tag
,
const
std
::
string
&
value
);
void
update_value
(
RowSet
&&
rows
,
const
std
::
string
&
tag
,
const
std
::
string
&
value
);
...
@@ -1954,25 +2041,30 @@ class Category
...
@@ -1954,25 +2041,30 @@ class Category
std
::
string
getUniqueID
(
std
::
function
<
std
::
string
(
int
)
>
generator
=
cif
::
cifIdForNumber
);
std
::
string
getUniqueID
(
std
::
function
<
std
::
string
(
int
)
>
generator
=
cif
::
cifIdForNumber
);
std
::
string
getUniqueID
(
const
std
::
string
&
prefix
)
std
::
string
getUniqueID
(
const
std
::
string
&
prefix
)
{
{
return
getUniqueID
([
prefix
](
int
nr
)
{
return
prefix
+
std
::
to_string
(
nr
);
});
return
getUniqueID
([
prefix
](
int
nr
)
{
return
prefix
+
std
::
to_string
(
nr
);
});
}
}
private
:
// --------------------------------------------------------------------
// for debugging
void
write
(
std
::
ostream
&
os
);
friend
bool
operator
==
(
const
Category
&
lhs
,
const
Category
&
rhs
);
void
write
(
std
::
ostream
&
os
,
const
std
::
vector
<
std
::
string
>&
order
);
void
write
(
std
::
ostream
&
os
,
const
std
::
vector
<
size_t
>&
order
,
bool
includeEmptyColumns
);
size_t
addColumn
(
const
std
::
string
&
name
);
private
:
void
write
(
std
::
ostream
&
os
);
Datablock
&
mDb
;
void
write
(
std
::
ostream
&
os
,
const
std
::
vector
<
std
::
string
>
&
order
);
std
::
string
mName
;
void
write
(
std
::
ostream
&
os
,
const
std
::
vector
<
size_t
>
&
order
,
bool
includeEmptyColumns
);
Validator
*
mValidator
;
const
ValidateCategory
*
mCatValidator
=
nullptr
;
size_t
addColumn
(
const
std
::
string
&
name
);
std
::
vector
<
ItemColumn
>
mColumns
;
ItemRow
*
mHead
;
Datablock
&
mDb
;
ItemRow
*
mTail
;
std
::
string
mName
;
class
CatIndex
*
mIndex
;
Validator
*
mValidator
;
const
ValidateCategory
*
mCatValidator
=
nullptr
;
std
::
vector
<
ItemColumn
>
mColumns
;
ItemRow
*
mHead
;
ItemRow
*
mTail
;
class
CatIndex
*
mIndex
;
};
};
// --------------------------------------------------------------------
// --------------------------------------------------------------------
...
@@ -1984,82 +2076,96 @@ class File
...
@@ -1984,82 +2076,96 @@ class File
friend
class
Validator
;
friend
class
Validator
;
File
();
File
();
File
(
std
::
istream
&
is
,
bool
validate
=
false
);
File
(
std
::
istream
&
is
,
bool
validate
=
false
);
File
(
const
std
::
string
&
path
,
bool
validate
=
false
);
File
(
const
std
::
string
&
path
,
bool
validate
=
false
);
File
(
File
&&
rhs
);
File
(
File
&&
rhs
);
File
(
const
File
&
rhs
)
=
delete
;
File
(
const
File
&
rhs
)
=
delete
;
File
&
operator
=
(
const
File
&
rhs
)
=
delete
;
File
&
operator
=
(
const
File
&
rhs
)
=
delete
;
~
File
();
~
File
();
void
load
(
const
std
::
string
&
p
);
void
load
(
const
std
::
string
&
p
);
void
save
(
const
std
::
string
&
p
);
void
save
(
const
std
::
string
&
p
);
void
load
(
std
::
istream
&
is
);
void
load
(
std
::
istream
&
is
);
void
save
(
std
::
ostream
&
os
);
void
save
(
std
::
ostream
&
os
);
/// \brief Load only the data block \a datablock from the mmCIF file
/// \brief Load only the data block \a datablock from the mmCIF file
void
load
(
std
::
istream
&
is
,
const
std
::
string
&
datablock
);
void
load
(
std
::
istream
&
is
,
const
std
::
string
&
datablock
);
void
save
(
std
::
ostream
&
os
,
const
std
::
vector
<
std
::
string
>&
order
)
{
write
(
os
,
order
);
}
void
save
(
std
::
ostream
&
os
,
const
std
::
vector
<
std
::
string
>
&
order
)
{
write
(
os
,
order
);
}
void
write
(
std
::
ostream
&
os
,
const
std
::
vector
<
std
::
string
>&
order
);
void
write
(
std
::
ostream
&
os
,
const
std
::
vector
<
std
::
string
>
&
order
);
void
loadDictionary
();
// load the default dictionary, that is mmcifDdl in this case
void
loadDictionary
();
// load the default dictionary, that is mmcifDdl in this case
void
loadDictionary
(
const
char
*
dict
);
// load one of the compiled in dictionaries
void
loadDictionary
(
const
char
*
dict
);
// load one of the compiled in dictionaries
void
loadDictionary
(
std
::
istream
&
is
);
// load dictionary from input stream
void
loadDictionary
(
std
::
istream
&
is
);
// load dictionary from input stream
bool
isValid
();
bool
isValid
();
void
validateLinks
()
const
;
void
validateLinks
()
const
;
Datablock
&
firstDatablock
()
const
Datablock
&
firstDatablock
()
const
{
{
if
(
mHead
==
nullptr
)
if
(
mHead
==
nullptr
)
throw
std
::
runtime_error
(
"No datablocks in file"
);
throw
std
::
runtime_error
(
"No datablocks in file"
);
return
*
mHead
;
return
*
mHead
;
}
}
void
append
(
Datablock
*
e
);
Datablock
&
firstDatablock
()
{
Datablock
*
get
(
const
std
::
string
&
name
)
const
;
if
(
mHead
==
nullptr
)
Datablock
&
operator
[](
const
std
::
string
&
name
);
throw
std
::
runtime_error
(
"No datablocks in file"
);
return
*
mHead
;
}
void
append
(
Datablock
*
e
);
struct
iterator
Datablock
*
get
(
const
std
::
string
&
name
)
const
;
Datablock
&
operator
[](
const
std
::
string
&
name
);
struct
iterator
{
{
using
iterator_category
=
std
::
forward_iterator_tag
;
using
iterator_category
=
std
::
forward_iterator_tag
;
using
value_type
=
Datablock
;
using
value_type
=
Datablock
;
using
difference_type
=
std
::
ptrdiff_t
;
using
difference_type
=
std
::
ptrdiff_t
;
using
pointer
=
value_type
*
;
using
pointer
=
value_type
*
;
using
reference
=
value_type
&
;
using
reference
=
value_type
&
;
iterator
(
Datablock
*
db
)
:
mCurrent
(
db
)
{}
iterator
(
Datablock
*
db
)
:
mCurrent
(
db
)
reference
operator
*
()
{
return
*
mCurrent
;
}
{
pointer
operator
->
()
{
return
mCurrent
;
}
}
iterator
&
operator
++
();
reference
operator
*
()
{
return
*
mCurrent
;
}
iterator
operator
++
(
int
)
{
iterator
result
(
*
this
);
this
->
operator
++
();
return
result
;
}
pointer
operator
->
()
{
return
mCurrent
;
}
bool
operator
==
(
const
iterator
&
rhs
)
const
{
return
mCurrent
==
rhs
.
mCurrent
;
}
iterator
&
operator
++
();
bool
operator
!=
(
const
iterator
&
rhs
)
const
{
return
not
(
mCurrent
==
rhs
.
mCurrent
);
}
iterator
operator
++
(
int
)
{
iterator
result
(
*
this
);
this
->
operator
++
();
return
result
;
}
bool
operator
==
(
const
iterator
&
rhs
)
const
{
return
mCurrent
==
rhs
.
mCurrent
;
}
bool
operator
!=
(
const
iterator
&
rhs
)
const
{
return
not
(
mCurrent
==
rhs
.
mCurrent
);
}
private
:
private
:
Datablock
*
mCurrent
;
Datablock
*
mCurrent
;
};
};
iterator
begin
()
const
;
iterator
begin
()
const
;
iterator
end
()
const
;
iterator
end
()
const
;
bool
empty
()
const
{
return
mHead
==
nullptr
;
}
const
Validator
&
getValidator
()
const
;
bool
empty
()
const
{
return
mHead
==
nullptr
;
}
void
getTagOrder
(
std
::
vector
<
std
::
string
>&
tags
)
const
;
private
:
void
setValidator
(
Validator
*
v
);
const
Validator
&
getValidator
()
const
;
void
getTagOrder
(
std
::
vector
<
std
::
string
>
&
tags
)
const
;
Datablock
*
mHead
;
private
:
Validator
*
mValidator
;
void
setValidator
(
Validator
*
v
);
Datablock
*
mHead
;
Validator
*
mValidator
;
};
};
// --------------------------------------------------------------------
// --------------------------------------------------------------------
...
@@ -2068,64 +2174,67 @@ class File
...
@@ -2068,64 +2174,67 @@ class File
namespace
detail
namespace
detail
{
{
template
<
typename
T
>
template
<
typename
T
>
inline
inline
bool
AnyIsConditionImpl
<
T
>::
test
(
const
Category
&
c
,
const
Row
&
r
)
const
bool
AnyIsConditionImpl
<
T
>::
test
(
const
Category
&
c
,
const
Row
&
r
)
const
{
bool
result
=
false
;
for
(
auto
&
f
:
c
.
fields
())
{
{
try
bool
result
=
false
;
for
(
auto
&
f
:
c
.
fields
())
{
{
if
(
r
[
f
].
as
<
valueType
>
()
==
mValue
)
try
{
if
(
r
[
f
].
as
<
valueType
>
()
==
mValue
)
{
result
=
true
;
break
;
}
}
catch
(...)
{
{
result
=
true
;
break
;
}
}
}
}
catch
(...)
{}
return
result
;
}
}
return
result
;
}
inline
bool
AnyMatchesConditionImpl
::
test
(
const
Category
&
c
,
const
Row
&
r
)
const
inline
bool
AnyMatchesConditionImpl
::
test
(
const
Category
&
c
,
const
Row
&
r
)
const
{
bool
result
=
false
;
for
(
auto
&
f
:
c
.
fields
())
{
{
try
bool
result
=
false
;
for
(
auto
&
f
:
c
.
fields
())
{
{
if
(
std
::
regex_match
(
r
[
f
].
as
<
std
::
string
>
(),
mRx
))
try
{
if
(
std
::
regex_match
(
r
[
f
].
as
<
std
::
string
>
(),
mRx
))
{
result
=
true
;
break
;
}
}
catch
(...)
{
{
result
=
true
;
break
;
}
}
}
}
catch
(...)
{}
return
result
;
}
}
return
result
;
}
// namespace detail
}
}
// these should be here, as I learned today
// these should be here, as I learned today
inline
void
swap
(
cif
::
Row
&
a
,
cif
::
Row
&
b
)
inline
void
swap
(
cif
::
Row
&
a
,
cif
::
Row
&
b
)
{
{
a
.
swap
(
b
);
a
.
swap
(
b
);
}
}
inline
void
swap
(
cif
::
detail
::
ItemReference
&
a
,
cif
::
detail
::
ItemReference
&
b
)
inline
void
swap
(
cif
::
detail
::
ItemReference
&
a
,
cif
::
detail
::
ItemReference
&
b
)
{
{
a
.
swap
(
b
);
a
.
swap
(
b
);
}
}
// --------------------------------------------------------------------
// --------------------------------------------------------------------
template
<
typename
RowType
,
typename
...
Ts
>
template
<
typename
RowType
,
typename
...
Ts
>
iterator_proxy
<
RowType
,
Ts
...
>::
iterator_proxy
(
Category
&
cat
,
row_iterator
pos
,
char
const
*
const
columns
[
N
])
iterator_proxy
<
RowType
,
Ts
...
>::
iterator_proxy
(
Category
&
cat
,
row_iterator
pos
,
char
const
*
const
columns
[
N
])
:
mCat
(
&
cat
)
:
mCat
(
&
cat
)
,
mCBegin
(
pos
)
,
mCBegin
(
pos
)
,
mCEnd
(
cat
.
end
())
,
mCEnd
(
cat
.
end
())
...
@@ -2134,8 +2243,8 @@ iterator_proxy<RowType, Ts...>::iterator_proxy(Category& cat, row_iterator pos,
...
@@ -2134,8 +2243,8 @@ iterator_proxy<RowType, Ts...>::iterator_proxy(Category& cat, row_iterator pos,
mCix
[
i
]
=
mCat
->
getColumnIndex
(
columns
[
i
]);
mCix
[
i
]
=
mCat
->
getColumnIndex
(
columns
[
i
]);
}
}
template
<
typename
RowType
,
typename
...
Ts
>
template
<
typename
RowType
,
typename
...
Ts
>
iterator_proxy
<
RowType
,
Ts
...
>::
iterator_proxy
(
Category
&
cat
,
row_iterator
pos
,
std
::
initializer_list
<
char
const
*>
columns
)
iterator_proxy
<
RowType
,
Ts
...
>::
iterator_proxy
(
Category
&
cat
,
row_iterator
pos
,
std
::
initializer_list
<
char
const
*>
columns
)
:
mCat
(
&
cat
)
:
mCat
(
&
cat
)
,
mCBegin
(
pos
)
,
mCBegin
(
pos
)
,
mCEnd
(
cat
.
end
())
,
mCEnd
(
cat
.
end
())
...
@@ -2143,30 +2252,36 @@ iterator_proxy<RowType, Ts...>::iterator_proxy(Category& cat, row_iterator pos,
...
@@ -2143,30 +2252,36 @@ iterator_proxy<RowType, Ts...>::iterator_proxy(Category& cat, row_iterator pos,
// static_assert(columns.size() == N, "The list of column names should be exactly the same as the list of requested columns");
// static_assert(columns.size() == N, "The list of column names should be exactly the same as the list of requested columns");
std
::
size_t
i
=
0
;
std
::
size_t
i
=
0
;
for
(
auto
column
:
columns
)
for
(
auto
column
:
columns
)
mCix
[
i
++
]
=
mCat
->
getColumnIndex
(
column
);
mCix
[
i
++
]
=
mCat
->
getColumnIndex
(
column
);
}
}
// --------------------------------------------------------------------
// --------------------------------------------------------------------
template
<
typename
RowType
,
typename
...
Ts
>
template
<
typename
RowType
,
typename
...
Ts
>
conditional_iterator_proxy
<
RowType
,
Ts
...
>::
conditional_iterator_impl
::
conditional_iterator_impl
(
conditional_iterator_proxy
<
RowType
,
Ts
...
>::
conditional_iterator_impl
::
conditional_iterator_impl
(
Category
&
cat
,
row_iterator
pos
,
const
Condition
&
cond
,
const
std
::
array
<
size_t
,
N
>&
cix
)
Category
&
cat
,
row_iterator
pos
,
const
Condition
&
cond
,
const
std
::
array
<
size_t
,
N
>
&
cix
)
:
mCat
(
&
cat
),
mBegin
(
pos
,
cix
),
mEnd
(
cat
.
end
(),
cix
),
mCondition
(
&
cond
)
:
mCat
(
&
cat
)
,
mBegin
(
pos
,
cix
)
,
mEnd
(
cat
.
end
(),
cix
)
,
mCondition
(
&
cond
)
{
{
}
}
template
<
typename
RowType
,
typename
...
Ts
>
template
<
typename
RowType
,
typename
...
Ts
>
conditional_iterator_proxy
<
RowType
,
Ts
...
>::
conditional_iterator_proxy
(
conditional_iterator_proxy
&&
p
)
conditional_iterator_proxy
<
RowType
,
Ts
...
>::
conditional_iterator_proxy
(
conditional_iterator_proxy
&&
p
)
:
mCat
(
nullptr
),
mCBegin
(
p
.
mCBegin
),
mCEnd
(
p
.
mCEnd
),
mCix
(
p
.
mCix
)
:
mCat
(
nullptr
)
,
mCBegin
(
p
.
mCBegin
)
,
mCEnd
(
p
.
mCEnd
)
,
mCix
(
p
.
mCix
)
{
{
std
::
swap
(
mCat
,
p
.
mCat
);
std
::
swap
(
mCat
,
p
.
mCat
);
std
::
swap
(
mCix
,
p
.
mCix
);
std
::
swap
(
mCix
,
p
.
mCix
);
mCondition
.
swap
(
p
.
mCondition
);
mCondition
.
swap
(
p
.
mCondition
);
}
}
template
<
typename
RowType
,
typename
...
Ts
>
template
<
typename
RowType
,
typename
...
Ts
>
conditional_iterator_proxy
<
RowType
,
Ts
...
>::
conditional_iterator_proxy
(
Category
&
cat
,
row_iterator
pos
,
Condition
&&
cond
)
conditional_iterator_proxy
<
RowType
,
Ts
...
>::
conditional_iterator_proxy
(
Category
&
cat
,
row_iterator
pos
,
Condition
&&
cond
)
:
mCat
(
&
cat
)
:
mCat
(
&
cat
)
,
mCondition
(
std
::
move
(
cond
))
,
mCondition
(
std
::
move
(
cond
))
,
mCBegin
(
pos
)
,
mCBegin
(
pos
)
...
@@ -2178,9 +2293,9 @@ conditional_iterator_proxy<RowType, Ts...>::conditional_iterator_proxy(Category&
...
@@ -2178,9 +2293,9 @@ conditional_iterator_proxy<RowType, Ts...>::conditional_iterator_proxy(Category&
++
mCBegin
;
++
mCBegin
;
}
}
template
<
typename
RowType
,
typename
...
Ts
>
template
<
typename
RowType
,
typename
...
Ts
>
template
<
std
::
size_t
TN
,
std
::
enable_if_t
<
TN
!=
0
,
bool
>>
template
<
std
::
size_t
TN
,
std
::
enable_if_t
<
TN
!=
0
,
bool
>>
conditional_iterator_proxy
<
RowType
,
Ts
...
>::
conditional_iterator_proxy
(
Category
&
cat
,
row_iterator
pos
,
Condition
&&
cond
,
const
char
*
const
columns
[
N
])
conditional_iterator_proxy
<
RowType
,
Ts
...
>::
conditional_iterator_proxy
(
Category
&
cat
,
row_iterator
pos
,
Condition
&&
cond
,
const
char
*
const
columns
[
N
])
:
mCat
(
&
cat
)
:
mCat
(
&
cat
)
,
mCondition
(
std
::
move
(
cond
))
,
mCondition
(
std
::
move
(
cond
))
,
mCBegin
(
pos
)
,
mCBegin
(
pos
)
...
@@ -2195,33 +2310,33 @@ conditional_iterator_proxy<RowType, Ts...>::conditional_iterator_proxy(Category&
...
@@ -2195,33 +2310,33 @@ conditional_iterator_proxy<RowType, Ts...>::conditional_iterator_proxy(Category&
mCix
[
i
]
=
mCat
->
getColumnIndex
(
columns
[
i
]);
mCix
[
i
]
=
mCat
->
getColumnIndex
(
columns
[
i
]);
}
}
template
<
typename
RowType
,
typename
...
Ts
>
template
<
typename
RowType
,
typename
...
Ts
>
conditional_iterator_proxy
<
RowType
,
Ts
...
>
&
conditional_iterator_proxy
<
RowType
,
Ts
...
>::
operator
=
(
conditional_iterator_proxy
&&
p
)
conditional_iterator_proxy
<
RowType
,
Ts
...
>
&
conditional_iterator_proxy
<
RowType
,
Ts
...
>::
operator
=
(
conditional_iterator_proxy
&&
p
)
{
{
swap
(
p
);
swap
(
p
);
return
*
this
;
return
*
this
;
}
}
template
<
typename
RowType
,
typename
...
Ts
>
template
<
typename
RowType
,
typename
...
Ts
>
typename
conditional_iterator_proxy
<
RowType
,
Ts
...
>::
iterator
conditional_iterator_proxy
<
RowType
,
Ts
...
>::
begin
()
const
typename
conditional_iterator_proxy
<
RowType
,
Ts
...
>::
iterator
conditional_iterator_proxy
<
RowType
,
Ts
...
>::
begin
()
const
{
{
return
iterator
(
*
mCat
,
mCBegin
,
mCondition
,
mCix
);
return
iterator
(
*
mCat
,
mCBegin
,
mCondition
,
mCix
);
}
}
template
<
typename
RowType
,
typename
...
Ts
>
template
<
typename
RowType
,
typename
...
Ts
>
typename
conditional_iterator_proxy
<
RowType
,
Ts
...
>::
iterator
conditional_iterator_proxy
<
RowType
,
Ts
...
>::
end
()
const
typename
conditional_iterator_proxy
<
RowType
,
Ts
...
>::
iterator
conditional_iterator_proxy
<
RowType
,
Ts
...
>::
end
()
const
{
{
return
iterator
(
*
mCat
,
mCEnd
,
mCondition
,
mCix
);
return
iterator
(
*
mCat
,
mCEnd
,
mCondition
,
mCix
);
}
}
template
<
typename
RowType
,
typename
...
Ts
>
template
<
typename
RowType
,
typename
...
Ts
>
bool
conditional_iterator_proxy
<
RowType
,
Ts
...
>::
empty
()
const
bool
conditional_iterator_proxy
<
RowType
,
Ts
...
>::
empty
()
const
{
{
return
mCBegin
==
mCEnd
;
return
mCBegin
==
mCEnd
;
}
}
template
<
typename
RowType
,
typename
...
Ts
>
template
<
typename
RowType
,
typename
...
Ts
>
void
conditional_iterator_proxy
<
RowType
,
Ts
...
>::
swap
(
conditional_iterator_proxy
&
rhs
)
void
conditional_iterator_proxy
<
RowType
,
Ts
...
>::
swap
(
conditional_iterator_proxy
&
rhs
)
{
{
std
::
swap
(
mCat
,
rhs
.
mCat
);
std
::
swap
(
mCat
,
rhs
.
mCat
);
mCondition
.
swap
(
rhs
.
mCondition
);
mCondition
.
swap
(
rhs
.
mCondition
);
...
@@ -2230,5 +2345,4 @@ void conditional_iterator_proxy<RowType, Ts...>::swap(conditional_iterator_proxy
...
@@ -2230,5 +2345,4 @@ void conditional_iterator_proxy<RowType, Ts...>::swap(conditional_iterator_proxy
std
::
swap
(
mCix
,
rhs
.
mCix
);
std
::
swap
(
mCix
,
rhs
.
mCix
);
}
}
}
}
// namespace cif
include/cif++/Structure.hpp
View file @
345c4778
...
@@ -199,15 +199,15 @@ class Residue
...
@@ -199,15 +199,15 @@ class Residue
// constructor for waters
// constructor for waters
Residue
(
const
Structure
&
structure
,
const
std
::
string
&
compoundID
,
Residue
(
const
Structure
&
structure
,
const
std
::
string
&
compoundID
,
const
std
::
string
&
asymID
,
const
std
::
string
&
authSeqID
);
const
std
::
string
&
asymID
,
const
std
::
string
&
authSeqID
);
// constructor for a residue without a sequence number
// constructor for a residue without a sequence number
Residue
(
const
Structure
&
structure
,
const
std
::
string
&
compoundID
,
Residue
(
const
Structure
&
structure
,
const
std
::
string
&
compoundID
,
const
std
::
string
&
asymID
);
const
std
::
string
&
asymID
);
// constructor for a residue with a sequence number
// constructor for a residue with a sequence number
Residue
(
const
Structure
&
structure
,
const
std
::
string
&
compoundID
,
Residue
(
const
Structure
&
structure
,
const
std
::
string
&
compoundID
,
const
std
::
string
&
asymID
,
int
seqID
,
const
std
::
string
&
authSeqID
);
const
std
::
string
&
asymID
,
int
seqID
,
const
std
::
string
&
authSeqID
);
Residue
(
const
Residue
&
rhs
)
=
delete
;
Residue
(
const
Residue
&
rhs
)
=
delete
;
Residue
&
operator
=
(
const
Residue
&
rhs
)
=
delete
;
Residue
&
operator
=
(
const
Residue
&
rhs
)
=
delete
;
...
@@ -297,7 +297,7 @@ class Monomer : public Residue
...
@@ -297,7 +297,7 @@ class Monomer : public Residue
Monomer
&
operator
=
(
Monomer
&&
rhs
);
Monomer
&
operator
=
(
Monomer
&&
rhs
);
Monomer
(
const
Polymer
&
polymer
,
size_t
index
,
int
seqID
,
const
std
::
string
&
authSeqID
,
Monomer
(
const
Polymer
&
polymer
,
size_t
index
,
int
seqID
,
const
std
::
string
&
authSeqID
,
const
std
::
string
&
compoundID
);
const
std
::
string
&
compoundID
);
bool
is_first_in_chain
()
const
;
bool
is_first_in_chain
()
const
;
bool
is_last_in_chain
()
const
;
bool
is_last_in_chain
()
const
;
...
@@ -397,6 +397,8 @@ class File : public std::enable_shared_from_this<File>
...
@@ -397,6 +397,8 @@ class File : public std::enable_shared_from_this<File>
File
(
const
File
&
)
=
delete
;
File
(
const
File
&
)
=
delete
;
File
&
operator
=
(
const
File
&
)
=
delete
;
File
&
operator
=
(
const
File
&
)
=
delete
;
cif
::
Datablock
&
createDatablock
(
const
std
::
string
&
name
);
void
load
(
const
std
::
string
&
path
);
void
load
(
const
std
::
string
&
path
);
void
save
(
const
std
::
string
&
path
);
void
save
(
const
std
::
string
&
path
);
...
@@ -450,7 +452,7 @@ class Structure
...
@@ -450,7 +452,7 @@ class Structure
// Atom getAtomByLocation(Point pt, float maxDistance) const;
// Atom getAtomByLocation(Point pt, float maxDistance) const;
Atom
getAtomByLabel
(
const
std
::
string
&
atomID
,
const
std
::
string
&
asymID
,
Atom
getAtomByLabel
(
const
std
::
string
&
atomID
,
const
std
::
string
&
asymID
,
const
std
::
string
&
compID
,
int
seqID
,
const
std
::
string
&
altID
=
""
);
const
std
::
string
&
compID
,
int
seqID
,
const
std
::
string
&
altID
=
""
);
/// \brief Get a residue, if \a seqID is zero, the non-polymers are searched
/// \brief Get a residue, if \a seqID is zero, the non-polymers are searched
const
Residue
&
getResidue
(
const
std
::
string
&
asymID
,
const
std
::
string
&
compID
,
int
seqID
=
0
)
const
;
const
Residue
&
getResidue
(
const
std
::
string
&
asymID
,
const
std
::
string
&
compID
,
int
seqID
=
0
)
const
;
...
@@ -458,7 +460,7 @@ class Structure
...
@@ -458,7 +460,7 @@ class Structure
// map between auth and label locations
// map between auth and label locations
std
::
tuple
<
std
::
string
,
int
,
std
::
string
>
MapAuthToLabel
(
const
std
::
string
&
asymID
,
std
::
tuple
<
std
::
string
,
int
,
std
::
string
>
MapAuthToLabel
(
const
std
::
string
&
asymID
,
const
std
::
string
&
seqID
,
const
std
::
string
&
compID
,
const
std
::
string
&
insCode
=
""
);
const
std
::
string
&
seqID
,
const
std
::
string
&
compID
,
const
std
::
string
&
insCode
=
""
);
std
::
tuple
<
std
::
string
,
std
::
string
,
std
::
string
,
std
::
string
>
MapLabelToAuth
(
std
::
tuple
<
std
::
string
,
std
::
string
,
std
::
string
,
std
::
string
>
MapLabelToAuth
(
const
std
::
string
&
asymID
,
int
seqID
,
const
std
::
string
&
compID
);
const
std
::
string
&
asymID
,
int
seqID
,
const
std
::
string
&
compID
);
...
@@ -480,7 +482,20 @@ class Structure
...
@@ -480,7 +482,20 @@ class Structure
void
swapAtoms
(
Atom
&
a1
,
Atom
&
a2
);
// swap the labels for these atoms
void
swapAtoms
(
Atom
&
a1
,
Atom
&
a2
);
// swap the labels for these atoms
void
moveAtom
(
Atom
&
a
,
Point
p
);
// move atom to a new location
void
moveAtom
(
Atom
&
a
,
Point
p
);
// move atom to a new location
void
changeResidue
(
const
Residue
&
res
,
const
std
::
string
&
newCompound
,
void
changeResidue
(
const
Residue
&
res
,
const
std
::
string
&
newCompound
,
const
std
::
vector
<
std
::
tuple
<
std
::
string
,
std
::
string
>>
&
remappedAtoms
);
const
std
::
vector
<
std
::
tuple
<
std
::
string
,
std
::
string
>>
&
remappedAtoms
);
/// \brief Create a new non-polymer entity, returns new ID
/// \param data The data to use to fill the entity
/// \param mon_id The mon_id for the new nonpoly
/// \param name The name of the nonpoly
/// \return The ID of the created entity
std
::
string
createEntityNonPoly
(
std
::
vector
<
cif
::
Item
>
data
,
const
std
::
string
&
mon_id
);
/// \brief Create a new NonPolymer struct_asym with atoms constructed from \a atom_data, returns asym_id
/// \param entity_id The entity ID of the new nonpoly
/// \param atoms The array of atom data fields
/// \return The newly create asym ID
std
::
string
createNonpoly
(
const
std
::
string
&
entity_id
,
const
std
::
vector
<
cif
::
Item
>
&
atoms
);
/// To sort the atoms in order of model > asym-id > res-id > atom-id
/// To sort the atoms in order of model > asym-id > res-id > atom-id
/// Will asssign new atom_id's to all atoms. Be carefull
/// Will asssign new atom_id's to all atoms. Be carefull
...
...
src/Cif++.cpp
View file @
345c4778
...
@@ -26,26 +26,26 @@
...
@@ -26,26 +26,26 @@
#include <cassert>
#include <cassert>
#include <
stack
>
#include <
fstream
>
#include <
tuple
>
#include <
numeric
>
#include <regex>
#include <regex>
#include <set>
#include <set>
#include <stack>
#include <tuple>
#include <unordered_map>
#include <unordered_map>
#include <numeric>
#include <fstream>
#include <filesystem>
#include <filesystem>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/bzip2.hpp>
#include <boost/iostreams/filter/bzip2.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/logic/tribool.hpp>
#include <boost/logic/tribool.hpp>
#include "cif++/Cif++.hpp"
#include "cif++/Cif++.hpp"
#include "cif++/CifParser.hpp"
#include "cif++/CifParser.hpp"
#include "cif++/CifValidator.hpp"
#include "cif++/CifUtils.hpp"
#include "cif++/CifUtils.hpp"
#include "cif++/CifValidator.hpp"
namespace
ba
=
boost
::
algorithm
;
namespace
ba
=
boost
::
algorithm
;
namespace
io
=
boost
::
iostreams
;
namespace
io
=
boost
::
iostreams
;
...
@@ -56,34 +56,35 @@ namespace cif
...
@@ -56,34 +56,35 @@ namespace cif
CIFPP_EXPORT
int
VERBOSE
=
0
;
CIFPP_EXPORT
int
VERBOSE
=
0
;
static
const
char
*
kEmptyResult
=
""
;
static
const
char
*
kEmptyResult
=
""
;
// --------------------------------------------------------------------
// --------------------------------------------------------------------
// most internal data structures are stored as linked lists
// most internal data structures are stored as linked lists
// Item values are stored in a simple struct. They should be const anyway
// Item values are stored in a simple struct. They should be const anyway
struct
ItemValue
struct
ItemValue
{
{
ItemValue
*
mNext
;
ItemValue
*
mNext
;
uint32_t
mColumnIndex
;
uint32_t
mColumnIndex
;
char
mText
[
4
];
char
mText
[
4
];
ItemValue
(
const
char
*
v
,
size_t
columnIndex
);
ItemValue
(
const
char
*
v
,
size_t
columnIndex
);
~
ItemValue
();
~
ItemValue
();
bool
empty
()
const
{
return
mText
[
0
]
==
0
or
((
mText
[
0
]
==
'.'
or
mText
[
0
]
==
'?'
)
and
mText
[
1
]
==
0
);
}
bool
null
()
const
{
return
mText
[
0
]
==
'.'
and
mText
[
1
]
==
0
;
}
bool
unknown
()
const
{
return
mText
[
0
]
==
'?'
and
mText
[
1
]
==
0
;
}
void
*
operator
new
(
size_t
size
,
size_t
dataSize
);
bool
empty
()
const
{
return
mText
[
0
]
==
0
or
((
mText
[
0
]
==
'.'
or
mText
[
0
]
==
'?'
)
and
mText
[
1
]
==
0
);
}
void
operator
delete
(
void
*
p
);
bool
null
()
const
{
return
mText
[
0
]
==
'.'
and
mText
[
1
]
==
0
;
}
void
operator
delete
(
void
*
p
,
size_t
dataSize
);
bool
unknown
()
const
{
return
mText
[
0
]
==
'?'
and
mText
[
1
]
==
0
;
}
void
*
operator
new
(
size_t
size
,
size_t
dataSize
);
void
operator
delete
(
void
*
p
);
void
operator
delete
(
void
*
p
,
size_t
dataSize
);
};
};
// --------------------------------------------------------------------
// --------------------------------------------------------------------
ItemValue
::
ItemValue
(
const
char
*
value
,
size_t
columnIndex
)
ItemValue
::
ItemValue
(
const
char
*
value
,
size_t
columnIndex
)
:
mNext
(
nullptr
),
mColumnIndex
(
uint32_t
(
columnIndex
))
:
mNext
(
nullptr
)
,
mColumnIndex
(
uint32_t
(
columnIndex
))
{
{
assert
(
columnIndex
<
std
::
numeric_limits
<
uint32_t
>::
max
());
assert
(
columnIndex
<
std
::
numeric_limits
<
uint32_t
>::
max
());
strcpy
(
mText
,
value
);
strcpy
(
mText
,
value
);
...
@@ -101,17 +102,17 @@ ItemValue::~ItemValue()
...
@@ -101,17 +102,17 @@ ItemValue::~ItemValue()
}
}
}
}
void
*
ItemValue
::
operator
new
(
size_t
size
,
size_t
dataSize
)
void
*
ItemValue
::
operator
new
(
size_t
size
,
size_t
dataSize
)
{
{
return
malloc
(
size
-
4
+
dataSize
+
1
);
return
malloc
(
size
-
4
+
dataSize
+
1
);
}
}
void
ItemValue
::
operator
delete
(
void
*
p
)
void
ItemValue
::
operator
delete
(
void
*
p
)
{
{
free
(
p
);
free
(
p
);
}
}
void
ItemValue
::
operator
delete
(
void
*
p
,
size_t
dataSize
)
void
ItemValue
::
operator
delete
(
void
*
p
,
size_t
dataSize
)
{
{
free
(
p
);
free
(
p
);
}
}
...
@@ -121,8 +122,8 @@ void ItemValue::operator delete(void* p, size_t dataSize)
...
@@ -121,8 +122,8 @@ void ItemValue::operator delete(void* p, size_t dataSize)
struct
ItemColumn
struct
ItemColumn
{
{
std
::
string
mName
;
// store lower-case, for optimization
std
::
string
mName
;
// store lower-case, for optimization
const
ValidateItem
*
mValidator
;
const
ValidateItem
*
mValidator
;
};
};
// itemRow contains the actual values for a Row in a Category
// itemRow contains the actual values for a Row in a Category
...
@@ -132,8 +133,8 @@ struct ItemRow
...
@@ -132,8 +133,8 @@ struct ItemRow
~
ItemRow
();
~
ItemRow
();
void
drop
(
size_t
columnIx
);
void
drop
(
size_t
columnIx
);
const
char
*
c_str
(
size_t
columnIx
)
const
;
const
char
*
c_str
(
size_t
columnIx
)
const
;
std
::
string
str
()
const
std
::
string
str
()
const
{
{
std
::
stringstream
s
;
std
::
stringstream
s
;
...
@@ -144,21 +145,21 @@ struct ItemRow
...
@@ -144,21 +145,21 @@ struct ItemRow
s
<<
mCategory
->
getColumnName
(
v
->
mColumnIndex
)
s
<<
mCategory
->
getColumnName
(
v
->
mColumnIndex
)
<<
':'
<<
':'
<<
v
->
mText
;
<<
v
->
mText
;
if
(
v
->
mNext
!=
nullptr
)
if
(
v
->
mNext
!=
nullptr
)
s
<<
", "
;
s
<<
", "
;
}
}
s
<<
'}'
;
s
<<
'}'
;
return
s
.
str
();
return
s
.
str
();
}
}
ItemRow
*
mNext
;
ItemRow
*
mNext
;
Category
*
mCategory
;
Category
*
mCategory
;
ItemValue
*
mValues
;
ItemValue
*
mValues
;
uint32_t
mLineNr
=
0
;
uint32_t
mLineNr
=
0
;
};
};
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
ItemRow
&
r
)
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
ItemRow
&
r
)
{
{
os
<<
r
.
mCategory
->
name
()
<<
'['
;
os
<<
r
.
mCategory
->
name
()
<<
'['
;
for
(
auto
iv
=
r
.
mValues
;
iv
!=
nullptr
;
iv
=
iv
->
mNext
)
for
(
auto
iv
=
r
.
mValues
;
iv
!=
nullptr
;
iv
=
iv
->
mNext
)
...
@@ -168,7 +169,7 @@ std::ostream& operator<<(std::ostream& os, const ItemRow& r)
...
@@ -168,7 +169,7 @@ std::ostream& operator<<(std::ostream& os, const ItemRow& r)
os
<<
','
;
os
<<
','
;
}
}
os
<<
']'
;
os
<<
']'
;
return
os
;
return
os
;
}
}
...
@@ -219,10 +220,10 @@ void ItemRow::drop(size_t columnIx)
...
@@ -219,10 +220,10 @@ void ItemRow::drop(size_t columnIx)
#endif
#endif
}
}
const
char
*
ItemRow
::
c_str
(
size_t
columnIx
)
const
const
char
*
ItemRow
::
c_str
(
size_t
columnIx
)
const
{
{
const
char
*
result
=
kEmptyResult
;
const
char
*
result
=
kEmptyResult
;
for
(
auto
v
=
mValues
;
v
!=
nullptr
;
v
=
v
->
mNext
)
for
(
auto
v
=
mValues
;
v
!=
nullptr
;
v
=
v
->
mNext
)
{
{
if
(
v
->
mColumnIndex
==
columnIx
)
if
(
v
->
mColumnIndex
==
columnIx
)
...
@@ -240,119 +241,121 @@ const char* ItemRow::c_str(size_t columnIx) const
...
@@ -240,119 +241,121 @@ const char* ItemRow::c_str(size_t columnIx) const
namespace
detail
namespace
detail
{
{
ItemReference
&
ItemReference
::
operator
=
(
const
std
::
string
&
value
)
ItemReference
&
ItemReference
::
operator
=
(
const
std
::
string
&
value
)
{
{
if
(
mConst
)
if
(
mConst
)
throw
std
::
logic_error
(
"Attempt to write to a constant row"
);
throw
std
::
logic_error
(
"Attempt to write to a constant row"
);
if
(
mRow
.
mData
==
nullptr
)
if
(
mRow
.
mData
==
nullptr
)
throw
std
::
logic_error
(
"Attempt to write to an uninitialized row"
);
throw
std
::
logic_error
(
"Attempt to write to an uninitialized row"
);
mRow
.
assign
(
mName
,
value
,
false
);
mRow
.
assign
(
mName
,
value
,
false
);
return
*
this
;
return
*
this
;
}
}
const
char
*
ItemReference
::
c_str
()
const
const
char
*
ItemReference
::
c_str
()
const
{
const
char
*
result
=
kEmptyResult
;
if
(
mRow
.
mData
!=
nullptr
/* and mRow.mData->mCategory != nullptr*/
)
{
{
// assert(mRow.mData->mCategory)
;
const
char
*
result
=
kEmptyResult
;
for
(
auto
iv
=
mRow
.
mData
->
mValues
;
iv
!=
nullptr
;
iv
=
iv
->
mNext
)
if
(
mRow
.
mData
!=
nullptr
/* and mRow.mData->mCategory != nullptr*/
)
{
{
if
(
iv
->
mColumnIndex
==
mColumn
)
// assert(mRow.mData->mCategory);
for
(
auto
iv
=
mRow
.
mData
->
mValues
;
iv
!=
nullptr
;
iv
=
iv
->
mNext
)
{
{
if
(
iv
->
mText
[
0
]
!=
'.'
or
iv
->
mText
[
1
]
!=
0
)
if
(
iv
->
mColumnIndex
==
mColumn
)
result
=
iv
->
mText
;
{
if
(
iv
->
mText
[
0
]
!=
'.'
or
iv
->
mText
[
1
]
!=
0
)
break
;
result
=
iv
->
mText
;
break
;
}
}
}
}
}
return
result
;
}
}
return
result
;
}
const
char
*
ItemReference
::
c_str
(
const
char
*
defaultValue
)
const
const
char
*
ItemReference
::
c_str
(
const
char
*
defaultValue
)
const
{
const
char
*
result
=
defaultValue
;
if
(
mRow
.
mData
!=
nullptr
and
mRow
.
mData
->
mCategory
!=
nullptr
)
{
{
for
(
auto
iv
=
mRow
.
mData
->
mValues
;
iv
!=
nullptr
;
iv
=
iv
->
mNext
)
const
char
*
result
=
defaultValue
;
if
(
mRow
.
mData
!=
nullptr
and
mRow
.
mData
->
mCategory
!=
nullptr
)
{
{
if
(
iv
->
mColumnIndex
==
mColumn
)
for
(
auto
iv
=
mRow
.
mData
->
mValues
;
iv
!=
nullptr
;
iv
=
iv
->
mNext
)
{
{
// only really non-empty values
if
(
iv
->
mColumnIndex
==
mColumn
)
if
(
iv
->
mText
[
0
]
!=
0
and
((
iv
->
mText
[
0
]
!=
'.'
and
iv
->
mText
[
0
]
!=
'?'
)
or
iv
->
mText
[
1
]
!=
0
))
{
result
=
iv
->
mText
;
// only really non-empty values
if
(
iv
->
mText
[
0
]
!=
0
and
((
iv
->
mText
[
0
]
!=
'.'
and
iv
->
mText
[
0
]
!=
'?'
)
or
iv
->
mText
[
1
]
!=
0
))
result
=
iv
->
mText
;
break
;
break
;
}
}
}
}
if
(
result
==
defaultValue
and
mColumn
<
mRow
.
mData
->
mCategory
->
mColumns
.
size
())
// not found, perhaps the category has a default defined?
if
(
result
==
defaultValue
and
mColumn
<
mRow
.
mData
->
mCategory
->
mColumns
.
size
())
// not found, perhaps the category has a default defined?
{
{
auto
iv
=
mRow
.
mData
->
mCategory
->
mColumns
[
mColumn
].
mValidator
;
auto
iv
=
mRow
.
mData
->
mCategory
->
mColumns
[
mColumn
].
mValidator
;
if
(
iv
!=
nullptr
and
not
iv
->
mDefault
.
empty
())
if
(
iv
!=
nullptr
and
not
iv
->
mDefault
.
empty
())
result
=
iv
->
mDefault
.
c_str
();
result
=
iv
->
mDefault
.
c_str
();
}
}
}
return
result
;
}
}
return
result
;
}
bool
ItemReference
::
empty
()
const
bool
ItemReference
::
empty
()
const
{
{
return
c_str
()
==
kEmptyResult
;
return
c_str
()
==
kEmptyResult
;
}
}
bool
ItemReference
::
is_null
()
const
bool
ItemReference
::
is_null
()
const
{
boost
::
tribool
result
;
if
(
mRow
.
mData
!=
nullptr
and
mRow
.
mData
->
mCategory
!=
nullptr
)
{
{
for
(
auto
iv
=
mRow
.
mData
->
mValues
;
iv
!=
nullptr
;
iv
=
iv
->
mNext
)
boost
::
tribool
result
;
if
(
mRow
.
mData
!=
nullptr
and
mRow
.
mData
->
mCategory
!=
nullptr
)
{
{
if
(
iv
->
mColumnIndex
==
mColumn
)
for
(
auto
iv
=
mRow
.
mData
->
mValues
;
iv
!=
nullptr
;
iv
=
iv
->
mNext
)
{
{
result
=
iv
->
mText
[
0
]
==
'.'
and
iv
->
mText
[
1
]
==
0
;
if
(
iv
->
mColumnIndex
==
mColumn
)
break
;
{
result
=
iv
->
mText
[
0
]
==
'.'
and
iv
->
mText
[
1
]
==
0
;
break
;
}
}
}
}
if
(
result
==
boost
::
indeterminate
and
mColumn
<
mRow
.
mData
->
mCategory
->
mColumns
.
size
())
// not found, perhaps the category has a default defined?
if
(
result
==
boost
::
indeterminate
and
mColumn
<
mRow
.
mData
->
mCategory
->
mColumns
.
size
())
// not found, perhaps the category has a default defined?
{
{
auto
iv
=
mRow
.
mData
->
mCategory
->
mColumns
[
mColumn
].
mValidator
;
auto
iv
=
mRow
.
mData
->
mCategory
->
mColumns
[
mColumn
].
mValidator
;
if
(
iv
!=
nullptr
)
if
(
iv
!=
nullptr
)
result
=
iv
->
mDefaultIsNull
;
result
=
iv
->
mDefaultIsNull
;
}
}
}
return
result
?
true
:
false
;
}
}
return
result
?
true
:
false
;
}
void
ItemReference
::
swap
(
ItemReference
&
b
)
void
ItemReference
::
swap
(
ItemReference
&
b
)
{
{
Row
::
swap
(
mColumn
,
mRow
.
mData
,
b
.
mRow
.
mData
);
Row
::
swap
(
mColumn
,
mRow
.
mData
,
b
.
mRow
.
mData
);
}
}
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
ItemReference
&
item
)
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
ItemReference
&
item
)
{
{
os
<<
item
.
c_str
();
os
<<
item
.
c_str
();
return
os
;
return
os
;
}
}
}
}
// namespace detail
// --------------------------------------------------------------------
// --------------------------------------------------------------------
// Datablock implementation
// Datablock implementation
Datablock
::
Datablock
(
const
std
::
string
&
name
)
Datablock
::
Datablock
(
const
std
::
string
&
name
)
:
mName
(
name
),
mValidator
(
nullptr
),
mNext
(
nullptr
)
:
mName
(
name
)
,
mValidator
(
nullptr
)
,
mNext
(
nullptr
)
{
{
}
}
...
@@ -361,18 +364,18 @@ Datablock::~Datablock()
...
@@ -361,18 +364,18 @@ Datablock::~Datablock()
delete
mNext
;
delete
mNext
;
}
}
std
::
string
Datablock
::
firstItem
(
const
std
::
string
&
tag
)
const
std
::
string
Datablock
::
firstItem
(
const
std
::
string
&
tag
)
const
{
{
std
::
string
result
;
std
::
string
result
;
std
::
string
catName
,
itemName
;
std
::
string
catName
,
itemName
;
std
::
tie
(
catName
,
itemName
)
=
splitTagName
(
tag
);
std
::
tie
(
catName
,
itemName
)
=
splitTagName
(
tag
);
for
(
auto
&
cat
:
mCategories
)
for
(
auto
&
cat
:
mCategories
)
{
{
if
(
iequals
(
cat
.
name
(),
catName
))
if
(
iequals
(
cat
.
name
(),
catName
))
{
{
for
(
auto
row
:
cat
)
for
(
auto
row
:
cat
)
{
{
result
=
row
[
itemName
].
as
<
std
::
string
>
();
result
=
row
[
itemName
].
as
<
std
::
string
>
();
break
;
break
;
...
@@ -385,33 +388,41 @@ std::string Datablock::firstItem(const std::string& tag) const
...
@@ -385,33 +388,41 @@ std::string Datablock::firstItem(const std::string& tag) const
return
result
;
return
result
;
}
}
auto
Datablock
::
emplace
(
const
std
::
string
&
name
)
->
std
::
tuple
<
iterator
,
bool
>
auto
Datablock
::
emplace
(
const
std
::
string
&
name
)
->
std
::
tuple
<
iterator
,
bool
>
{
{
bool
isNew
=
false
;
bool
isNew
=
false
;
iterator
i
=
find_if
(
begin
(),
end
(),
[
name
](
const
Category
&
cat
)
->
bool
iterator
i
=
find_if
(
begin
(),
end
(),
[
name
](
const
Category
&
cat
)
->
bool
{
return
iequals
(
cat
.
name
(),
name
);
});
{
return
iequals
(
cat
.
name
(),
name
);
});
if
(
i
==
end
())
if
(
i
==
end
())
{
{
isNew
=
true
;
isNew
=
true
;
i
=
mCategories
.
emplace
(
end
(),
*
this
,
name
,
mValidator
);
i
=
mCategories
.
emplace
(
end
(),
*
this
,
name
,
mValidator
);
}
}
return
std
::
make_tuple
(
i
,
isNew
);
return
std
::
make_tuple
(
i
,
isNew
);
}
}
Category
&
Datablock
::
operator
[](
const
std
::
string
&
name
)
Category
&
Datablock
::
operator
[](
const
std
::
string
&
name
)
{
{
iterator
i
;
iterator
i
;
std
::
tie
(
i
,
std
::
ignore
)
=
emplace
(
name
);
std
::
tie
(
i
,
std
::
ignore
)
=
emplace
(
name
);
return
*
i
;
return
*
i
;
}
}
Category
*
Datablock
::
get
(
const
std
::
string
&
name
)
Category
*
Datablock
::
get
(
const
std
::
string
&
name
)
{
{
auto
i
=
find_if
(
begin
(),
end
(),
[
name
](
const
Category
&
cat
)
->
bool
auto
i
=
find_if
(
begin
(),
end
(),
[
name
](
const
Category
&
cat
)
->
bool
{
return
iequals
(
cat
.
name
(),
name
);
});
{
return
iequals
(
cat
.
name
(),
name
);
});
return
i
==
end
()
?
nullptr
:
&*
i
;
}
const
Category
*
Datablock
::
get
(
const
std
::
string
&
name
)
const
{
auto
i
=
find_if
(
begin
(),
end
(),
[
name
](
const
Category
&
cat
)
->
bool
{
return
iequals
(
cat
.
name
(),
name
);
});
return
i
==
end
()
?
nullptr
:
&*
i
;
return
i
==
end
()
?
nullptr
:
&*
i
;
}
}
...
@@ -421,188 +432,257 @@ bool Datablock::isValid()
...
@@ -421,188 +432,257 @@ bool Datablock::isValid()
throw
std
::
runtime_error
(
"Validator not specified"
);
throw
std
::
runtime_error
(
"Validator not specified"
);
bool
result
=
true
;
bool
result
=
true
;
for
(
auto
&
cat
:
*
this
)
for
(
auto
&
cat
:
*
this
)
result
=
cat
.
isValid
()
and
result
;
result
=
cat
.
isValid
()
and
result
;
return
result
;
return
result
;
}
}
void
Datablock
::
validateLinks
()
const
void
Datablock
::
validateLinks
()
const
{
{
for
(
auto
&
cat
:
*
this
)
for
(
auto
&
cat
:
*
this
)
cat
.
validateLinks
();
cat
.
validateLinks
();
}
}
void
Datablock
::
setValidator
(
Validator
*
v
)
void
Datablock
::
setValidator
(
Validator
*
v
)
{
{
mValidator
=
v
;
mValidator
=
v
;
for
(
auto
&
cat
:
*
this
)
for
(
auto
&
cat
:
*
this
)
cat
.
setValidator
(
v
);
cat
.
setValidator
(
v
);
}
}
void
Datablock
::
add_software
(
const
std
::
string
&
name
,
const
std
::
string
&
classification
,
const
std
::
string
&
versionNr
,
const
std
::
string
&
versionDate
)
void
Datablock
::
add_software
(
const
std
::
string
&
name
,
const
std
::
string
&
classification
,
const
std
::
string
&
versionNr
,
const
std
::
string
&
versionDate
)
{
{
Category
&
cat
=
operator
[](
"software"
);
Category
&
cat
=
operator
[](
"software"
);
auto
ordNr
=
cat
.
size
()
+
1
;
auto
ordNr
=
cat
.
size
()
+
1
;
// TODO: should we check this ordinal number???
// TODO: should we check this ordinal number???
cat
.
emplace
({
cat
.
emplace
({{
"pdbx_ordinal"
,
ordNr
},
{
"pdbx_ordinal"
,
ordNr
},
{
"name"
,
name
},
{
"name"
,
name
},
{
"version"
,
versionNr
},
{
"version"
,
versionNr
},
{
"date"
,
versionDate
},
{
"date"
,
versionDate
},
{
"classification"
,
classification
}});
{
"classification"
,
classification
}
});
}
}
void
Datablock
::
getTagOrder
(
std
::
vector
<
std
::
string
>
&
tags
)
const
void
Datablock
::
getTagOrder
(
std
::
vector
<
std
::
string
>
&
tags
)
const
{
{
for
(
auto
&
cat
:
*
this
)
for
(
auto
&
cat
:
*
this
)
cat
.
getTagOrder
(
tags
);
cat
.
getTagOrder
(
tags
);
}
}
void
Datablock
::
write
(
std
::
ostream
&
os
)
void
Datablock
::
write
(
std
::
ostream
&
os
)
{
{
os
<<
"data_"
<<
mName
<<
std
::
endl
os
<<
"data_"
<<
mName
<<
std
::
endl
<<
"# "
<<
std
::
endl
;
<<
"# "
<<
std
::
endl
;
// mmcif support, sort of. First write the 'entry' Category
// mmcif support, sort of. First write the 'entry' Category
// and if it exists, _AND_ we have a Validator, write out the
// and if it exists, _AND_ we have a Validator, write out the
// audit_conform record.
// audit_conform record.
for
(
auto
&
cat
:
mCategories
)
for
(
auto
&
cat
:
mCategories
)
{
{
if
(
cat
.
name
()
==
"entry"
)
if
(
cat
.
name
()
==
"entry"
)
{
{
cat
.
write
(
os
);
cat
.
write
(
os
);
if
(
mValidator
!=
nullptr
)
if
(
mValidator
!=
nullptr
)
{
{
Category
auditConform
(
*
this
,
"audit_conform"
,
nullptr
);
Category
auditConform
(
*
this
,
"audit_conform"
,
nullptr
);
auditConform
.
emplace
({
auditConform
.
emplace
({{
"dict_name"
,
mValidator
->
dictName
()},
{
"dict_name"
,
mValidator
->
dictName
()
},
{
"dict_version"
,
mValidator
->
dictVersion
()}});
{
"dict_version"
,
mValidator
->
dictVersion
()
}
});
auditConform
.
write
(
os
);
auditConform
.
write
(
os
);
}
}
break
;
break
;
}
}
}
}
for
(
auto
&
cat
:
mCategories
)
for
(
auto
&
cat
:
mCategories
)
{
{
if
(
cat
.
name
()
!=
"entry"
and
cat
.
name
()
!=
"audit_conform"
)
if
(
cat
.
name
()
!=
"entry"
and
cat
.
name
()
!=
"audit_conform"
)
cat
.
write
(
os
);
cat
.
write
(
os
);
}
}
}
}
void
Datablock
::
write
(
std
::
ostream
&
os
,
const
std
::
vector
<
std
::
string
>&
order
)
void
Datablock
::
write
(
std
::
ostream
&
os
,
const
std
::
vector
<
std
::
string
>
&
order
)
{
{
os
<<
"data_"
<<
mName
<<
std
::
endl
os
<<
"data_"
<<
mName
<<
std
::
endl
<<
"# "
<<
std
::
endl
;
<<
"# "
<<
std
::
endl
;
std
::
vector
<
std
::
string
>
catOrder
;
std
::
vector
<
std
::
string
>
catOrder
;
for
(
auto
&
o
:
order
)
for
(
auto
&
o
:
order
)
{
{
std
::
string
cat
,
Item
;
std
::
string
cat
,
Item
;
std
::
tie
(
cat
,
Item
)
=
splitTagName
(
o
);
std
::
tie
(
cat
,
Item
)
=
splitTagName
(
o
);
if
(
find_if
(
catOrder
.
rbegin
(),
catOrder
.
rend
(),
[
cat
](
const
std
::
string
&
s
)
->
bool
{
return
iequals
(
cat
,
s
);
})
==
catOrder
.
rend
())
if
(
find_if
(
catOrder
.
rbegin
(),
catOrder
.
rend
(),
[
cat
](
const
std
::
string
&
s
)
->
bool
{
return
iequals
(
cat
,
s
);
})
==
catOrder
.
rend
())
catOrder
.
push_back
(
cat
);
catOrder
.
push_back
(
cat
);
}
}
for
(
auto
&
c
:
catOrder
)
for
(
auto
&
c
:
catOrder
)
{
{
auto
cat
=
get
(
c
);
auto
cat
=
get
(
c
);
if
(
cat
==
nullptr
)
if
(
cat
==
nullptr
)
continue
;
continue
;
std
::
vector
<
std
::
string
>
items
;
std
::
vector
<
std
::
string
>
items
;
for
(
auto
&
o
:
order
)
for
(
auto
&
o
:
order
)
{
{
std
::
string
catName
,
Item
;
std
::
string
catName
,
Item
;
std
::
tie
(
catName
,
Item
)
=
splitTagName
(
o
);
std
::
tie
(
catName
,
Item
)
=
splitTagName
(
o
);
if
(
catName
==
c
)
if
(
catName
==
c
)
items
.
push_back
(
Item
);
items
.
push_back
(
Item
);
}
}
cat
->
write
(
os
,
items
);
cat
->
write
(
os
,
items
);
}
}
// for any Category we missed in the catOrder
// for any Category we missed in the catOrder
for
(
auto
&
cat
:
mCategories
)
for
(
auto
&
cat
:
mCategories
)
{
{
if
(
find_if
(
catOrder
.
begin
(),
catOrder
.
end
(),
[
&
](
const
std
::
string
&
s
)
->
bool
{
return
iequals
(
cat
.
name
(),
s
);
})
!=
catOrder
.
end
())
if
(
find_if
(
catOrder
.
begin
(),
catOrder
.
end
(),
[
&
](
const
std
::
string
&
s
)
->
bool
{
return
iequals
(
cat
.
name
(),
s
);
})
!=
catOrder
.
end
())
continue
;
continue
;
cat
.
write
(
os
);
cat
.
write
(
os
);
}
}
// // mmcif support, sort of. First write the 'entry' Category
// // and if it exists, _AND_ we have a Validator, write out the
// // auditConform record.
//
// for (auto& cat: mCategories)
// {
// if (cat.name() == "entry")
// {
// cat.write(os);
//
// if (mValidator != nullptr)
// {
// Category auditConform(*this, "audit_conform", nullptr);
// auditConform.emplace({
// { "dict_name", mValidator->dictName() },
// { "dict_version", mValidator->dictVersion() }
// });
// auditConform.write(os);
// }
//
// break;
// }
// }
//
// for (auto& cat: mCategories)
// {
// if (cat.name() != "entry" and cat.name() != "audit_conform")
// cat.write(os);
// }
}
// --------------------------------------------------------------------
// // mmcif support, sort of. First write the 'entry' Category
//
// // and if it exists, _AND_ we have a Validator, write out the
// // auditConform record.
//
// for (auto& cat: mCategories)
// {
// if (cat.name() == "entry")
// {
// cat.write(os);
//
// if (mValidator != nullptr)
// {
// Category auditConform(*this, "audit_conform", nullptr);
// auditConform.emplace({
// { "dict_name", mValidator->dictName() },
// { "dict_version", mValidator->dictVersion() }
// });
// auditConform.write(os);
// }
//
// break;
// }
// }
//
// for (auto& cat: mCategories)
// {
// if (cat.name() != "entry" and cat.name() != "audit_conform")
// cat.write(os);
// }
}
namespace
detail
bool
operator
==
(
const
cif
::
Datablock
&
dbA
,
const
cif
::
Datablock
&
dbB
)
{
{
std
::
vector
<
std
::
string
>
catA
,
catB
;
void
KeyCompareConditionImpl
::
prepare
(
const
Category
&
c
)
for
(
auto
&
cat
:
dbA
)
{
{
mItemIx
=
c
.
getColumnIndex
(
mItemTag
);
if
(
not
cat
.
empty
())
catA
.
push_back
(
cat
.
name
());
}
sort
(
catA
.
begin
(),
catA
.
end
());
for
(
auto
&
cat
:
dbB
)
{
if
(
not
cat
.
empty
())
catB
.
push_back
(
cat
.
name
());
}
sort
(
catB
.
begin
(),
catB
.
end
());
// loop over categories twice, to group output
// First iteration is to list missing categories.
std
::
vector
<
std
::
string
>
missingA
,
missingB
;
auto
catA_i
=
catA
.
begin
(),
catB_i
=
catB
.
begin
();
while
(
catA_i
!=
catA
.
end
()
and
catB_i
!=
catB
.
end
())
{
if
(
not
iequals
(
*
catA_i
,
*
catB_i
))
return
false
;
++
catA_i
,
++
catB_i
;
}
if
(
catA_i
!=
catA
.
end
()
or
catB_i
!=
catB
.
end
())
return
false
;
// Second loop, now compare category values
catA_i
=
catA
.
begin
(),
catB_i
=
catB
.
begin
();
auto
cv
=
c
.
getCatValidator
();
while
(
catA_i
!=
catA
.
end
()
and
catB_i
!=
catB
.
end
())
if
(
cv
)
{
{
auto
iv
=
cv
->
getValidatorForItem
(
mItemTag
);
std
::
string
nA
=
*
catA_i
;
if
(
iv
!=
nullptr
and
iv
->
mType
!=
nullptr
)
ba
::
to_lower
(
nA
);
std
::
string
nB
=
*
catB_i
;
ba
::
to_lower
(
nB
);
int
d
=
nA
.
compare
(
nB
);
if
(
d
>
0
)
++
catB_i
;
else
if
(
d
<
0
)
++
catA_i
;
else
{
{
auto
type
=
iv
->
mType
;
if
(
not
(
*
dbA
.
get
(
*
catA_i
)
==
*
dbB
.
get
(
*
catB_i
)))
mCaseInsensitive
=
type
->
mPrimitiveType
==
DDL_PrimitiveType
::
UChar
;
return
false
;
++
catA_i
;
++
catB_i
;
}
}
}
}
return
true
;
}
}
void
KeyIsEmptyConditionImpl
::
prepare
(
const
Category
&
c
)
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
Datablock
&
data
)
{
{
mItemIx
=
c
.
getColumnIndex
(
mItemTag
);
// whoohoo... this sucks!
const_cast
<
Datablock
&>
(
data
).
write
(
os
);
return
os
;
}
}
void
KeyMatchesConditionImpl
::
prepare
(
const
Category
&
c
)
// --------------------------------------------------------------------
//
namespace
detail
{
{
mItemIx
=
c
.
getColumnIndex
(
mItemTag
);
}
}
void
KeyCompareConditionImpl
::
prepare
(
const
Category
&
c
)
{
mItemIx
=
c
.
getColumnIndex
(
mItemTag
);
auto
cv
=
c
.
getCatValidator
();
if
(
cv
)
{
auto
iv
=
cv
->
getValidatorForItem
(
mItemTag
);
if
(
iv
!=
nullptr
and
iv
->
mType
!=
nullptr
)
{
auto
type
=
iv
->
mType
;
mCaseInsensitive
=
type
->
mPrimitiveType
==
DDL_PrimitiveType
::
UChar
;
}
}
}
void
KeyIsEmptyConditionImpl
::
prepare
(
const
Category
&
c
)
{
mItemIx
=
c
.
getColumnIndex
(
mItemTag
);
}
void
KeyMatchesConditionImpl
::
prepare
(
const
Category
&
c
)
{
mItemIx
=
c
.
getColumnIndex
(
mItemTag
);
}
}
// namespace detail
// --------------------------------------------------------------------
// --------------------------------------------------------------------
//
//
...
@@ -611,77 +691,76 @@ void KeyMatchesConditionImpl::prepare(const Category& c)
...
@@ -611,77 +691,76 @@ void KeyMatchesConditionImpl::prepare(const Category& c)
class
RowComparator
class
RowComparator
{
{
public
:
public
:
RowComparator
(
Category
*
cat
)
RowComparator
(
Category
*
cat
)
:
RowComparator
(
cat
,
cat
->
getCatValidator
()
->
mKeys
.
begin
(),
cat
->
getCatValidator
()
->
mKeys
.
end
())
:
RowComparator
(
cat
,
cat
->
getCatValidator
()
->
mKeys
.
begin
(),
cat
->
getCatValidator
()
->
mKeys
.
end
())
{
{
}
}
template
<
typename
KeyIter
>
RowComparator
(
Category
*
cat
,
KeyIter
b
,
KeyIter
e
);
int
operator
()(
const
ItemRow
*
a
,
const
ItemRow
*
b
)
const
;
int
operator
()(
const
Row
&
a
,
const
Row
&
b
)
const
template
<
typename
KeyIter
>
RowComparator
(
Category
*
cat
,
KeyIter
b
,
KeyIter
e
);
int
operator
()(
const
ItemRow
*
a
,
const
ItemRow
*
b
)
const
;
int
operator
()(
const
Row
&
a
,
const
Row
&
b
)
const
{
{
return
operator
()(
a
.
mData
,
b
.
mData
);
return
operator
()(
a
.
mData
,
b
.
mData
);
}
}
private
:
private
:
typedef
std
::
function
<
int
(
const
char
*
,
const
char
*
)
>
compareFunc
;
typedef
std
::
function
<
int
(
const
char
*
,
const
char
*
)
>
compareFunc
;
typedef
std
::
tuple
<
size_t
,
compareFunc
>
keyComp
;
typedef
std
::
tuple
<
size_t
,
compareFunc
>
keyComp
;
std
::
vector
<
keyComp
>
mComp
;
std
::
vector
<
keyComp
>
mComp
;
};
};
template
<
typename
KeyIter
>
template
<
typename
KeyIter
>
RowComparator
::
RowComparator
(
Category
*
cat
,
KeyIter
b
,
KeyIter
e
)
RowComparator
::
RowComparator
(
Category
*
cat
,
KeyIter
b
,
KeyIter
e
)
{
{
auto
cv
=
cat
->
getCatValidator
();
auto
cv
=
cat
->
getCatValidator
();
for
(
auto
ki
=
b
;
ki
!=
e
;
++
ki
)
for
(
auto
ki
=
b
;
ki
!=
e
;
++
ki
)
{
{
std
::
string
k
=
*
ki
;
std
::
string
k
=
*
ki
;
size_t
ix
=
cat
->
getColumnIndex
(
k
);
size_t
ix
=
cat
->
getColumnIndex
(
k
);
auto
iv
=
cv
->
getValidatorForItem
(
k
);
auto
iv
=
cv
->
getValidatorForItem
(
k
);
if
(
iv
==
nullptr
)
if
(
iv
==
nullptr
)
throw
std
::
runtime_error
(
"Incomplete dictionary, no Item Validator for Key "
+
k
);
throw
std
::
runtime_error
(
"Incomplete dictionary, no Item Validator for Key "
+
k
);
auto
tv
=
iv
->
mType
;
auto
tv
=
iv
->
mType
;
if
(
tv
==
nullptr
)
if
(
tv
==
nullptr
)
throw
std
::
runtime_error
(
"Incomplete dictionary, no type Validator for Item "
+
k
);
throw
std
::
runtime_error
(
"Incomplete dictionary, no type Validator for Item "
+
k
);
using
namespace
std
::
placeholders
;
using
namespace
std
::
placeholders
;
mComp
.
emplace_back
(
ix
,
std
::
bind
(
&
ValidateType
::
compare
,
tv
,
_1
,
_2
));
mComp
.
emplace_back
(
ix
,
std
::
bind
(
&
ValidateType
::
compare
,
tv
,
_1
,
_2
));
}
}
}
}
int
RowComparator
::
operator
()(
const
ItemRow
*
a
,
const
ItemRow
*
b
)
const
int
RowComparator
::
operator
()(
const
ItemRow
*
a
,
const
ItemRow
*
b
)
const
{
{
assert
(
a
);
assert
(
a
);
assert
(
b
);
assert
(
b
);
int
d
=
0
;
int
d
=
0
;
for
(
auto
&
c
:
mComp
)
for
(
auto
&
c
:
mComp
)
{
{
size_t
k
;
size_t
k
;
compareFunc
f
;
compareFunc
f
;
std
::
tie
(
k
,
f
)
=
c
;
std
::
tie
(
k
,
f
)
=
c
;
const
char
*
ka
=
a
->
c_str
(
k
);
const
char
*
ka
=
a
->
c_str
(
k
);
const
char
*
kb
=
b
->
c_str
(
k
);
const
char
*
kb
=
b
->
c_str
(
k
);
d
=
f
(
ka
,
kb
);
d
=
f
(
ka
,
kb
);
if
(
d
!=
0
)
if
(
d
!=
0
)
break
;
break
;
}
}
return
d
;
return
d
;
}
}
...
@@ -693,148 +772,152 @@ int RowComparator::operator()(const ItemRow* a, const ItemRow* b) const
...
@@ -693,148 +772,152 @@ int RowComparator::operator()(const ItemRow* a, const ItemRow* b) const
class
CatIndex
class
CatIndex
{
{
public
:
public
:
CatIndex
(
Category
*
cat
);
CatIndex
(
Category
*
cat
);
~
CatIndex
();
~
CatIndex
();
ItemRow
*
find
(
ItemRow
*
k
)
const
;
void
insert
(
ItemRow
*
r
);
ItemRow
*
find
(
ItemRow
*
k
)
const
;
void
erase
(
ItemRow
*
r
);
void
insert
(
ItemRow
*
r
);
void
erase
(
ItemRow
*
r
);
// batch create
// batch create
void
reconstruct
();
void
reconstruct
();
// reorder the ItemRow's and returns new head and tail
// reorder the ItemRow's and returns new head and tail
std
::
tuple
<
ItemRow
*
,
ItemRow
*>
reorder
()
std
::
tuple
<
ItemRow
*
,
ItemRow
*>
reorder
()
{
{
std
::
tuple
<
ItemRow
*
,
ItemRow
*>
result
=
std
::
make_tuple
(
nullptr
,
nullptr
);
std
::
tuple
<
ItemRow
*
,
ItemRow
*>
result
=
std
::
make_tuple
(
nullptr
,
nullptr
);
if
(
mRoot
!=
nullptr
)
if
(
mRoot
!=
nullptr
)
{
{
entry
*
head
=
findMin
(
mRoot
);
entry
*
head
=
findMin
(
mRoot
);
entry
*
tail
=
reorder
(
mRoot
);
entry
*
tail
=
reorder
(
mRoot
);
tail
->
mRow
->
mNext
=
nullptr
;
tail
->
mRow
->
mNext
=
nullptr
;
result
=
std
::
make_tuple
(
head
->
mRow
,
tail
->
mRow
);
result
=
std
::
make_tuple
(
head
->
mRow
,
tail
->
mRow
);
}
}
return
result
;
return
result
;
}
}
size_t
size
()
const
;
size_t
size
()
const
;
// bool isValid() const;
// bool isValid() const;
private
:
private
:
struct
entry
struct
entry
{
{
entry
(
ItemRow
*
r
)
entry
(
ItemRow
*
r
)
:
mRow
(
r
),
mLeft
(
nullptr
),
mRight
(
nullptr
),
mRed
(
true
)
{}
:
mRow
(
r
)
,
mLeft
(
nullptr
)
,
mRight
(
nullptr
)
,
mRed
(
true
)
{
}
~
entry
()
~
entry
()
{
{
delete
mLeft
;
delete
mLeft
;
delete
mRight
;
delete
mRight
;
}
}
ItemRow
*
mRow
;
ItemRow
*
mRow
;
entry
*
mLeft
;
entry
*
mLeft
;
entry
*
mRight
;
entry
*
mRight
;
bool
mRed
;
bool
mRed
;
};
};
entry
*
insert
(
entry
*
h
,
ItemRow
*
v
);
entry
*
insert
(
entry
*
h
,
ItemRow
*
v
);
entry
*
erase
(
entry
*
h
,
ItemRow
*
k
);
entry
*
erase
(
entry
*
h
,
ItemRow
*
k
);
// void validate(entry* h, bool isParentRed, uint32_t blackDepth, uint32_t& minBlack, uint32_t& maxBlack) const;
// void validate(entry* h, bool isParentRed, uint32_t blackDepth, uint32_t& minBlack, uint32_t& maxBlack) const;
entry
*
rotateLeft
(
entry
*
h
)
entry
*
rotateLeft
(
entry
*
h
)
{
{
entry
*
x
=
h
->
mRight
;
entry
*
x
=
h
->
mRight
;
h
->
mRight
=
x
->
mLeft
;
h
->
mRight
=
x
->
mLeft
;
x
->
mLeft
=
h
;
x
->
mLeft
=
h
;
x
->
mRed
=
h
->
mRed
;
x
->
mRed
=
h
->
mRed
;
h
->
mRed
=
true
;
h
->
mRed
=
true
;
return
x
;
return
x
;
}
}
entry
*
rotateRight
(
entry
*
h
)
entry
*
rotateRight
(
entry
*
h
)
{
{
entry
*
x
=
h
->
mLeft
;
entry
*
x
=
h
->
mLeft
;
h
->
mLeft
=
x
->
mRight
;
h
->
mLeft
=
x
->
mRight
;
x
->
mRight
=
h
;
x
->
mRight
=
h
;
x
->
mRed
=
h
->
mRed
;
x
->
mRed
=
h
->
mRed
;
h
->
mRed
=
true
;
h
->
mRed
=
true
;
return
x
;
return
x
;
}
}
void
flipColour
(
entry
*
h
)
void
flipColour
(
entry
*
h
)
{
{
h
->
mRed
=
not
h
->
mRed
;
h
->
mRed
=
not
h
->
mRed
;
if
(
h
->
mLeft
!=
nullptr
)
if
(
h
->
mLeft
!=
nullptr
)
h
->
mLeft
->
mRed
=
not
h
->
mLeft
->
mRed
;
h
->
mLeft
->
mRed
=
not
h
->
mLeft
->
mRed
;
if
(
h
->
mRight
!=
nullptr
)
if
(
h
->
mRight
!=
nullptr
)
h
->
mRight
->
mRed
=
not
h
->
mRight
->
mRed
;
h
->
mRight
->
mRed
=
not
h
->
mRight
->
mRed
;
}
}
bool
isRed
(
entry
*
h
)
const
bool
isRed
(
entry
*
h
)
const
{
{
return
h
!=
nullptr
and
h
->
mRed
;
return
h
!=
nullptr
and
h
->
mRed
;
}
}
entry
*
moveRedLeft
(
entry
*
h
)
entry
*
moveRedLeft
(
entry
*
h
)
{
{
flipColour
(
h
);
flipColour
(
h
);
if
(
h
->
mRight
!=
nullptr
and
isRed
(
h
->
mRight
->
mLeft
))
if
(
h
->
mRight
!=
nullptr
and
isRed
(
h
->
mRight
->
mLeft
))
{
{
h
->
mRight
=
rotateRight
(
h
->
mRight
);
h
->
mRight
=
rotateRight
(
h
->
mRight
);
h
=
rotateLeft
(
h
);
h
=
rotateLeft
(
h
);
flipColour
(
h
);
flipColour
(
h
);
}
}
return
h
;
return
h
;
}
}
entry
*
moveRedRight
(
entry
*
h
)
entry
*
moveRedRight
(
entry
*
h
)
{
{
flipColour
(
h
);
flipColour
(
h
);
if
(
h
->
mLeft
!=
nullptr
and
isRed
(
h
->
mLeft
->
mLeft
))
if
(
h
->
mLeft
!=
nullptr
and
isRed
(
h
->
mLeft
->
mLeft
))
{
{
h
=
rotateRight
(
h
);
h
=
rotateRight
(
h
);
flipColour
(
h
);
flipColour
(
h
);
}
}
return
h
;
return
h
;
}
}
entry
*
fixUp
(
entry
*
h
)
entry
*
fixUp
(
entry
*
h
)
{
{
if
(
isRed
(
h
->
mRight
))
if
(
isRed
(
h
->
mRight
))
h
=
rotateLeft
(
h
);
h
=
rotateLeft
(
h
);
if
(
isRed
(
h
->
mLeft
)
and
isRed
(
h
->
mLeft
->
mLeft
))
if
(
isRed
(
h
->
mLeft
)
and
isRed
(
h
->
mLeft
->
mLeft
))
h
=
rotateRight
(
h
);
h
=
rotateRight
(
h
);
if
(
isRed
(
h
->
mLeft
)
and
isRed
(
h
->
mRight
))
if
(
isRed
(
h
->
mLeft
)
and
isRed
(
h
->
mRight
))
flipColour
(
h
);
flipColour
(
h
);
return
h
;
return
h
;
}
}
entry
*
findMin
(
entry
*
h
)
entry
*
findMin
(
entry
*
h
)
{
{
while
(
h
->
mLeft
!=
nullptr
)
while
(
h
->
mLeft
!=
nullptr
)
h
=
h
->
mLeft
;
h
=
h
->
mLeft
;
return
h
;
return
h
;
}
}
entry
*
eraseMin
(
entry
*
h
)
entry
*
eraseMin
(
entry
*
h
)
{
{
if
(
h
->
mLeft
==
nullptr
)
if
(
h
->
mLeft
==
nullptr
)
{
{
...
@@ -845,44 +928,46 @@ class CatIndex
...
@@ -845,44 +928,46 @@ class CatIndex
{
{
if
(
not
isRed
(
h
->
mLeft
)
and
not
isRed
(
h
->
mLeft
->
mLeft
))
if
(
not
isRed
(
h
->
mLeft
)
and
not
isRed
(
h
->
mLeft
->
mLeft
))
h
=
moveRedLeft
(
h
);
h
=
moveRedLeft
(
h
);
h
->
mLeft
=
eraseMin
(
h
->
mLeft
);
h
->
mLeft
=
eraseMin
(
h
->
mLeft
);
h
=
fixUp
(
h
);
h
=
fixUp
(
h
);
}
}
return
h
;
return
h
;
}
}
// Fix mNext fields for rows in order of this index
// Fix mNext fields for rows in order of this index
entry
*
reorder
(
entry
*
e
)
entry
*
reorder
(
entry
*
e
)
{
{
auto
result
=
e
;
auto
result
=
e
;
if
(
e
->
mLeft
!=
nullptr
)
if
(
e
->
mLeft
!=
nullptr
)
{
{
auto
l
=
reorder
(
e
->
mLeft
);
auto
l
=
reorder
(
e
->
mLeft
);
l
->
mRow
->
mNext
=
e
->
mRow
;
l
->
mRow
->
mNext
=
e
->
mRow
;
}
}
if
(
e
->
mRight
!=
nullptr
)
if
(
e
->
mRight
!=
nullptr
)
{
{
auto
mr
=
findMin
(
e
->
mRight
);
auto
mr
=
findMin
(
e
->
mRight
);
e
->
mRow
->
mNext
=
mr
->
mRow
;
e
->
mRow
->
mNext
=
mr
->
mRow
;
result
=
reorder
(
e
->
mRight
);
result
=
reorder
(
e
->
mRight
);
}
}
return
result
;
return
result
;
}
}
Category
&
mCat
;
Category
&
mCat
;
RowComparator
mComp
;
RowComparator
mComp
;
entry
*
mRoot
;
entry
*
mRoot
;
};
};
CatIndex
::
CatIndex
(
Category
*
cat
)
CatIndex
::
CatIndex
(
Category
*
cat
)
:
mCat
(
*
cat
),
mComp
(
cat
),
mRoot
(
nullptr
)
:
mCat
(
*
cat
)
,
mComp
(
cat
)
,
mRoot
(
nullptr
)
{
{
}
}
...
@@ -891,9 +976,9 @@ CatIndex::~CatIndex()
...
@@ -891,9 +976,9 @@ CatIndex::~CatIndex()
delete
mRoot
;
delete
mRoot
;
}
}
ItemRow
*
CatIndex
::
find
(
ItemRow
*
k
)
const
ItemRow
*
CatIndex
::
find
(
ItemRow
*
k
)
const
{
{
const
entry
*
r
=
mRoot
;
const
entry
*
r
=
mRoot
;
while
(
r
!=
nullptr
)
while
(
r
!=
nullptr
)
{
{
int
d
=
mComp
(
k
,
r
->
mRow
);
int
d
=
mComp
(
k
,
r
->
mRow
);
...
@@ -904,24 +989,26 @@ ItemRow* CatIndex::find(ItemRow* k) const
...
@@ -904,24 +989,26 @@ ItemRow* CatIndex::find(ItemRow* k) const
else
else
break
;
break
;
}
}
return
r
?
r
->
mRow
:
nullptr
;
return
r
?
r
->
mRow
:
nullptr
;
}
}
void
CatIndex
::
insert
(
ItemRow
*
k
)
void
CatIndex
::
insert
(
ItemRow
*
k
)
{
{
mRoot
=
insert
(
mRoot
,
k
);
mRoot
=
insert
(
mRoot
,
k
);
mRoot
->
mRed
=
false
;
mRoot
->
mRed
=
false
;
}
}
CatIndex
::
entry
*
CatIndex
::
insert
(
entry
*
h
,
ItemRow
*
v
)
CatIndex
::
entry
*
CatIndex
::
insert
(
entry
*
h
,
ItemRow
*
v
)
{
{
if
(
h
==
nullptr
)
if
(
h
==
nullptr
)
return
new
entry
(
v
);
return
new
entry
(
v
);
int
d
=
mComp
(
v
,
h
->
mRow
);
int
d
=
mComp
(
v
,
h
->
mRow
);
if
(
d
<
0
)
h
->
mLeft
=
insert
(
h
->
mLeft
,
v
);
if
(
d
<
0
)
else
if
(
d
>
0
)
h
->
mRight
=
insert
(
h
->
mRight
,
v
);
h
->
mLeft
=
insert
(
h
->
mLeft
,
v
);
else
if
(
d
>
0
)
h
->
mRight
=
insert
(
h
->
mRight
,
v
);
else
else
throw
std
::
runtime_error
(
"Duplicate Key violation, cat: "
+
mCat
.
name
()
+
" values: "
+
v
->
str
());
throw
std
::
runtime_error
(
"Duplicate Key violation, cat: "
+
mCat
.
name
()
+
" values: "
+
v
->
str
());
...
@@ -930,21 +1017,21 @@ CatIndex::entry* CatIndex::insert(entry* h, ItemRow* v)
...
@@ -930,21 +1017,21 @@ CatIndex::entry* CatIndex::insert(entry* h, ItemRow* v)
if
(
isRed
(
h
->
mLeft
)
and
isRed
(
h
->
mLeft
->
mLeft
))
if
(
isRed
(
h
->
mLeft
)
and
isRed
(
h
->
mLeft
->
mLeft
))
h
=
rotateRight
(
h
);
h
=
rotateRight
(
h
);
if
(
isRed
(
h
->
mLeft
)
and
isRed
(
h
->
mRight
))
if
(
isRed
(
h
->
mLeft
)
and
isRed
(
h
->
mRight
))
flipColour
(
h
);
flipColour
(
h
);
return
h
;
return
h
;
}
}
void
CatIndex
::
erase
(
ItemRow
*
k
)
void
CatIndex
::
erase
(
ItemRow
*
k
)
{
{
mRoot
=
erase
(
mRoot
,
k
);
mRoot
=
erase
(
mRoot
,
k
);
if
(
mRoot
!=
nullptr
)
if
(
mRoot
!=
nullptr
)
mRoot
->
mRed
=
false
;
mRoot
->
mRed
=
false
;
}
}
CatIndex
::
entry
*
CatIndex
::
erase
(
entry
*
h
,
ItemRow
*
k
)
CatIndex
::
entry
*
CatIndex
::
erase
(
entry
*
h
,
ItemRow
*
k
)
{
{
if
(
mComp
(
k
,
h
->
mRow
)
<
0
)
if
(
mComp
(
k
,
h
->
mRow
)
<
0
)
{
{
...
@@ -960,18 +1047,18 @@ CatIndex::entry* CatIndex::erase(entry* h, ItemRow* k)
...
@@ -960,18 +1047,18 @@ CatIndex::entry* CatIndex::erase(entry* h, ItemRow* k)
{
{
if
(
isRed
(
h
->
mLeft
))
if
(
isRed
(
h
->
mLeft
))
h
=
rotateRight
(
h
);
h
=
rotateRight
(
h
);
if
(
mComp
(
k
,
h
->
mRow
)
==
0
and
h
->
mRight
==
nullptr
)
if
(
mComp
(
k
,
h
->
mRow
)
==
0
and
h
->
mRight
==
nullptr
)
{
{
delete
h
;
delete
h
;
return
nullptr
;
return
nullptr
;
}
}
if
(
h
->
mRight
!=
nullptr
)
if
(
h
->
mRight
!=
nullptr
)
{
{
if
(
not
isRed
(
h
->
mRight
)
and
not
isRed
(
h
->
mRight
->
mLeft
))
if
(
not
isRed
(
h
->
mRight
)
and
not
isRed
(
h
->
mRight
->
mLeft
))
h
=
moveRedRight
(
h
);
h
=
moveRedRight
(
h
);
if
(
mComp
(
k
,
h
->
mRow
)
==
0
)
if
(
mComp
(
k
,
h
->
mRow
)
==
0
)
{
{
h
->
mRow
=
findMin
(
h
->
mRight
)
->
mRow
;
h
->
mRow
=
findMin
(
h
->
mRight
)
->
mRow
;
...
@@ -981,7 +1068,7 @@ CatIndex::entry* CatIndex::erase(entry* h, ItemRow* k)
...
@@ -981,7 +1068,7 @@ CatIndex::entry* CatIndex::erase(entry* h, ItemRow* k)
h
->
mRight
=
erase
(
h
->
mRight
,
k
);
h
->
mRight
=
erase
(
h
->
mRight
,
k
);
}
}
}
}
return
fixUp
(
h
);
return
fixUp
(
h
);
}
}
...
@@ -989,133 +1076,133 @@ void CatIndex::reconstruct()
...
@@ -989,133 +1076,133 @@ void CatIndex::reconstruct()
{
{
delete
mRoot
;
delete
mRoot
;
mRoot
=
nullptr
;
mRoot
=
nullptr
;
for
(
auto
r
:
mCat
)
for
(
auto
r
:
mCat
)
insert
(
r
.
mData
);
insert
(
r
.
mData
);
// maybe reconstruction can be done quicker by using the following commented code.
// maybe reconstruction can be done quicker by using the following commented code.
// however, I've not had the time to think of a way to std::set the red/black flag correctly in that case.
// however, I've not had the time to think of a way to std::set the red/black flag correctly in that case.
// std::vector<ItemRow*> rows;
// std::vector<ItemRow*> rows;
// transform(mCat.begin(), mCat.end(), backInserter(rows),
// transform(mCat.begin(), mCat.end(), backInserter(rows),
// [](Row r) -> ItemRow* { assert(r.mData); return r.mData; });
// [](Row r) -> ItemRow* { assert(r.mData); return r.mData; });
//
//
// assert(std::find(rows.begin(), rows.end(), nullptr) == rows.end());
// assert(std::find(rows.begin(), rows.end(), nullptr) == rows.end());
//
//
// // don't use sort here, it will run out of the stack of something.
// // don't use sort here, it will run out of the stack of something.
// // quicksort is notorious for using excessive recursion.
// // quicksort is notorious for using excessive recursion.
// // Besides, most of the time, the data is ordered already anyway.
// // Besides, most of the time, the data is ordered already anyway.
//
//
// stable_sort(rows.begin(), rows.end(), [this](ItemRow* a, ItemRow* b) -> bool { return this->mComp(a, b) < 0; });
// stable_sort(rows.begin(), rows.end(), [this](ItemRow* a, ItemRow* b) -> bool { return this->mComp(a, b) < 0; });
//
//
// for (size_t i = 0; i < rows.size() - 1; ++i)
// for (size_t i = 0; i < rows.size() - 1; ++i)
// assert(mComp(rows[i], rows[i + 1]) < 0);
// assert(mComp(rows[i], rows[i + 1]) < 0);
//
//
// deque<entry*> e;
// deque<entry*> e;
// transform(rows.begin(), rows.end(), back_inserter(e),
// transform(rows.begin(), rows.end(), back_inserter(e),
// [](ItemRow* r) -> entry* { return new entry(r); });
// [](ItemRow* r) -> entry* { return new entry(r); });
//
//
// while (e.size() > 1)
// while (e.size() > 1)
// {
// {
// deque<entry*> ne;
// deque<entry*> ne;
//
//
// while (not e.empty())
// while (not e.empty())
// {
// {
// entry* a = e.front();
// entry* a = e.front();
// e.pop_front();
// e.pop_front();
//
//
// if (e.empty())
// if (e.empty())
// ne.push_back(a);
// ne.push_back(a);
// else
// else
// {
// {
// entry* b = e.front();
// entry* b = e.front();
// b->mLeft = a;
// b->mLeft = a;
//
//
// assert(mComp(a->mRow, b->mRow) < 0);
// assert(mComp(a->mRow, b->mRow) < 0);
//
//
// e.pop_front();
// e.pop_front();
//
//
// if (not e.empty())
// if (not e.empty())
// {
// {
// entry* c = e.front();
// entry* c = e.front();
// e.pop_front();
// e.pop_front();
//
//
// assert(mComp(b->mRow, c->mRow) < 0);
// assert(mComp(b->mRow, c->mRow) < 0);
//
//
// b->mRight = c;
// b->mRight = c;
// }
// }
//
//
// ne.push_back(b);
// ne.push_back(b);
//
//
// if (not e.empty())
// if (not e.empty())
// {
// {
// ne.push_back(e.front());
// ne.push_back(e.front());
// e.pop_front();
// e.pop_front();
// }
// }
// }
// }
// }
// }
//
//
// swap (e, ne);
// swap (e, ne);
// }
// }
//
//
// assert(e.size() == 1);
// assert(e.size() == 1);
// mRoot = e.front();
// mRoot = e.front();
}
}
size_t
CatIndex
::
size
()
const
size_t
CatIndex
::
size
()
const
{
{
std
::
stack
<
entry
*>
s
;
std
::
stack
<
entry
*>
s
;
s
.
push
(
mRoot
);
s
.
push
(
mRoot
);
size_t
result
=
0
;
size_t
result
=
0
;
while
(
not
s
.
empty
())
while
(
not
s
.
empty
())
{
{
entry
*
e
=
s
.
top
();
entry
*
e
=
s
.
top
();
s
.
pop
();
s
.
pop
();
if
(
e
==
nullptr
)
if
(
e
==
nullptr
)
continue
;
continue
;
++
result
;
++
result
;
s
.
push
(
e
->
mLeft
);
s
.
push
(
e
->
mLeft
);
s
.
push
(
e
->
mRight
);
s
.
push
(
e
->
mRight
);
}
}
return
result
;
return
result
;
}
}
//bool CatIndex::isValid() const
//bool CatIndex::isValid() const
//{
//{
// bool result = true;
// bool result = true;
//
//
// if (mRoot != nullptr)
// if (mRoot != nullptr)
// {
// {
// uint32_t minBlack = numeric_limits<uint32_t>::max();
// uint32_t minBlack = numeric_limits<uint32_t>::max();
// uint32_t maxBlack = 0;
// uint32_t maxBlack = 0;
//
//
// assert(not mRoot->mRed);
// assert(not mRoot->mRed);
//
//
// result = isValid(mRoot, false, 0, minBlack, maxBlack);
// result = isValid(mRoot, false, 0, minBlack, maxBlack);
// assert(minBlack == maxBlack);
// assert(minBlack == maxBlack);
// }
// }
//
//
// return result;
// return result;
//}
//}
//
//
//bool CatIndex::validate(entry* h, bool isParentRed, uint32_t blackDepth, uint32_t& minBlack, uint32_t& maxBlack) const
//bool CatIndex::validate(entry* h, bool isParentRed, uint32_t blackDepth, uint32_t& minBlack, uint32_t& maxBlack) const
//{
//{
// bool result = true;
// bool result = true;
//
//
// if (h->mRed)
// if (h->mRed)
// assert(not isParentRed);
// assert(not isParentRed);
// else
// else
// ++blackDepth;
// ++blackDepth;
//
//
// if (isParentRed)
// if (isParentRed)
// assert(not h->mRed);
// assert(not h->mRed);
//
//
// if (h->mLeft != nullptr and h->mRight != nullptr)
// if (h->mLeft != nullptr and h->mRight != nullptr)
// {
// {
// if (isRed(h->mLeft))
// if (isRed(h->mLeft))
...
@@ -1123,7 +1210,7 @@ size_t CatIndex::size() const
...
@@ -1123,7 +1210,7 @@ size_t CatIndex::size() const
// if (isRed(h->mRight))
// if (isRed(h->mRight))
// assert(not isRed(h->mLeft));
// assert(not isRed(h->mLeft));
// }
// }
//
//
// if (h->mLeft != nullptr)
// if (h->mLeft != nullptr)
// {
// {
// assert(mComp(h->mLeft->mRow, h->mRow) < 0);
// assert(mComp(h->mLeft->mRow, h->mRow) < 0);
...
@@ -1136,7 +1223,7 @@ size_t CatIndex::size() const
...
@@ -1136,7 +1223,7 @@ size_t CatIndex::size() const
// if (maxBlack < blackDepth)
// if (maxBlack < blackDepth)
// maxBlack = blackDepth;
// maxBlack = blackDepth;
// }
// }
//
//
// if (h->mRight != nullptr)
// if (h->mRight != nullptr)
// {
// {
// assert(mComp(h->mRight->mRow, h->mRow) > 0);
// assert(mComp(h->mRight->mRow, h->mRow) > 0);
...
@@ -1153,36 +1240,36 @@ size_t CatIndex::size() const
...
@@ -1153,36 +1240,36 @@ size_t CatIndex::size() const
// --------------------------------------------------------------------
// --------------------------------------------------------------------
RowSet
::
RowSet
(
Category
&
cat
)
RowSet
::
RowSet
(
Category
&
cat
)
:
mCat
(
&
cat
)
:
mCat
(
&
cat
)
// , mCond(nullptr)
// , mCond(nullptr)
{
{
}
}
RowSet
::
RowSet
(
Category
&
cat
,
Condition
&&
cond
)
RowSet
::
RowSet
(
Category
&
cat
,
Condition
&&
cond
)
:
mCat
(
&
cat
)
:
mCat
(
&
cat
)
// , mCond(new Condition(std::forward<Condition>(cond)))
// , mCond(new Condition(std::forward<Condition>(cond)))
{
{
cond
.
prepare
(
cat
);
cond
.
prepare
(
cat
);
for
(
auto
r
:
cat
)
for
(
auto
r
:
cat
)
{
{
if
(
cond
(
cat
,
r
))
if
(
cond
(
cat
,
r
))
mItems
.
push_back
(
r
.
mData
);
mItems
.
push_back
(
r
.
mData
);
}
}
}
}
RowSet
::
RowSet
(
const
RowSet
&
rhs
)
RowSet
::
RowSet
(
const
RowSet
&
rhs
)
:
mCat
(
rhs
.
mCat
)
:
mCat
(
rhs
.
mCat
)
,
mItems
(
rhs
.
mItems
)
,
mItems
(
rhs
.
mItems
)
// , mCond(nullptr)
// , mCond(nullptr)
{
{
}
}
RowSet
::
RowSet
(
RowSet
&&
rhs
)
RowSet
::
RowSet
(
RowSet
&&
rhs
)
:
mCat
(
rhs
.
mCat
)
:
mCat
(
rhs
.
mCat
)
,
mItems
(
std
::
move
(
rhs
.
mItems
))
,
mItems
(
std
::
move
(
rhs
.
mItems
))
// , mCond(rhs.mCond)
// , mCond(rhs.mCond)
{
{
// rhs.mCond = nullptr;
// rhs.mCond = nullptr;
}
}
...
@@ -1192,59 +1279,63 @@ RowSet::~RowSet()
...
@@ -1192,59 +1279,63 @@ RowSet::~RowSet()
// delete mCond;
// delete mCond;
}
}
RowSet
&
RowSet
::
operator
=
(
const
RowSet
&
rhs
)
RowSet
&
RowSet
::
operator
=
(
const
RowSet
&
rhs
)
{
{
if
(
this
!=
&
rhs
)
if
(
this
!=
&
rhs
)
{
{
mItems
=
rhs
.
mItems
;
mItems
=
rhs
.
mItems
;
mCat
=
rhs
.
mCat
;
mCat
=
rhs
.
mCat
;
}
}
return
*
this
;
return
*
this
;
}
}
RowSet
&
RowSet
::
operator
=
(
RowSet
&&
rhs
)
RowSet
&
RowSet
::
operator
=
(
RowSet
&&
rhs
)
{
{
if
(
this
!=
&
rhs
)
if
(
this
!=
&
rhs
)
{
{
std
::
swap
(
mItems
,
rhs
.
mItems
);
std
::
swap
(
mItems
,
rhs
.
mItems
);
mCat
=
rhs
.
mCat
;
mCat
=
rhs
.
mCat
;
}
}
return
*
this
;
return
*
this
;
}
}
RowSet
&
RowSet
::
orderBy
(
std
::
initializer_list
<
std
::
string
>
items
)
RowSet
&
RowSet
::
orderBy
(
std
::
initializer_list
<
std
::
string
>
items
)
{
{
RowComparator
c
(
mCat
,
items
.
begin
(),
items
.
end
());
RowComparator
c
(
mCat
,
items
.
begin
(),
items
.
end
());
stable_sort
(
mItems
.
begin
(),
mItems
.
end
(),
c
);
stable_sort
(
mItems
.
begin
(),
mItems
.
end
(),
c
);
return
*
this
;
return
*
this
;
}
}
// --------------------------------------------------------------------
// --------------------------------------------------------------------
Category
::
Category
(
Datablock
&
db
,
const
std
::
string
&
name
,
Validator
*
Validator
)
Category
::
Category
(
Datablock
&
db
,
const
std
::
string
&
name
,
Validator
*
Validator
)
:
mDb
(
db
),
mName
(
name
),
mValidator
(
Validator
)
:
mDb
(
db
)
,
mHead
(
nullptr
),
mTail
(
nullptr
),
mIndex
(
nullptr
)
,
mName
(
name
)
,
mValidator
(
Validator
)
,
mHead
(
nullptr
)
,
mTail
(
nullptr
)
,
mIndex
(
nullptr
)
{
{
if
(
mName
.
empty
())
if
(
mName
.
empty
())
throw
ValidationError
(
"invalid empty name for Category"
);
throw
ValidationError
(
"invalid empty name for Category"
);
if
(
mValidator
!=
nullptr
)
if
(
mValidator
!=
nullptr
)
{
{
mCatValidator
=
mValidator
->
getValidatorForCategory
(
mName
);
mCatValidator
=
mValidator
->
getValidatorForCategory
(
mName
);
if
(
mCatValidator
!=
nullptr
)
if
(
mCatValidator
!=
nullptr
)
{
{
// make sure all required columns are added
// make sure all required columns are added
for
(
auto
&
k
:
mCatValidator
->
mKeys
)
for
(
auto
&
k
:
mCatValidator
->
mKeys
)
addColumn
(
k
);
addColumn
(
k
);
for
(
auto
&
k
:
mCatValidator
->
mMandatoryFields
)
for
(
auto
&
k
:
mCatValidator
->
mMandatoryFields
)
addColumn
(
k
);
addColumn
(
k
);
mIndex
=
new
CatIndex
(
this
);
mIndex
=
new
CatIndex
(
this
);
}
}
}
}
...
@@ -1256,16 +1347,16 @@ Category::~Category()
...
@@ -1256,16 +1347,16 @@ Category::~Category()
delete
mIndex
;
delete
mIndex
;
}
}
void
Category
::
setValidator
(
Validator
*
v
)
void
Category
::
setValidator
(
Validator
*
v
)
{
{
mValidator
=
v
;
mValidator
=
v
;
if
(
mIndex
!=
nullptr
)
if
(
mIndex
!=
nullptr
)
{
{
delete
mIndex
;
delete
mIndex
;
mIndex
=
nullptr
;
mIndex
=
nullptr
;
}
}
if
(
mValidator
!=
nullptr
)
if
(
mValidator
!=
nullptr
)
{
{
mCatValidator
=
mValidator
->
getValidatorForCategory
(
mName
);
mCatValidator
=
mValidator
->
getValidatorForCategory
(
mName
);
...
@@ -1273,22 +1364,22 @@ void Category::setValidator(Validator* v)
...
@@ -1273,22 +1364,22 @@ void Category::setValidator(Validator* v)
{
{
mIndex
=
new
CatIndex
(
this
);
mIndex
=
new
CatIndex
(
this
);
mIndex
->
reconstruct
();
mIndex
->
reconstruct
();
//#if DEBUG
//#if DEBUG
// assert(mIndex->size() == size());
// assert(mIndex->size() == size());
// mIndex->validate();
// mIndex->validate();
//#endif
//#endif
}
}
}
}
else
else
mCatValidator
=
nullptr
;
mCatValidator
=
nullptr
;
}
}
bool
Category
::
hasColumn
(
const
std
::
string
&
name
)
const
bool
Category
::
hasColumn
(
const
std
::
string
&
name
)
const
{
{
return
getColumnIndex
(
name
)
<
mColumns
.
size
();
return
getColumnIndex
(
name
)
<
mColumns
.
size
();
}
}
size_t
Category
::
getColumnIndex
(
const
std
::
string
&
name
)
const
size_t
Category
::
getColumnIndex
(
const
std
::
string
&
name
)
const
{
{
size_t
result
;
size_t
result
;
...
@@ -1297,18 +1388,18 @@ size_t Category::getColumnIndex(const std::string& name) const
...
@@ -1297,18 +1388,18 @@ size_t Category::getColumnIndex(const std::string& name) const
if
(
iequals
(
name
,
mColumns
[
result
].
mName
))
if
(
iequals
(
name
,
mColumns
[
result
].
mName
))
break
;
break
;
}
}
if
(
VERBOSE
and
result
==
mColumns
.
size
()
and
mCatValidator
!=
nullptr
)
// validate the name, if it is known at all (since it was not found)
if
(
VERBOSE
and
result
==
mColumns
.
size
()
and
mCatValidator
!=
nullptr
)
// validate the name, if it is known at all (since it was not found)
{
{
auto
iv
=
mCatValidator
->
getValidatorForItem
(
name
);
auto
iv
=
mCatValidator
->
getValidatorForItem
(
name
);
if
(
iv
==
nullptr
)
if
(
iv
==
nullptr
)
std
::
cerr
<<
"Invalid name used '"
+
name
+
"' is not a known column in "
+
mName
<<
std
::
endl
;
std
::
cerr
<<
"Invalid name used '"
+
name
+
"' is not a known column in "
+
mName
<<
std
::
endl
;
}
}
return
result
;
return
result
;
}
}
const
std
::
string
&
Category
::
getColumnName
(
size_t
columnIx
)
const
const
std
::
string
&
Category
::
getColumnName
(
size_t
columnIx
)
const
{
{
return
mColumns
.
at
(
columnIx
).
mName
;
return
mColumns
.
at
(
columnIx
).
mName
;
}
}
...
@@ -1316,29 +1407,29 @@ const std::string& Category::getColumnName(size_t columnIx) const
...
@@ -1316,29 +1407,29 @@ const std::string& Category::getColumnName(size_t columnIx) const
std
::
vector
<
std
::
string
>
Category
::
getColumnNames
()
const
std
::
vector
<
std
::
string
>
Category
::
getColumnNames
()
const
{
{
std
::
vector
<
std
::
string
>
result
;
std
::
vector
<
std
::
string
>
result
;
for
(
auto
&
c
:
mColumns
)
for
(
auto
&
c
:
mColumns
)
result
.
push_back
(
c
.
mName
);
result
.
push_back
(
c
.
mName
);
return
result
;
return
result
;
}
}
size_t
Category
::
addColumn
(
const
std
::
string
&
name
)
size_t
Category
::
addColumn
(
const
std
::
string
&
name
)
{
{
size_t
result
=
getColumnIndex
(
name
);
size_t
result
=
getColumnIndex
(
name
);
if
(
result
==
mColumns
.
size
())
if
(
result
==
mColumns
.
size
())
{
{
const
ValidateItem
*
itemValidator
=
nullptr
;
const
ValidateItem
*
itemValidator
=
nullptr
;
if
(
mCatValidator
!=
nullptr
)
if
(
mCatValidator
!=
nullptr
)
{
{
itemValidator
=
mCatValidator
->
getValidatorForItem
(
name
);
itemValidator
=
mCatValidator
->
getValidatorForItem
(
name
);
if
(
itemValidator
==
nullptr
)
if
(
itemValidator
==
nullptr
)
mValidator
->
reportError
(
"tag "
+
name
+
" not allowed in Category "
+
mName
,
false
);
mValidator
->
reportError
(
"tag "
+
name
+
" not allowed in Category "
+
mName
,
false
);
}
}
mColumns
.
push_back
({
name
,
itemValidator
});
mColumns
.
push_back
({
name
,
itemValidator
});
}
}
return
result
;
return
result
;
}
}
...
@@ -1363,17 +1454,17 @@ void Category::reorderByIndex()
...
@@ -1363,17 +1454,17 @@ void Category::reorderByIndex()
std
::
tie
(
mHead
,
mTail
)
=
mIndex
->
reorder
();
std
::
tie
(
mHead
,
mTail
)
=
mIndex
->
reorder
();
}
}
void
Category
::
sort
(
std
::
function
<
int
(
const
Row
&
,
const
Row
&
)
>
comparator
)
void
Category
::
sort
(
std
::
function
<
int
(
const
Row
&
,
const
Row
&
)
>
comparator
)
{
{
if
(
mHead
==
nullptr
)
if
(
mHead
==
nullptr
)
return
;
return
;
std
::
vector
<
ItemRow
*>
rows
;
std
::
vector
<
ItemRow
*>
rows
;
for
(
auto
itemRow
=
mHead
;
itemRow
!=
nullptr
;
itemRow
=
itemRow
->
mNext
)
for
(
auto
itemRow
=
mHead
;
itemRow
!=
nullptr
;
itemRow
=
itemRow
->
mNext
)
rows
.
push_back
(
itemRow
);
rows
.
push_back
(
itemRow
);
std
::
stable_sort
(
rows
.
begin
(),
rows
.
end
(),
std
::
stable_sort
(
rows
.
begin
(),
rows
.
end
(),
[
&
comparator
](
ItemRow
*
ia
,
ItemRow
*
ib
)
[
&
comparator
](
ItemRow
*
ia
,
ItemRow
*
ib
)
{
{
Row
ra
(
ia
);
Row
ra
(
ia
);
Row
rb
(
ib
);
Row
rb
(
ib
);
...
@@ -1416,10 +1507,10 @@ std::string Category::getUniqueID(std::function<std::string(int)> generator)
...
@@ -1416,10 +1507,10 @@ std::string Category::getUniqueID(std::function<std::string(int)> generator)
size_t
Category
::
size
()
const
size_t
Category
::
size
()
const
{
{
size_t
result
=
0
;
size_t
result
=
0
;
for
(
auto
pi
=
mHead
;
pi
!=
nullptr
;
pi
=
pi
->
mNext
)
for
(
auto
pi
=
mHead
;
pi
!=
nullptr
;
pi
=
pi
->
mNext
)
++
result
;
++
result
;
return
result
;
return
result
;
}
}
...
@@ -1428,30 +1519,31 @@ bool Category::empty() const
...
@@ -1428,30 +1519,31 @@ bool Category::empty() const
return
mHead
==
nullptr
or
mHead
->
mValues
==
nullptr
;
return
mHead
==
nullptr
or
mHead
->
mValues
==
nullptr
;
}
}
void
Category
::
drop
(
const
std
::
string
&
field
)
void
Category
::
drop
(
const
std
::
string
&
field
)
{
{
using
namespace
std
::
placeholders
;
using
namespace
std
::
placeholders
;
auto
ci
=
find_if
(
mColumns
.
begin
(),
mColumns
.
end
(),
auto
ci
=
find_if
(
mColumns
.
begin
(),
mColumns
.
end
(),
[
field
](
ItemColumn
&
c
)
->
bool
{
return
iequals
(
c
.
mName
,
field
);
});
[
field
](
ItemColumn
&
c
)
->
bool
{
return
iequals
(
c
.
mName
,
field
);
});
if
(
ci
!=
mColumns
.
end
())
if
(
ci
!=
mColumns
.
end
())
{
{
size_t
columnIx
=
ci
-
mColumns
.
begin
();
size_t
columnIx
=
ci
-
mColumns
.
begin
();
for
(
auto
pi
=
mHead
;
pi
!=
nullptr
;
pi
=
pi
->
mNext
)
for
(
auto
pi
=
mHead
;
pi
!=
nullptr
;
pi
=
pi
->
mNext
)
pi
->
drop
(
columnIx
);
pi
->
drop
(
columnIx
);
mColumns
.
erase
(
ci
);
mColumns
.
erase
(
ci
);
}
}
}
}
Row
Category
::
operator
[](
Condition
&&
cond
)
Row
Category
::
operator
[](
Condition
&&
cond
)
{
{
Row
result
;
Row
result
;
cond
.
prepare
(
*
this
);
cond
.
prepare
(
*
this
);
for
(
auto
r
:
*
this
)
for
(
auto
r
:
*
this
)
{
{
if
(
cond
(
*
this
,
r
))
if
(
cond
(
*
this
,
r
))
{
{
...
@@ -1461,15 +1553,15 @@ Row Category::operator[](Condition&& cond)
...
@@ -1461,15 +1553,15 @@ Row Category::operator[](Condition&& cond)
}
}
return
result
;
return
result
;
}
}
// RowSet Category::find(Condition&& cond)
// RowSet Category::find(Condition&& cond)
// {
// {
// // return RowSet(*this, std::forward<Condition>(cond));
// // return RowSet(*this, std::forward<Condition>(cond));
// RowSet result(*this);
// RowSet result(*this);
// cond.prepare(*this);
// cond.prepare(*this);
// for (auto r: *this)
// for (auto r: *this)
// {
// {
// if (cond(*this, r))
// if (cond(*this, r))
...
@@ -1478,13 +1570,13 @@ Row Category::operator[](Condition&& cond)
...
@@ -1478,13 +1570,13 @@ Row Category::operator[](Condition&& cond)
// return result;
// return result;
// }
// }
bool
Category
::
exists
(
Condition
&&
cond
)
const
bool
Category
::
exists
(
Condition
&&
cond
)
const
{
{
bool
result
=
false
;
bool
result
=
false
;
cond
.
prepare
(
*
this
);
cond
.
prepare
(
*
this
);
for
(
auto
r
:
*
this
)
for
(
auto
r
:
*
this
)
{
{
if
(
cond
(
*
this
,
r
))
if
(
cond
(
*
this
,
r
))
{
{
...
@@ -1500,7 +1592,7 @@ RowSet Category::orderBy(std::initializer_list<std::string> items)
...
@@ -1500,7 +1592,7 @@ RowSet Category::orderBy(std::initializer_list<std::string> items)
{
{
RowSet
result
(
*
this
);
RowSet
result
(
*
this
);
result
.
insert
(
result
.
begin
(),
begin
(),
end
());
result
.
insert
(
result
.
begin
(),
begin
(),
end
());
return
result
.
orderBy
(
items
);
return
result
.
orderBy
(
items
);
}
}
...
@@ -1508,7 +1600,7 @@ void Category::clear()
...
@@ -1508,7 +1600,7 @@ void Category::clear()
{
{
delete
mHead
;
delete
mHead
;
mHead
=
mTail
=
nullptr
;
mHead
=
mTail
=
nullptr
;
if
(
mIndex
!=
nullptr
)
if
(
mIndex
!=
nullptr
)
{
{
delete
mIndex
;
delete
mIndex
;
...
@@ -1516,8 +1608,8 @@ void Category::clear()
...
@@ -1516,8 +1608,8 @@ void Category::clear()
}
}
}
}
template
<
class
Iter
>
template
<
class
Iter
>
std
::
tuple
<
Row
,
bool
>
Category
::
emplace
(
Iter
b
,
Iter
e
)
std
::
tuple
<
Row
,
bool
>
Category
::
emplace
(
Iter
b
,
Iter
e
)
{
{
// First, make sure all mandatory fields are supplied
// First, make sure all mandatory fields are supplied
Row
result
;
Row
result
;
...
@@ -1525,15 +1617,15 @@ std::tuple<Row,bool> Category::emplace(Iter b, Iter e)
...
@@ -1525,15 +1617,15 @@ std::tuple<Row,bool> Category::emplace(Iter b, Iter e)
if
(
mCatValidator
!=
nullptr
and
b
!=
e
)
if
(
mCatValidator
!=
nullptr
and
b
!=
e
)
{
{
for
(
auto
&
col
:
mColumns
)
for
(
auto
&
col
:
mColumns
)
{
{
auto
iv
=
mCatValidator
->
getValidatorForItem
(
col
.
mName
);
auto
iv
=
mCatValidator
->
getValidatorForItem
(
col
.
mName
);
if
(
iv
==
nullptr
)
if
(
iv
==
nullptr
)
continue
;
continue
;
bool
seen
=
false
;
bool
seen
=
false
;
for
(
auto
v
=
b
;
v
!=
e
;
++
v
)
for
(
auto
v
=
b
;
v
!=
e
;
++
v
)
{
{
if
(
iequals
(
v
->
name
(),
col
.
mName
))
if
(
iequals
(
v
->
name
(),
col
.
mName
))
...
@@ -1542,23 +1634,23 @@ std::tuple<Row,bool> Category::emplace(Iter b, Iter e)
...
@@ -1542,23 +1634,23 @@ std::tuple<Row,bool> Category::emplace(Iter b, Iter e)
break
;
break
;
}
}
}
}
if
(
not
seen
and
iv
->
mMandatory
)
if
(
not
seen
and
iv
->
mMandatory
)
throw
std
::
runtime_error
(
"missing mandatory field "
+
col
.
mName
+
" for Category "
+
mName
);
throw
std
::
runtime_error
(
"missing mandatory field "
+
col
.
mName
+
" for Category "
+
mName
);
}
}
if
(
mIndex
!=
nullptr
)
if
(
mIndex
!=
nullptr
)
{
{
std
::
unique_ptr
<
ItemRow
>
nr
(
new
ItemRow
{
nullptr
,
this
,
nullptr
});
std
::
unique_ptr
<
ItemRow
>
nr
(
new
ItemRow
{
nullptr
,
this
,
nullptr
});
Row
r
(
nr
.
get
());
Row
r
(
nr
.
get
());
auto
keys
=
keyFields
();
auto
keys
=
keyFields
();
for
(
auto
v
=
b
;
v
!=
e
;
++
v
)
for
(
auto
v
=
b
;
v
!=
e
;
++
v
)
{
{
if
(
keys
.
count
(
v
->
name
()))
if
(
keys
.
count
(
v
->
name
()))
r
.
assign
(
v
->
name
(),
v
->
value
(),
true
);
r
.
assign
(
v
->
name
(),
v
->
value
(),
true
);
}
}
auto
test
=
mIndex
->
find
(
nr
.
get
());
auto
test
=
mIndex
->
find
(
nr
.
get
());
if
(
test
!=
nullptr
)
if
(
test
!=
nullptr
)
{
{
...
@@ -1578,7 +1670,7 @@ std::tuple<Row,bool> Category::emplace(Iter b, Iter e)
...
@@ -1578,7 +1670,7 @@ std::tuple<Row,bool> Category::emplace(Iter b, Iter e)
for
(
auto
v
=
b
;
v
!=
e
;
++
v
)
for
(
auto
v
=
b
;
v
!=
e
;
++
v
)
r
.
assign
(
*
v
,
true
);
r
.
assign
(
*
v
,
true
);
// if (isOrphan(r))
// if (isOrphan(r))
// throw std::runtime_error("Cannot insert row in category " + mName + " since it would be an orphan");
// throw std::runtime_error("Cannot insert row in category " + mName + " since it would be an orphan");
...
@@ -1600,16 +1692,16 @@ std::tuple<Row,bool> Category::emplace(Iter b, Iter e)
...
@@ -1600,16 +1692,16 @@ std::tuple<Row,bool> Category::emplace(Iter b, Iter e)
if
(
mIndex
!=
nullptr
)
if
(
mIndex
!=
nullptr
)
mIndex
->
insert
(
nr
);
mIndex
->
insert
(
nr
);
}
}
return
{
result
,
isNew
};
return
{
result
,
isNew
};
}
}
std
::
tuple
<
Row
,
bool
>
Category
::
emplace
(
Row
r
)
std
::
tuple
<
Row
,
bool
>
Category
::
emplace
(
Row
r
)
{
{
return
emplace
(
r
.
begin
(),
r
.
end
());
return
emplace
(
r
.
begin
(),
r
.
end
());
}
}
size_t
Category
::
erase
(
Condition
&&
cond
)
size_t
Category
::
erase
(
Condition
&&
cond
)
{
{
size_t
result
=
0
;
size_t
result
=
0
;
...
@@ -1627,10 +1719,10 @@ size_t Category::erase(Condition&& cond)
...
@@ -1627,10 +1719,10 @@ size_t Category::erase(Condition&& cond)
++
ri
;
++
ri
;
}
}
return
result
;
return
result
;
}
}
size_t
Category
::
erase
(
Condition
&&
cond
,
std
::
function
<
void
(
const
Row
&
)
>&&
verbose
)
size_t
Category
::
erase
(
Condition
&&
cond
,
std
::
function
<
void
(
const
Row
&
)
>
&&
verbose
)
{
{
size_t
result
=
0
;
size_t
result
=
0
;
...
@@ -1652,26 +1744,26 @@ size_t Category::erase(Condition&& cond, std::function<void(const Row&)>&& verbo
...
@@ -1652,26 +1744,26 @@ size_t Category::erase(Condition&& cond, std::function<void(const Row&)>&& verbo
return
result
;
return
result
;
}
}
void
Category
::
eraseOrphans
(
Condition
&&
cond
)
void
Category
::
eraseOrphans
(
Condition
&&
cond
)
{
{
std
::
vector
<
ItemRow
*>
remove
;
std
::
vector
<
ItemRow
*>
remove
;
cond
.
prepare
(
*
this
);
cond
.
prepare
(
*
this
);
for
(
auto
r
:
*
this
)
for
(
auto
r
:
*
this
)
{
{
if
(
cond
(
*
this
,
r
)
and
isOrphan
(
r
))
if
(
cond
(
*
this
,
r
)
and
isOrphan
(
r
))
{
{
if
(
VERBOSE
>
1
)
if
(
VERBOSE
>
1
)
std
::
cerr
<<
"Removing orphaned record: "
<<
std
::
endl
std
::
cerr
<<
"Removing orphaned record: "
<<
std
::
endl
<<
r
<<
std
::
endl
<<
r
<<
std
::
endl
<<
std
::
endl
;
<<
std
::
endl
;
remove
.
push_back
(
r
.
mData
);
remove
.
push_back
(
r
.
mData
);
}
}
}
}
for
(
auto
r
:
remove
)
for
(
auto
r
:
remove
)
erase
(
iterator
(
r
));
erase
(
iterator
(
r
));
}
}
...
@@ -1694,7 +1786,7 @@ auto Category::erase(iterator pos) -> iterator
...
@@ -1694,7 +1786,7 @@ auto Category::erase(iterator pos) -> iterator
if
(
mIndex
!=
nullptr
)
if
(
mIndex
!=
nullptr
)
mIndex
->
erase
(
r
.
mData
);
mIndex
->
erase
(
r
.
mData
);
if
(
r
==
mHead
)
if
(
r
==
mHead
)
{
{
mHead
=
mHead
->
mNext
;
mHead
=
mHead
->
mNext
;
...
@@ -1716,25 +1808,25 @@ auto Category::erase(iterator pos) -> iterator
...
@@ -1716,25 +1808,25 @@ auto Category::erase(iterator pos) -> iterator
// links are created based on the _pdbx_item_linked_group_list entries
// links are created based on the _pdbx_item_linked_group_list entries
// in mmcif_pdbx_v50.dic dictionary.
// in mmcif_pdbx_v50.dic dictionary.
//
//
// For each link group in _pdbx_item_linked_group_list
// For each link group in _pdbx_item_linked_group_list
// a std::set of keys from one category is mapped to another.
// a std::set of keys from one category is mapped to another.
// If all values in a child are the same as the specified parent ones
// If all values in a child are the same as the specified parent ones
// the child is removed as well, recursively of course.
// the child is removed as well, recursively of course.
if
(
mValidator
!=
nullptr
)
if
(
mValidator
!=
nullptr
)
{
{
for
(
auto
&
link
:
mValidator
->
getLinksForParent
(
mName
))
for
(
auto
&
link
:
mValidator
->
getLinksForParent
(
mName
))
{
{
auto
childCat
=
mDb
.
get
(
link
->
mChildCategory
);
auto
childCat
=
mDb
.
get
(
link
->
mChildCategory
);
if
(
childCat
==
nullptr
)
if
(
childCat
==
nullptr
)
continue
;
continue
;
Condition
cond
;
Condition
cond
;
for
(
size_t
ix
=
0
;
ix
<
link
->
mParentKeys
.
size
();
++
ix
)
for
(
size_t
ix
=
0
;
ix
<
link
->
mParentKeys
.
size
();
++
ix
)
{
{
const
char
*
value
=
r
[
link
->
mParentKeys
[
ix
]].
c_str
();
const
char
*
value
=
r
[
link
->
mParentKeys
[
ix
]].
c_str
();
cond
=
std
::
move
(
cond
)
&&
(
Key
(
link
->
mChildKeys
[
ix
])
==
value
);
cond
=
std
::
move
(
cond
)
&&
(
Key
(
link
->
mChildKeys
[
ix
])
==
value
);
}
}
...
@@ -1780,15 +1872,15 @@ Row Category::copyRow(const Row &row)
...
@@ -1780,15 +1872,15 @@ Row Category::copyRow(const Row &row)
}
}
}
}
auto
&&
[
result
,
inserted
]
=
emplace
(
items
.
begin
(),
items
.
end
());
auto
&&
[
result
,
inserted
]
=
emplace
(
items
.
begin
(),
items
.
end
());
// assert(inserted);
// assert(inserted);
return
result
;
return
result
;
}
}
void
Category
::
getTagOrder
(
std
::
vector
<
std
::
string
>
&
tags
)
const
void
Category
::
getTagOrder
(
std
::
vector
<
std
::
string
>
&
tags
)
const
{
{
for
(
auto
&
c
:
mColumns
)
for
(
auto
&
c
:
mColumns
)
tags
.
push_back
(
"_"
+
mName
+
"."
+
c
.
mName
);
tags
.
push_back
(
"_"
+
mName
+
"."
+
c
.
mName
);
}
}
...
@@ -1822,7 +1914,7 @@ Category::const_iterator Category::end() const
...
@@ -1822,7 +1914,7 @@ Category::const_iterator Category::end() const
return
const_iterator
();
return
const_iterator
();
}
}
bool
Category
::
hasParent
(
Row
r
,
const
Category
&
parentCat
,
const
ValidateLink
&
link
)
const
bool
Category
::
hasParent
(
Row
r
,
const
Category
&
parentCat
,
const
ValidateLink
&
link
)
const
{
{
assert
(
mValidator
!=
nullptr
);
assert
(
mValidator
!=
nullptr
);
assert
(
mCatValidator
!=
nullptr
);
assert
(
mCatValidator
!=
nullptr
);
...
@@ -1832,7 +1924,7 @@ bool Category::hasParent(Row r, const Category& parentCat, const ValidateLink& l
...
@@ -1832,7 +1924,7 @@ bool Category::hasParent(Row r, const Category& parentCat, const ValidateLink& l
Condition
cond
;
Condition
cond
;
for
(
size_t
ix
=
0
;
ix
<
link
.
mChildKeys
.
size
();
++
ix
)
for
(
size_t
ix
=
0
;
ix
<
link
.
mChildKeys
.
size
();
++
ix
)
{
{
auto
&
name
=
link
.
mChildKeys
[
ix
];
auto
&
name
=
link
.
mChildKeys
[
ix
];
auto
field
=
r
[
name
];
auto
field
=
r
[
name
];
if
(
field
.
empty
())
if
(
field
.
empty
())
{
{
...
@@ -1841,7 +1933,7 @@ bool Category::hasParent(Row r, const Category& parentCat, const ValidateLink& l
...
@@ -1841,7 +1933,7 @@ bool Category::hasParent(Row r, const Category& parentCat, const ValidateLink& l
}
}
else
else
{
{
const
char
*
value
=
field
.
c_str
();
const
char
*
value
=
field
.
c_str
();
cond
=
std
::
move
(
cond
)
and
(
Key
(
link
.
mParentKeys
[
ix
])
==
value
);
cond
=
std
::
move
(
cond
)
and
(
Key
(
link
.
mParentKeys
[
ix
])
==
value
);
}
}
}
}
...
@@ -1866,16 +1958,16 @@ bool Category::isOrphan(Row r)
...
@@ -1866,16 +1958,16 @@ bool Category::isOrphan(Row r)
return
false
;
return
false
;
bool
isOrphan
=
true
;
bool
isOrphan
=
true
;
for
(
auto
&
link
:
mValidator
->
getLinksForChild
(
mName
))
for
(
auto
&
link
:
mValidator
->
getLinksForChild
(
mName
))
{
{
auto
parentCat
=
mDb
.
get
(
link
->
mParentCategory
);
auto
parentCat
=
mDb
.
get
(
link
->
mParentCategory
);
if
(
parentCat
==
nullptr
)
if
(
parentCat
==
nullptr
)
continue
;
continue
;
Condition
cond
;
Condition
cond
;
for
(
size_t
ix
=
0
;
ix
<
link
->
mChildKeys
.
size
();
++
ix
)
for
(
size_t
ix
=
0
;
ix
<
link
->
mChildKeys
.
size
();
++
ix
)
{
{
const
char
*
value
=
r
[
link
->
mChildKeys
[
ix
]].
c_str
();
const
char
*
value
=
r
[
link
->
mChildKeys
[
ix
]].
c_str
();
cond
=
std
::
move
(
cond
)
&&
(
Key
(
link
->
mParentKeys
[
ix
])
==
value
);
cond
=
std
::
move
(
cond
)
&&
(
Key
(
link
->
mParentKeys
[
ix
])
==
value
);
}
}
...
@@ -1902,18 +1994,18 @@ bool Category::hasChildren(Row r) const
...
@@ -1902,18 +1994,18 @@ bool Category::hasChildren(Row r) const
bool
result
=
false
;
bool
result
=
false
;
for
(
auto
&
link
:
mValidator
->
getLinksForParent
(
mName
))
for
(
auto
&
link
:
mValidator
->
getLinksForParent
(
mName
))
{
{
auto
childCat
=
mDb
.
get
(
link
->
mChildCategory
);
auto
childCat
=
mDb
.
get
(
link
->
mChildCategory
);
if
(
childCat
==
nullptr
)
if
(
childCat
==
nullptr
)
continue
;
continue
;
Condition
cond
;
Condition
cond
;
for
(
size_t
ix
=
0
;
ix
<
link
->
mParentKeys
.
size
();
++
ix
)
for
(
size_t
ix
=
0
;
ix
<
link
->
mParentKeys
.
size
();
++
ix
)
{
{
const
char
*
value
=
r
[
link
->
mParentKeys
[
ix
]].
c_str
();
const
char
*
value
=
r
[
link
->
mParentKeys
[
ix
]].
c_str
();
cond
=
std
::
move
(
cond
)
&&
(
Key
(
link
->
mChildKeys
[
ix
])
==
value
);
cond
=
std
::
move
(
cond
)
&&
(
Key
(
link
->
mChildKeys
[
ix
])
==
value
);
}
}
...
@@ -1933,18 +2025,18 @@ bool Category::hasParents(Row r) const
...
@@ -1933,18 +2025,18 @@ bool Category::hasParents(Row r) const
bool
result
=
false
;
bool
result
=
false
;
for
(
auto
&
link
:
mValidator
->
getLinksForChild
(
mName
))
for
(
auto
&
link
:
mValidator
->
getLinksForChild
(
mName
))
{
{
auto
parentCat
=
mDb
.
get
(
link
->
mParentCategory
);
auto
parentCat
=
mDb
.
get
(
link
->
mParentCategory
);
if
(
parentCat
==
nullptr
)
if
(
parentCat
==
nullptr
)
continue
;
continue
;
Condition
cond
;
Condition
cond
;
for
(
size_t
ix
=
0
;
ix
<
link
->
mChildKeys
.
size
();
++
ix
)
for
(
size_t
ix
=
0
;
ix
<
link
->
mChildKeys
.
size
();
++
ix
)
{
{
const
char
*
value
=
r
[
link
->
mChildKeys
[
ix
]].
c_str
();
const
char
*
value
=
r
[
link
->
mChildKeys
[
ix
]].
c_str
();
cond
=
std
::
move
(
cond
)
&&
(
Key
(
link
->
mParentKeys
[
ix
])
==
value
);
cond
=
std
::
move
(
cond
)
&&
(
Key
(
link
->
mParentKeys
[
ix
])
==
value
);
}
}
...
@@ -1957,29 +2049,29 @@ bool Category::hasParents(Row r) const
...
@@ -1957,29 +2049,29 @@ bool Category::hasParents(Row r) const
return
result
;
return
result
;
}
}
RowSet
Category
::
getChildren
(
Row
r
,
const
char
*
childCat
)
RowSet
Category
::
getChildren
(
Row
r
,
const
char
*
childCat
)
{
{
return
getChildren
(
r
,
mDb
[
childCat
]);
return
getChildren
(
r
,
mDb
[
childCat
]);
}
}
RowSet
Category
::
getChildren
(
Row
r
,
Category
&
childCat
)
RowSet
Category
::
getChildren
(
Row
r
,
Category
&
childCat
)
{
{
assert
(
mValidator
!=
nullptr
);
assert
(
mValidator
!=
nullptr
);
assert
(
mCatValidator
!=
nullptr
);
assert
(
mCatValidator
!=
nullptr
);
RowSet
result
(
childCat
);
RowSet
result
(
childCat
);
for
(
auto
&
link
:
mValidator
->
getLinksForParent
(
mName
))
for
(
auto
&
link
:
mValidator
->
getLinksForParent
(
mName
))
{
{
if
(
link
->
mChildCategory
!=
childCat
.
mName
)
if
(
link
->
mChildCategory
!=
childCat
.
mName
)
continue
;
continue
;
Condition
cond
;
Condition
cond
;
for
(
size_t
ix
=
0
;
ix
<
link
->
mParentKeys
.
size
();
++
ix
)
for
(
size_t
ix
=
0
;
ix
<
link
->
mParentKeys
.
size
();
++
ix
)
{
{
const
char
*
value
=
r
[
link
->
mParentKeys
[
ix
]].
c_str
();
const
char
*
value
=
r
[
link
->
mParentKeys
[
ix
]].
c_str
();
cond
=
std
::
move
(
cond
)
&&
(
Key
(
link
->
mChildKeys
[
ix
])
==
value
);
cond
=
std
::
move
(
cond
)
&&
(
Key
(
link
->
mChildKeys
[
ix
])
==
value
);
}
}
...
@@ -1993,29 +2085,29 @@ RowSet Category::getChildren(Row r, Category& childCat)
...
@@ -1993,29 +2085,29 @@ RowSet Category::getChildren(Row r, Category& childCat)
return
result
;
return
result
;
}
}
RowSet
Category
::
getParents
(
Row
r
,
const
char
*
parentCat
)
RowSet
Category
::
getParents
(
Row
r
,
const
char
*
parentCat
)
{
{
return
getParents
(
r
,
mDb
[
parentCat
]);
return
getParents
(
r
,
mDb
[
parentCat
]);
}
}
RowSet
Category
::
getParents
(
Row
r
,
Category
&
parentCat
)
RowSet
Category
::
getParents
(
Row
r
,
Category
&
parentCat
)
{
{
assert
(
mValidator
!=
nullptr
);
assert
(
mValidator
!=
nullptr
);
assert
(
mCatValidator
!=
nullptr
);
assert
(
mCatValidator
!=
nullptr
);
RowSet
result
(
parentCat
);
RowSet
result
(
parentCat
);
for
(
auto
&
link
:
mValidator
->
getLinksForChild
(
mName
))
for
(
auto
&
link
:
mValidator
->
getLinksForChild
(
mName
))
{
{
if
(
link
->
mParentCategory
!=
parentCat
.
mName
)
if
(
link
->
mParentCategory
!=
parentCat
.
mName
)
continue
;
continue
;
Condition
cond
;
Condition
cond
;
for
(
size_t
ix
=
0
;
ix
<
link
->
mChildKeys
.
size
();
++
ix
)
for
(
size_t
ix
=
0
;
ix
<
link
->
mChildKeys
.
size
();
++
ix
)
{
{
const
char
*
value
=
r
[
link
->
mChildKeys
[
ix
]].
c_str
();
const
char
*
value
=
r
[
link
->
mChildKeys
[
ix
]].
c_str
();
cond
=
std
::
move
(
cond
)
&&
(
Key
(
link
->
mParentKeys
[
ix
])
==
value
);
cond
=
std
::
move
(
cond
)
&&
(
Key
(
link
->
mParentKeys
[
ix
])
==
value
);
}
}
...
@@ -2029,12 +2121,12 @@ RowSet Category::getParents(Row r, Category& parentCat)
...
@@ -2029,12 +2121,12 @@ RowSet Category::getParents(Row r, Category& parentCat)
return
result
;
return
result
;
}
}
RowSet
Category
::
getLinked
(
Row
r
,
const
char
*
cat
)
RowSet
Category
::
getLinked
(
Row
r
,
const
char
*
cat
)
{
{
return
getLinked
(
r
,
mDb
[
cat
]);
return
getLinked
(
r
,
mDb
[
cat
]);
}
}
RowSet
Category
::
getLinked
(
Row
r
,
Category
&
cat
)
RowSet
Category
::
getLinked
(
Row
r
,
Category
&
cat
)
{
{
RowSet
result
=
getChildren
(
r
,
cat
);
RowSet
result
=
getChildren
(
r
,
cat
);
if
(
result
.
empty
())
if
(
result
.
empty
())
...
@@ -2045,7 +2137,7 @@ RowSet Category::getLinked(Row r, Category& cat)
...
@@ -2045,7 +2137,7 @@ RowSet Category::getLinked(Row r, Category& cat)
bool
Category
::
isValid
()
bool
Category
::
isValid
()
{
{
bool
result
=
true
;
bool
result
=
true
;
if
(
mValidator
==
nullptr
)
if
(
mValidator
==
nullptr
)
throw
std
::
runtime_error
(
"no Validator specified"
);
throw
std
::
runtime_error
(
"no Validator specified"
);
...
@@ -2055,16 +2147,16 @@ bool Category::isValid()
...
@@ -2055,16 +2147,16 @@ bool Category::isValid()
std
::
cerr
<<
"Skipping validation of empty Category "
<<
mName
<<
std
::
endl
;
std
::
cerr
<<
"Skipping validation of empty Category "
<<
mName
<<
std
::
endl
;
return
true
;
return
true
;
}
}
if
(
mCatValidator
==
nullptr
)
if
(
mCatValidator
==
nullptr
)
{
{
mValidator
->
reportError
(
"undefined Category "
+
mName
,
false
);
mValidator
->
reportError
(
"undefined Category "
+
mName
,
false
);
return
false
;
return
false
;
}
}
auto
mandatory
=
mCatValidator
->
mMandatoryFields
;
auto
mandatory
=
mCatValidator
->
mMandatoryFields
;
for
(
auto
&
col
:
mColumns
)
for
(
auto
&
col
:
mColumns
)
{
{
auto
iv
=
mCatValidator
->
getValidatorForItem
(
col
.
mName
);
auto
iv
=
mCatValidator
->
getValidatorForItem
(
col
.
mName
);
if
(
iv
==
nullptr
)
if
(
iv
==
nullptr
)
...
@@ -2072,48 +2164,48 @@ bool Category::isValid()
...
@@ -2072,48 +2164,48 @@ bool Category::isValid()
mValidator
->
reportError
(
"Field "
+
col
.
mName
+
" is not valid in Category "
+
mName
,
false
);
mValidator
->
reportError
(
"Field "
+
col
.
mName
+
" is not valid in Category "
+
mName
,
false
);
result
=
false
;
result
=
false
;
}
}
col
.
mValidator
=
iv
;
col
.
mValidator
=
iv
;
mandatory
.
erase
(
col
.
mName
);
mandatory
.
erase
(
col
.
mName
);
}
}
if
(
not
mandatory
.
empty
())
if
(
not
mandatory
.
empty
())
{
{
mValidator
->
reportError
(
"In Category "
+
mName
+
" the following mandatory fields are missing: "
+
ba
::
join
(
mandatory
,
", "
),
false
);
mValidator
->
reportError
(
"In Category "
+
mName
+
" the following mandatory fields are missing: "
+
ba
::
join
(
mandatory
,
", "
),
false
);
result
=
false
;
result
=
false
;
}
}
//#if not defined(NDEBUG)
//#if not defined(NDEBUG)
// // check index?
// // check index?
// if (mIndex)
// if (mIndex)
// {
// {
// mIndex->validate();
// mIndex->validate();
// for (auto r: *this)
// for (auto r: *this)
// {
// {
// if (mIndex->find(r.mData) != r.mData)
// if (mIndex->find(r.mData) != r.mData)
// mValidator->reportError("Key not found in index for Category " + mName);
// mValidator->reportError("Key not found in index for Category " + mName);
// }
// }
// }
// }
//#endif
//#endif
// validate all values
// validate all values
mandatory
=
mCatValidator
->
mMandatoryFields
;
mandatory
=
mCatValidator
->
mMandatoryFields
;
for
(
auto
ri
=
mHead
;
ri
!=
nullptr
;
ri
=
ri
->
mNext
)
for
(
auto
ri
=
mHead
;
ri
!=
nullptr
;
ri
=
ri
->
mNext
)
{
{
for
(
size_t
cix
=
0
;
cix
<
mColumns
.
size
();
++
cix
)
for
(
size_t
cix
=
0
;
cix
<
mColumns
.
size
();
++
cix
)
{
{
bool
seen
=
false
;
bool
seen
=
false
;
auto
iv
=
mColumns
[
cix
].
mValidator
;
auto
iv
=
mColumns
[
cix
].
mValidator
;
if
(
iv
==
nullptr
)
if
(
iv
==
nullptr
)
{
{
mValidator
->
reportError
(
"invalid field "
+
mColumns
[
cix
].
mName
+
" for Category "
+
mName
,
false
);
mValidator
->
reportError
(
"invalid field "
+
mColumns
[
cix
].
mName
+
" for Category "
+
mName
,
false
);
result
=
false
;
result
=
false
;
continue
;
continue
;
}
}
for
(
auto
vi
=
ri
->
mValues
;
vi
!=
nullptr
;
vi
=
vi
->
mNext
)
for
(
auto
vi
=
ri
->
mValues
;
vi
!=
nullptr
;
vi
=
vi
->
mNext
)
{
{
if
(
vi
->
mColumnIndex
==
cix
)
if
(
vi
->
mColumnIndex
==
cix
)
...
@@ -2123,17 +2215,17 @@ bool Category::isValid()
...
@@ -2123,17 +2215,17 @@ bool Category::isValid()
{
{
(
*
iv
)(
vi
->
mText
);
(
*
iv
)(
vi
->
mText
);
}
}
catch
(
const
std
::
exception
&
e
)
catch
(
const
std
::
exception
&
e
)
{
{
mValidator
->
reportError
(
"Error validating "
+
mColumns
[
cix
].
mName
+
": "
+
e
.
what
(),
false
);
mValidator
->
reportError
(
"Error validating "
+
mColumns
[
cix
].
mName
+
": "
+
e
.
what
(),
false
);
continue
;
continue
;
}
}
}
}
}
}
if
(
seen
or
ri
!=
mHead
)
if
(
seen
or
ri
!=
mHead
)
continue
;
continue
;
if
(
iv
!=
nullptr
and
iv
->
mMandatory
)
if
(
iv
!=
nullptr
and
iv
->
mMandatory
)
{
{
mValidator
->
reportError
(
"missing mandatory field "
+
mColumns
[
cix
].
mName
+
" for Category "
+
mName
,
false
);
mValidator
->
reportError
(
"missing mandatory field "
+
mColumns
[
cix
].
mName
+
" for Category "
+
mName
,
false
);
...
@@ -2141,34 +2233,34 @@ bool Category::isValid()
...
@@ -2141,34 +2233,34 @@ bool Category::isValid()
}
}
}
}
}
}
return
result
;
return
result
;
}
}
void
Category
::
validateLinks
()
const
void
Category
::
validateLinks
()
const
{
{
auto
&
validator
=
getValidator
();
auto
&
validator
=
getValidator
();
for
(
auto
linkValidator
:
validator
.
getLinksForChild
(
mName
))
for
(
auto
linkValidator
:
validator
.
getLinksForChild
(
mName
))
{
{
auto
parent
=
mDb
.
get
(
linkValidator
->
mParentCategory
);
auto
parent
=
mDb
.
get
(
linkValidator
->
mParentCategory
);
if
(
parent
==
nullptr
)
if
(
parent
==
nullptr
)
continue
;
continue
;
size_t
missing
=
0
;
size_t
missing
=
0
;
for
(
auto
r
:
*
this
)
for
(
auto
r
:
*
this
)
if
(
not
hasParent
(
r
,
*
parent
,
*
linkValidator
))
if
(
not
hasParent
(
r
,
*
parent
,
*
linkValidator
))
++
missing
;
++
missing
;
if
(
missing
)
if
(
missing
)
{
{
std
::
cerr
<<
"Links for "
<<
linkValidator
->
mLinkGroupLabel
<<
" are incomplete"
<<
std
::
endl
std
::
cerr
<<
"Links for "
<<
linkValidator
->
mLinkGroupLabel
<<
" are incomplete"
<<
std
::
endl
<<
" There are "
<<
missing
<<
" items in "
<<
mName
<<
" that don't have matching parent items in "
<<
parent
->
mName
<<
std
::
endl
;
<<
" There are "
<<
missing
<<
" items in "
<<
mName
<<
" that don't have matching parent items in "
<<
parent
->
mName
<<
std
::
endl
;
}
}
}
}
}
}
const
Validator
&
Category
::
getValidator
()
const
const
Validator
&
Category
::
getValidator
()
const
{
{
if
(
mValidator
==
nullptr
)
if
(
mValidator
==
nullptr
)
throw
std
::
runtime_error
(
"no Validator defined yet"
);
throw
std
::
runtime_error
(
"no Validator defined yet"
);
...
@@ -2179,12 +2271,12 @@ iset Category::fields() const
...
@@ -2179,12 +2271,12 @@ iset Category::fields() const
{
{
if
(
mValidator
==
nullptr
)
if
(
mValidator
==
nullptr
)
throw
std
::
runtime_error
(
"No Validator specified"
);
throw
std
::
runtime_error
(
"No Validator specified"
);
if
(
mCatValidator
==
nullptr
)
if
(
mCatValidator
==
nullptr
)
mValidator
->
reportError
(
"undefined Category"
,
true
);
mValidator
->
reportError
(
"undefined Category"
,
true
);
iset
result
;
iset
result
;
for
(
auto
&
iv
:
mCatValidator
->
mItemValidators
)
for
(
auto
&
iv
:
mCatValidator
->
mItemValidators
)
result
.
insert
(
iv
.
mTag
);
result
.
insert
(
iv
.
mTag
);
return
result
;
return
result
;
}
}
...
@@ -2193,10 +2285,10 @@ iset Category::mandatoryFields() const
...
@@ -2193,10 +2285,10 @@ iset Category::mandatoryFields() const
{
{
if
(
mValidator
==
nullptr
)
if
(
mValidator
==
nullptr
)
throw
std
::
runtime_error
(
"No Validator specified"
);
throw
std
::
runtime_error
(
"No Validator specified"
);
if
(
mCatValidator
==
nullptr
)
if
(
mCatValidator
==
nullptr
)
mValidator
->
reportError
(
"undefined Category"
,
true
);
mValidator
->
reportError
(
"undefined Category"
,
true
);
return
mCatValidator
->
mMandatoryFields
;
return
mCatValidator
->
mMandatoryFields
;
}
}
...
@@ -2204,28 +2296,121 @@ iset Category::keyFields() const
...
@@ -2204,28 +2296,121 @@ iset Category::keyFields() const
{
{
if
(
mValidator
==
nullptr
)
if
(
mValidator
==
nullptr
)
throw
std
::
runtime_error
(
"No Validator specified"
);
throw
std
::
runtime_error
(
"No Validator specified"
);
if
(
mCatValidator
==
nullptr
)
if
(
mCatValidator
==
nullptr
)
mValidator
->
reportError
(
"undefined Category"
,
true
);
mValidator
->
reportError
(
"undefined Category"
,
true
);
return
iset
{
mCatValidator
->
mKeys
.
begin
(),
mCatValidator
->
mKeys
.
end
()
};
return
iset
{
mCatValidator
->
mKeys
.
begin
(),
mCatValidator
->
mKeys
.
end
()
};
}
}
std
::
set
<
size_t
>
Category
::
keyFieldsByIndex
()
const
std
::
set
<
size_t
>
Category
::
keyFieldsByIndex
()
const
{
{
if
(
mValidator
==
nullptr
)
if
(
mValidator
==
nullptr
)
throw
std
::
runtime_error
(
"No Validator specified"
);
throw
std
::
runtime_error
(
"No Validator specified"
);
if
(
mCatValidator
==
nullptr
)
if
(
mCatValidator
==
nullptr
)
mValidator
->
reportError
(
"undefined Category"
,
true
);
mValidator
->
reportError
(
"undefined Category"
,
true
);
std
::
set
<
size_t
>
result
;
std
::
set
<
size_t
>
result
;
for
(
auto
&
k
:
mCatValidator
->
mKeys
)
for
(
auto
&
k
:
mCatValidator
->
mKeys
)
result
.
insert
(
getColumnIndex
(
k
));
result
.
insert
(
getColumnIndex
(
k
));
return
result
;
return
result
;
}
}
bool
operator
==
(
const
Category
&
a
,
const
Category
&
b
)
{
using
namespace
std
::
placeholders
;
// set<std::string> tagsA(a.fields()), tagsB(b.fields());
//
// if (tagsA != tagsB)
// std::cout << "Unequal number of fields" << std::endl;
auto
&
validator
=
a
.
getValidator
();
auto
catValidator
=
validator
.
getValidatorForCategory
(
a
.
name
());
if
(
catValidator
==
nullptr
)
throw
std
::
runtime_error
(
"missing cat validator"
);
typedef
std
::
function
<
int
(
const
char
*
,
const
char
*
)
>
compType
;
std
::
vector
<
std
::
tuple
<
std
::
string
,
compType
>>
tags
;
auto
keys
=
catValidator
->
mKeys
;
std
::
vector
<
size_t
>
keyIx
;
for
(
auto
&
tag
:
a
.
fields
())
{
auto
iv
=
catValidator
->
getValidatorForItem
(
tag
);
if
(
iv
==
nullptr
)
throw
std
::
runtime_error
(
"missing item validator"
);
auto
tv
=
iv
->
mType
;
if
(
tv
==
nullptr
)
throw
std
::
runtime_error
(
"missing type validator"
);
tags
.
push_back
(
std
::
make_tuple
(
tag
,
std
::
bind
(
&
cif
::
ValidateType
::
compare
,
tv
,
std
::
placeholders
::
_1
,
std
::
placeholders
::
_2
)));
auto
pred
=
[
tag
](
const
std
::
string
&
s
)
->
bool
{
return
cif
::
iequals
(
tag
,
s
)
==
0
;
};
if
(
find_if
(
keys
.
begin
(),
keys
.
end
(),
pred
)
==
keys
.
end
())
keyIx
.
push_back
(
tags
.
size
()
-
1
);
}
// a.reorderByIndex();
// b.reorderByIndex();
auto
rowEqual
=
[
&
](
const
cif
::
Row
&
a
,
const
cif
::
Row
&
b
)
{
int
d
=
0
;
for
(
auto
kix
:
keyIx
)
{
std
::
string
tag
;
compType
compare
;
std
::
tie
(
tag
,
compare
)
=
tags
[
kix
];
d
=
compare
(
a
[
tag
].
c_str
(),
b
[
tag
].
c_str
());
if
(
d
!=
0
)
break
;
}
return
d
==
0
;
};
auto
ai
=
a
.
begin
(),
bi
=
b
.
begin
();
while
(
ai
!=
a
.
end
()
or
bi
!=
b
.
end
())
{
if
(
ai
==
a
.
end
()
or
bi
==
b
.
end
())
return
false
;
cif
::
Row
ra
=
*
ai
,
rb
=
*
bi
;
if
(
not
rowEqual
(
ra
,
rb
))
return
false
;
std
::
vector
<
std
::
string
>
missingA
,
missingB
,
different
;
for
(
auto
&
tt
:
tags
)
{
std
::
string
tag
;
compType
compare
;
std
::
tie
(
tag
,
compare
)
=
tt
;
// make it an option to compare unapplicable to empty or something
const
char
*
ta
=
ra
[
tag
].
c_str
();
if
(
strcmp
(
ta
,
"."
)
==
0
)
ta
=
""
;
const
char
*
tb
=
rb
[
tag
].
c_str
();
if
(
strcmp
(
tb
,
"."
)
==
0
)
tb
=
""
;
if
(
compare
(
ta
,
tb
)
!=
0
)
return
false
;
}
++
ai
;
++
bi
;
}
return
true
;
}
// auto Category::iterator::operator++() -> iterator&
// auto Category::iterator::operator++() -> iterator&
// {
// {
// mCurrent = Row(mCurrent.data()->mNext);
// mCurrent = Row(mCurrent.data()->mNext);
...
@@ -2241,52 +2426,27 @@ std::set<size_t> Category::keyFieldsByIndex() const
...
@@ -2241,52 +2426,27 @@ std::set<size_t> Category::keyFieldsByIndex() const
namespace
detail
namespace
detail
{
{
size_t
writeValue
(
std
::
ostream
&
os
,
std
::
string
value
,
size_t
offset
,
size_t
width
)
size_t
writeValue
(
std
::
ostream
&
os
,
std
::
string
value
,
size_t
offset
,
size_t
width
)
{
if
(
value
.
find
(
'\n'
)
!=
std
::
string
::
npos
or
width
==
0
or
value
.
length
()
>=
132
)
// write as text field
{
ba
::
replace_all
(
value
,
"
\n
;"
,
"
\n\\
;"
);
if
(
offset
>
0
)
os
<<
std
::
endl
;
os
<<
';'
<<
value
;
if
(
not
ba
::
ends_with
(
value
,
"
\n
"
))
os
<<
std
::
endl
;
os
<<
';'
<<
std
::
endl
;
offset
=
0
;
}
else
if
(
isUnquotedString
(
value
.
c_str
()))
{
{
os
<<
value
;
if
(
value
.
find
(
'\n'
)
!=
std
::
string
::
npos
or
width
==
0
or
value
.
length
()
>=
132
)
// write as text field
if
(
value
.
length
()
<
width
)
{
os
<<
std
::
string
(
width
-
value
.
length
(),
' '
);
offset
+=
width
;
}
else
{
{
os
<<
' '
;
ba
::
replace_all
(
value
,
"
\n
;"
,
"
\n\\
;"
);
offset
+=
value
.
length
()
+
1
;
if
(
offset
>
0
)
os
<<
std
::
endl
;
os
<<
';'
<<
value
;
if
(
not
ba
::
ends_with
(
value
,
"
\n
"
))
os
<<
std
::
endl
;
os
<<
';'
<<
std
::
endl
;
offset
=
0
;
}
}
}
else
if
(
isUnquotedString
(
value
.
c_str
()))
else
{
bool
done
=
false
;
for
(
char
q
:
{
'\''
,
'"'
})
{
{
auto
p
=
value
.
find
(
q
);
// see if we can use the quote character
os
<<
value
;
while
(
p
!=
std
::
string
::
npos
and
isNonBlank
(
value
[
p
+
1
])
and
value
[
p
+
1
]
!=
q
)
p
=
value
.
find
(
q
,
p
+
1
);
if
(
p
!=
std
::
string
::
npos
)
continue
;
os
<<
q
<<
value
<<
q
;
if
(
value
.
length
()
+
2
<
width
)
if
(
value
.
length
()
<
width
)
{
{
os
<<
std
::
string
(
width
-
value
.
length
()
-
2
,
' '
);
os
<<
std
::
string
(
width
-
value
.
length
(),
' '
);
offset
+=
width
;
offset
+=
width
;
}
}
else
else
...
@@ -2294,47 +2454,72 @@ size_t writeValue(std::ostream& os, std::string value, size_t offset, size_t wid
...
@@ -2294,47 +2454,72 @@ size_t writeValue(std::ostream& os, std::string value, size_t offset, size_t wid
os
<<
' '
;
os
<<
' '
;
offset
+=
value
.
length
()
+
1
;
offset
+=
value
.
length
()
+
1
;
}
}
done
=
true
;
break
;
}
}
else
if
(
not
done
)
{
{
if
(
offset
>
0
)
bool
done
=
false
;
os
<<
std
::
endl
;
for
(
char
q
:
{
'\''
,
'"'
})
os
<<
';'
<<
value
<<
std
::
endl
{
<<
';'
<<
std
::
endl
;
auto
p
=
value
.
find
(
q
);
// see if we can use the quote character
offset
=
0
;
while
(
p
!=
std
::
string
::
npos
and
isNonBlank
(
value
[
p
+
1
])
and
value
[
p
+
1
]
!=
q
)
p
=
value
.
find
(
q
,
p
+
1
);
if
(
p
!=
std
::
string
::
npos
)
continue
;
os
<<
q
<<
value
<<
q
;
if
(
value
.
length
()
+
2
<
width
)
{
os
<<
std
::
string
(
width
-
value
.
length
()
-
2
,
' '
);
offset
+=
width
;
}
else
{
os
<<
' '
;
offset
+=
value
.
length
()
+
1
;
}
done
=
true
;
break
;
}
if
(
not
done
)
{
if
(
offset
>
0
)
os
<<
std
::
endl
;
os
<<
';'
<<
value
<<
std
::
endl
<<
';'
<<
std
::
endl
;
offset
=
0
;
}
}
}
return
offset
;
}
}
return
offset
;
}
// namespace detail
}
}
void
Category
::
write
(
std
::
ostream
&
os
,
const
std
::
vector
<
size_t
>&
order
,
bool
includeEmptyColumns
)
void
Category
::
write
(
std
::
ostream
&
os
,
const
std
::
vector
<
size_t
>
&
order
,
bool
includeEmptyColumns
)
{
{
if
(
empty
())
if
(
empty
())
return
;
return
;
// If the first Row has a next, we need a loop_
// If the first Row has a next, we need a loop_
bool
needLoop
=
(
mHead
->
mNext
!=
nullptr
);
bool
needLoop
=
(
mHead
->
mNext
!=
nullptr
);
if
(
needLoop
)
if
(
needLoop
)
{
{
os
<<
"loop_"
<<
std
::
endl
;
os
<<
"loop_"
<<
std
::
endl
;
std
::
vector
<
size_t
>
columnWidths
;
std
::
vector
<
size_t
>
columnWidths
;
for
(
auto
cix
:
order
)
for
(
auto
cix
:
order
)
{
{
auto
&
col
=
mColumns
[
cix
];
auto
&
col
=
mColumns
[
cix
];
os
<<
'_'
<<
mName
<<
'.'
<<
col
.
mName
<<
' '
<<
std
::
endl
;
os
<<
'_'
<<
mName
<<
'.'
<<
col
.
mName
<<
' '
<<
std
::
endl
;
columnWidths
.
push_back
(
2
);
columnWidths
.
push_back
(
2
);
}
}
for
(
auto
Row
=
mHead
;
Row
!=
nullptr
;
Row
=
Row
->
mNext
)
for
(
auto
Row
=
mHead
;
Row
!=
nullptr
;
Row
=
Row
->
mNext
)
{
{
for
(
auto
v
=
Row
->
mValues
;
v
!=
nullptr
;
v
=
v
->
mNext
)
for
(
auto
v
=
Row
->
mValues
;
v
!=
nullptr
;
v
=
v
->
mNext
)
...
@@ -2342,7 +2527,7 @@ void Category::write(std::ostream& os, const std::vector<size_t>& order, bool in
...
@@ -2342,7 +2527,7 @@ void Category::write(std::ostream& os, const std::vector<size_t>& order, bool in
if
(
strchr
(
v
->
mText
,
'\n'
)
==
nullptr
)
if
(
strchr
(
v
->
mText
,
'\n'
)
==
nullptr
)
{
{
size_t
l
=
strlen
(
v
->
mText
);
size_t
l
=
strlen
(
v
->
mText
);
if
(
not
isUnquotedString
(
v
->
mText
))
if
(
not
isUnquotedString
(
v
->
mText
))
l
+=
2
;
l
+=
2
;
...
@@ -2354,15 +2539,15 @@ void Category::write(std::ostream& os, const std::vector<size_t>& order, bool in
...
@@ -2354,15 +2539,15 @@ void Category::write(std::ostream& os, const std::vector<size_t>& order, bool in
}
}
}
}
}
}
for
(
auto
Row
=
mHead
;
Row
!=
nullptr
;
Row
=
Row
->
mNext
)
// loop over rows
for
(
auto
Row
=
mHead
;
Row
!=
nullptr
;
Row
=
Row
->
mNext
)
// loop over rows
{
{
size_t
offset
=
0
;
size_t
offset
=
0
;
for
(
size_t
cix
:
order
)
for
(
size_t
cix
:
order
)
{
{
size_t
w
=
columnWidths
[
cix
];
size_t
w
=
columnWidths
[
cix
];
std
::
string
s
;
std
::
string
s
;
for
(
auto
iv
=
Row
->
mValues
;
iv
!=
nullptr
;
iv
=
iv
->
mNext
)
for
(
auto
iv
=
Row
->
mValues
;
iv
!=
nullptr
;
iv
=
iv
->
mNext
)
{
{
...
@@ -2372,10 +2557,10 @@ void Category::write(std::ostream& os, const std::vector<size_t>& order, bool in
...
@@ -2372,10 +2557,10 @@ void Category::write(std::ostream& os, const std::vector<size_t>& order, bool in
break
;
break
;
}
}
}
}
if
(
s
.
empty
())
if
(
s
.
empty
())
s
=
"?"
;
s
=
"?"
;
size_t
l
=
s
.
length
();
size_t
l
=
s
.
length
();
if
(
not
isUnquotedString
(
s
.
c_str
()))
if
(
not
isUnquotedString
(
s
.
c_str
()))
l
+=
2
;
l
+=
2
;
...
@@ -2387,41 +2572,41 @@ void Category::write(std::ostream& os, const std::vector<size_t>& order, bool in
...
@@ -2387,41 +2572,41 @@ void Category::write(std::ostream& os, const std::vector<size_t>& order, bool in
os
<<
std
::
endl
;
os
<<
std
::
endl
;
offset
=
0
;
offset
=
0
;
}
}
offset
=
detail
::
writeValue
(
os
,
s
,
offset
,
w
);
offset
=
detail
::
writeValue
(
os
,
s
,
offset
,
w
);
if
(
offset
>=
132
)
if
(
offset
>=
132
)
{
{
os
<<
std
::
endl
;
os
<<
std
::
endl
;
offset
=
0
;
offset
=
0
;
}
}
}
}
if
(
offset
>
0
)
if
(
offset
>
0
)
os
<<
std
::
endl
;
os
<<
std
::
endl
;
}
}
}
}
else
else
{
{
// first find the indent level
// first find the indent level
size_t
l
=
0
;
size_t
l
=
0
;
for
(
auto
&
col
:
mColumns
)
for
(
auto
&
col
:
mColumns
)
{
{
std
::
string
tag
=
'_'
+
mName
+
'.'
+
col
.
mName
;
std
::
string
tag
=
'_'
+
mName
+
'.'
+
col
.
mName
;
if
(
l
<
tag
.
length
())
if
(
l
<
tag
.
length
())
l
=
tag
.
length
();
l
=
tag
.
length
();
}
}
l
+=
3
;
l
+=
3
;
for
(
size_t
cix
:
order
)
for
(
size_t
cix
:
order
)
{
{
auto
&
col
=
mColumns
[
cix
];
auto
&
col
=
mColumns
[
cix
];
os
<<
'_'
<<
mName
<<
'.'
<<
col
.
mName
<<
std
::
string
(
l
-
col
.
mName
.
length
()
-
mName
.
length
()
-
2
,
' '
);
os
<<
'_'
<<
mName
<<
'.'
<<
col
.
mName
<<
std
::
string
(
l
-
col
.
mName
.
length
()
-
mName
.
length
()
-
2
,
' '
);
std
::
string
s
;
std
::
string
s
;
for
(
auto
iv
=
mHead
->
mValues
;
iv
!=
nullptr
;
iv
=
iv
->
mNext
)
for
(
auto
iv
=
mHead
->
mValues
;
iv
!=
nullptr
;
iv
=
iv
->
mNext
)
{
{
...
@@ -2431,10 +2616,10 @@ void Category::write(std::ostream& os, const std::vector<size_t>& order, bool in
...
@@ -2431,10 +2616,10 @@ void Category::write(std::ostream& os, const std::vector<size_t>& order, bool in
break
;
break
;
}
}
}
}
if
(
s
.
empty
())
if
(
s
.
empty
())
s
=
"?"
;
s
=
"?"
;
size_t
offset
=
l
;
size_t
offset
=
l
;
if
(
s
.
length
()
+
l
>=
kMaxLineLength
)
if
(
s
.
length
()
+
l
>=
kMaxLineLength
)
{
{
...
@@ -2450,23 +2635,23 @@ void Category::write(std::ostream& os, const std::vector<size_t>& order, bool in
...
@@ -2450,23 +2635,23 @@ void Category::write(std::ostream& os, const std::vector<size_t>& order, bool in
os
<<
"# "
<<
std
::
endl
;
os
<<
"# "
<<
std
::
endl
;
}
}
void
Category
::
write
(
std
::
ostream
&
os
)
void
Category
::
write
(
std
::
ostream
&
os
)
{
{
std
::
vector
<
size_t
>
order
(
mColumns
.
size
());
std
::
vector
<
size_t
>
order
(
mColumns
.
size
());
iota
(
order
.
begin
(),
order
.
end
(),
0
);
iota
(
order
.
begin
(),
order
.
end
(),
0
);
write
(
os
,
order
,
false
);
write
(
os
,
order
,
false
);
}
}
void
Category
::
write
(
std
::
ostream
&
os
,
const
std
::
vector
<
std
::
string
>&
columns
)
void
Category
::
write
(
std
::
ostream
&
os
,
const
std
::
vector
<
std
::
string
>
&
columns
)
{
{
// make sure all columns are present
// make sure all columns are present
for
(
auto
&
c
:
columns
)
for
(
auto
&
c
:
columns
)
addColumn
(
c
);
addColumn
(
c
);
std
::
vector
<
size_t
>
order
;
std
::
vector
<
size_t
>
order
;
order
.
reserve
(
mColumns
.
size
());
order
.
reserve
(
mColumns
.
size
());
for
(
auto
&
c
:
columns
)
for
(
auto
&
c
:
columns
)
order
.
push_back
(
getColumnIndex
(
c
));
order
.
push_back
(
getColumnIndex
(
c
));
for
(
size_t
i
=
0
;
i
<
mColumns
.
size
();
++
i
)
for
(
size_t
i
=
0
;
i
<
mColumns
.
size
();
++
i
)
...
@@ -2489,7 +2674,7 @@ void Category::update_value(RowSet &&rows, const std::string &tag, const std::st
...
@@ -2489,7 +2674,7 @@ void Category::update_value(RowSet &&rows, const std::string &tag, const std::st
if
(
colIx
>=
mColumns
.
size
())
if
(
colIx
>=
mColumns
.
size
())
throw
std
::
runtime_error
(
"Invalid column "
+
value
+
" for "
+
mName
);
throw
std
::
runtime_error
(
"Invalid column "
+
value
+
" for "
+
mName
);
auto
&
col
=
mColumns
[
colIx
];
auto
&
col
=
mColumns
[
colIx
];
// check the value
// check the value
if
(
col
.
mValidator
)
if
(
col
.
mValidator
)
...
@@ -2497,26 +2682,26 @@ void Category::update_value(RowSet &&rows, const std::string &tag, const std::st
...
@@ -2497,26 +2682,26 @@ void Category::update_value(RowSet &&rows, const std::string &tag, const std::st
// first some sanity checks, what was the old value and is it the same for all rows?
// first some sanity checks, what was the old value and is it the same for all rows?
std
::
string
oldValue
=
rows
.
front
()[
tag
].
c_str
();
std
::
string
oldValue
=
rows
.
front
()[
tag
].
c_str
();
for
(
auto
&
row
:
rows
)
for
(
auto
&
row
:
rows
)
{
{
if
(
oldValue
!=
row
[
tag
].
c_str
())
if
(
oldValue
!=
row
[
tag
].
c_str
())
throw
std
::
runtime_error
(
"Inconsistent old values in update_value"
);
throw
std
::
runtime_error
(
"Inconsistent old values in update_value"
);
}
}
if
(
oldValue
==
value
)
// no need to do anything
if
(
oldValue
==
value
)
// no need to do anything
return
;
return
;
// update rows, but do not cascade
// update rows, but do not cascade
for
(
auto
&
row
:
rows
)
for
(
auto
&
row
:
rows
)
row
.
assign
(
colIx
,
value
,
true
);
row
.
assign
(
colIx
,
value
,
true
);
// see if we need to update any child categories that depend on this value
// see if we need to update any child categories that depend on this value
auto
&
validator
=
getValidator
();
auto
&
validator
=
getValidator
();
auto
&
db
=
mDb
;
auto
&
db
=
mDb
;
for
(
auto
parent
:
rows
)
for
(
auto
parent
:
rows
)
{
{
for
(
auto
linked
:
validator
.
getLinksForParent
(
mName
))
for
(
auto
linked
:
validator
.
getLinksForParent
(
mName
))
{
{
auto
childCat
=
db
.
get
(
linked
->
mChildCategory
);
auto
childCat
=
db
.
get
(
linked
->
mChildCategory
);
if
(
childCat
==
nullptr
)
if
(
childCat
==
nullptr
)
...
@@ -2527,7 +2712,7 @@ void Category::update_value(RowSet &&rows, const std::string &tag, const std::st
...
@@ -2527,7 +2712,7 @@ void Category::update_value(RowSet &&rows, const std::string &tag, const std::st
Condition
cond
;
Condition
cond
;
std
::
string
childTag
;
std
::
string
childTag
;
for
(
size_t
ix
=
0
;
ix
<
linked
->
mParentKeys
.
size
();
++
ix
)
for
(
size_t
ix
=
0
;
ix
<
linked
->
mParentKeys
.
size
();
++
ix
)
{
{
std
::
string
pk
=
linked
->
mParentKeys
[
ix
];
std
::
string
pk
=
linked
->
mParentKeys
[
ix
];
...
@@ -2544,7 +2729,7 @@ void Category::update_value(RowSet &&rows, const std::string &tag, const std::st
...
@@ -2544,7 +2729,7 @@ void Category::update_value(RowSet &&rows, const std::string &tag, const std::st
cond
=
std
::
move
(
cond
)
&&
Key
(
ck
)
==
parent
[
pk
].
c_str
();
cond
=
std
::
move
(
cond
)
&&
Key
(
ck
)
==
parent
[
pk
].
c_str
();
}
}
auto
children
=
RowSet
{
*
childCat
,
std
::
move
(
cond
)
};
auto
children
=
RowSet
{
*
childCat
,
std
::
move
(
cond
)
};
if
(
children
.
empty
())
if
(
children
.
empty
())
continue
;
continue
;
...
@@ -2554,10 +2739,10 @@ void Category::update_value(RowSet &&rows, const std::string &tag, const std::st
...
@@ -2554,10 +2739,10 @@ void Category::update_value(RowSet &&rows, const std::string &tag, const std::st
RowSet
process
(
*
childCat
);
RowSet
process
(
*
childCat
);
for
(
auto
child
:
children
)
for
(
auto
child
:
children
)
{
{
Condition
cond_c
;
Condition
cond_c
;
for
(
size_t
ix
=
0
;
ix
<
linked
->
mParentKeys
.
size
();
++
ix
)
for
(
size_t
ix
=
0
;
ix
<
linked
->
mParentKeys
.
size
();
++
ix
)
{
{
std
::
string
pk
=
linked
->
mParentKeys
[
ix
];
std
::
string
pk
=
linked
->
mParentKeys
[
ix
];
...
@@ -2577,7 +2762,7 @@ void Category::update_value(RowSet &&rows, const std::string &tag, const std::st
...
@@ -2577,7 +2762,7 @@ void Category::update_value(RowSet &&rows, const std::string &tag, const std::st
// oops, we need to split this child, unless a row already exists for the new value
// oops, we need to split this child, unless a row already exists for the new value
Condition
check
;
Condition
check
;
for
(
size_t
ix
=
0
;
ix
<
linked
->
mParentKeys
.
size
();
++
ix
)
for
(
size_t
ix
=
0
;
ix
<
linked
->
mParentKeys
.
size
();
++
ix
)
{
{
std
::
string
pk
=
linked
->
mParentKeys
[
ix
];
std
::
string
pk
=
linked
->
mParentKeys
[
ix
];
...
@@ -2591,7 +2776,7 @@ void Category::update_value(RowSet &&rows, const std::string &tag, const std::st
...
@@ -2591,7 +2776,7 @@ void Category::update_value(RowSet &&rows, const std::string &tag, const std::st
check
=
std
::
move
(
check
)
&&
Key
(
ck
)
==
parent
[
pk
].
c_str
();
check
=
std
::
move
(
check
)
&&
Key
(
ck
)
==
parent
[
pk
].
c_str
();
}
}
if
(
childCat
->
exists
(
std
::
move
(
check
)))
// phew..., narrow escape
if
(
childCat
->
exists
(
std
::
move
(
check
)))
// phew..., narrow escape
continue
;
continue
;
// create the actual copy, if we can...
// create the actual copy, if we can...
...
@@ -2605,7 +2790,7 @@ void Category::update_value(RowSet &&rows, const std::string &tag, const std::st
...
@@ -2605,7 +2790,7 @@ void Category::update_value(RowSet &&rows, const std::string &tag, const std::st
}
}
}
}
// cannot update this...
// cannot update this...
if
(
cif
::
VERBOSE
)
if
(
cif
::
VERBOSE
)
std
::
cerr
<<
"Cannot update child "
<<
childCat
->
mName
<<
"."
<<
childTag
<<
" with value "
<<
value
<<
std
::
endl
;
std
::
cerr
<<
"Cannot update child "
<<
childCat
->
mName
<<
"."
<<
childTag
<<
" with value "
<<
value
<<
std
::
endl
;
}
}
...
@@ -2613,19 +2798,19 @@ void Category::update_value(RowSet &&rows, const std::string &tag, const std::st
...
@@ -2613,19 +2798,19 @@ void Category::update_value(RowSet &&rows, const std::string &tag, const std::st
// finally, update the children
// finally, update the children
if
(
not
process
.
empty
())
if
(
not
process
.
empty
())
childCat
->
update_value
(
std
::
move
(
process
),
childTag
,
value
);
childCat
->
update_value
(
std
::
move
(
process
),
childTag
,
value
);
}
}
}
}
}
}
// --------------------------------------------------------------------
// --------------------------------------------------------------------
Row
::
Row
(
const
Row
&
rhs
)
Row
::
Row
(
const
Row
&
rhs
)
:
mData
(
rhs
.
mData
)
:
mData
(
rhs
.
mData
)
,
mCascade
(
rhs
.
mCascade
)
,
mCascade
(
rhs
.
mCascade
)
{
{
}
}
Row
::
Row
(
Row
&&
rhs
)
Row
::
Row
(
Row
&&
rhs
)
:
mData
(
rhs
.
mData
)
:
mData
(
rhs
.
mData
)
,
mCascade
(
rhs
.
mCascade
)
,
mCascade
(
rhs
.
mCascade
)
{
{
...
@@ -2634,7 +2819,6 @@ Row::Row(Row&& rhs)
...
@@ -2634,7 +2819,6 @@ Row::Row(Row&& rhs)
Row
::~
Row
()
Row
::~
Row
()
{
{
}
}
void
Row
::
next
()
void
Row
::
next
()
...
@@ -2643,30 +2827,31 @@ void Row::next()
...
@@ -2643,30 +2827,31 @@ void Row::next()
mData
=
mData
->
mNext
;
mData
=
mData
->
mNext
;
}
}
Row
&
Row
::
operator
=
(
Row
&&
rhs
)
Row
&
Row
::
operator
=
(
Row
&&
rhs
)
{
{
mData
=
rhs
.
mData
;
rhs
.
mData
=
nullptr
;
mData
=
rhs
.
mData
;
rhs
.
mData
=
nullptr
;
mCascade
=
rhs
.
mCascade
;
mCascade
=
rhs
.
mCascade
;
return
*
this
;
return
*
this
;
}
}
Row
&
Row
::
operator
=
(
const
Row
&
rhs
)
Row
&
Row
::
operator
=
(
const
Row
&
rhs
)
{
{
mData
=
rhs
.
mData
;
mData
=
rhs
.
mData
;
mCascade
=
rhs
.
mCascade
;
mCascade
=
rhs
.
mCascade
;
return
*
this
;
return
*
this
;
}
}
void
Row
::
assign
(
const
std
::
vector
<
Item
>
&
values
)
void
Row
::
assign
(
const
std
::
vector
<
Item
>
&
values
)
{
{
auto
cat
=
mData
->
mCategory
;
auto
cat
=
mData
->
mCategory
;
std
::
map
<
std
::
string
,
std
::
tuple
<
size_t
,
std
::
string
,
std
::
string
>>
changed
;
std
::
map
<
std
::
string
,
std
::
tuple
<
size_t
,
std
::
string
,
std
::
string
>>
changed
;
for
(
auto
&
value
:
values
)
for
(
auto
&
value
:
values
)
{
{
auto
columnIx
=
cat
->
addColumn
(
value
.
name
());
auto
columnIx
=
cat
->
addColumn
(
value
.
name
());
auto
&
col
=
cat
->
mColumns
[
columnIx
];
auto
&
col
=
cat
->
mColumns
[
columnIx
];
std
::
string
tag
=
col
.
mValidator
?
col
.
mValidator
->
mTag
:
std
::
to_string
(
columnIx
);
std
::
string
tag
=
col
.
mValidator
?
col
.
mValidator
->
mTag
:
std
::
to_string
(
columnIx
);
changed
[
tag
]
=
std
::
make_tuple
(
columnIx
,
operator
[](
columnIx
).
c_str
(),
value
.
value
());
changed
[
tag
]
=
std
::
make_tuple
(
columnIx
,
operator
[](
columnIx
).
c_str
(),
value
.
value
());
...
@@ -2678,10 +2863,10 @@ void Row::assign(const std::vector<Item>& values)
...
@@ -2678,10 +2863,10 @@ void Row::assign(const std::vector<Item>& values)
// auto iv = col.mValidator;
// auto iv = col.mValidator;
if
(
mCascade
)
if
(
mCascade
)
{
{
auto
&
validator
=
cat
->
getValidator
();
auto
&
validator
=
cat
->
getValidator
();
auto
&
db
=
cat
->
db
();
auto
&
db
=
cat
->
db
();
for
(
auto
linked
:
validator
.
getLinksForParent
(
cat
->
mName
))
for
(
auto
linked
:
validator
.
getLinksForParent
(
cat
->
mName
))
{
{
auto
childCat
=
db
.
get
(
linked
->
mChildCategory
);
auto
childCat
=
db
.
get
(
linked
->
mChildCategory
);
if
(
childCat
==
nullptr
)
if
(
childCat
==
nullptr
)
...
@@ -2694,7 +2879,7 @@ void Row::assign(const std::vector<Item>& values)
...
@@ -2694,7 +2879,7 @@ void Row::assign(const std::vector<Item>& values)
std
::
string
childTag
;
std
::
string
childTag
;
std
::
vector
<
Item
>
newValues
;
std
::
vector
<
Item
>
newValues
;
for
(
size_t
ix
=
0
;
ix
<
linked
->
mParentKeys
.
size
();
++
ix
)
for
(
size_t
ix
=
0
;
ix
<
linked
->
mParentKeys
.
size
();
++
ix
)
{
{
std
::
string
pk
=
linked
->
mParentKeys
[
ix
];
std
::
string
pk
=
linked
->
mParentKeys
[
ix
];
...
@@ -2708,46 +2893,46 @@ void Row::assign(const std::vector<Item>& values)
...
@@ -2708,46 +2893,46 @@ void Row::assign(const std::vector<Item>& values)
}
}
else
else
{
{
const
char
*
value
=
(
*
this
)[
pk
].
c_str
();
const
char
*
value
=
(
*
this
)[
pk
].
c_str
();
cond
=
std
::
move
(
cond
)
&&
(
Key
(
ck
)
==
value
);
cond
=
std
::
move
(
cond
)
&&
(
Key
(
ck
)
==
value
);
}
}
}
}
auto
rows
=
childCat
->
find
(
std
::
move
(
cond
));
auto
rows
=
childCat
->
find
(
std
::
move
(
cond
));
for
(
auto
&
cr
:
rows
)
for
(
auto
&
cr
:
rows
)
cr
.
assign
(
newValues
);
cr
.
assign
(
newValues
);
}
}
}
}
}
}
void
Row
::
assign
(
const
Item
&
value
,
bool
skipUpdateLinked
)
void
Row
::
assign
(
const
Item
&
value
,
bool
skipUpdateLinked
)
{
{
assign
(
value
.
name
(),
value
.
value
(),
skipUpdateLinked
);
assign
(
value
.
name
(),
value
.
value
(),
skipUpdateLinked
);
}
}
void
Row
::
assign
(
const
std
::
string
&
name
,
const
std
::
string
&
value
,
bool
skipUpdateLinked
)
void
Row
::
assign
(
const
std
::
string
&
name
,
const
std
::
string
&
value
,
bool
skipUpdateLinked
)
{
{
try
try
{
{
auto
cat
=
mData
->
mCategory
;
auto
cat
=
mData
->
mCategory
;
assign
(
cat
->
addColumn
(
name
),
value
,
skipUpdateLinked
);
assign
(
cat
->
addColumn
(
name
),
value
,
skipUpdateLinked
);
}
}
catch
(
const
std
::
exception
&
ex
)
catch
(
const
std
::
exception
&
ex
)
{
{
std
::
cerr
<<
"Could not assign value '"
<<
value
<<
"' to column _"
<<
mData
->
mCategory
->
name
()
<<
'.'
<<
name
<<
std
::
endl
;
std
::
cerr
<<
"Could not assign value '"
<<
value
<<
"' to column _"
<<
mData
->
mCategory
->
name
()
<<
'.'
<<
name
<<
std
::
endl
;
throw
;
throw
;
}
}
}
}
void
Row
::
assign
(
size_t
column
,
const
std
::
string
&
value
,
bool
skipUpdateLinked
)
void
Row
::
assign
(
size_t
column
,
const
std
::
string
&
value
,
bool
skipUpdateLinked
)
{
{
if
(
mData
==
nullptr
)
if
(
mData
==
nullptr
)
throw
std
::
logic_error
(
"invalid Row, no data assigning value '"
+
value
+
"' to column with index "
+
std
::
to_string
(
column
));
throw
std
::
logic_error
(
"invalid Row, no data assigning value '"
+
value
+
"' to column with index "
+
std
::
to_string
(
column
));
auto
cat
=
mData
->
mCategory
;
auto
cat
=
mData
->
mCategory
;
auto
&
col
=
cat
->
mColumns
[
column
];
auto
&
col
=
cat
->
mColumns
[
column
];
const
char
*
oldValue
=
nullptr
;
const
char
*
oldValue
=
nullptr
;
for
(
auto
iv
=
mData
->
mValues
;
iv
!=
nullptr
;
iv
=
iv
->
mNext
)
for
(
auto
iv
=
mData
->
mValues
;
iv
!=
nullptr
;
iv
=
iv
->
mNext
)
{
{
assert
(
iv
!=
iv
->
mNext
and
(
iv
->
mNext
==
nullptr
or
iv
!=
iv
->
mNext
->
mNext
));
assert
(
iv
!=
iv
->
mNext
and
(
iv
->
mNext
==
nullptr
or
iv
!=
iv
->
mNext
->
mNext
));
...
@@ -2758,8 +2943,8 @@ void Row::assign(size_t column, const std::string& value, bool skipUpdateLinked)
...
@@ -2758,8 +2943,8 @@ void Row::assign(size_t column, const std::string& value, bool skipUpdateLinked)
break
;
break
;
}
}
}
}
if
(
oldValue
!=
nullptr
and
value
==
oldValue
)
// no need to update
if
(
oldValue
!=
nullptr
and
value
==
oldValue
)
// no need to update
return
;
return
;
std
::
string
oldStrValue
=
oldValue
?
oldValue
:
""
;
std
::
string
oldStrValue
=
oldValue
?
oldValue
:
""
;
...
@@ -2770,10 +2955,10 @@ void Row::assign(size_t column, const std::string& value, bool skipUpdateLinked)
...
@@ -2770,10 +2955,10 @@ void Row::assign(size_t column, const std::string& value, bool skipUpdateLinked)
// If the field is part of the Key for this Category, remove it from the index
// If the field is part of the Key for this Category, remove it from the index
// before updating
// before updating
bool
reinsert
=
false
;
bool
reinsert
=
false
;
if
(
not
skipUpdateLinked
and
// an update of an Item's value
if
(
not
skipUpdateLinked
and
// an update of an Item's value
cat
->
mIndex
!=
nullptr
and
cat
->
keyFieldsByIndex
().
count
(
column
))
cat
->
mIndex
!=
nullptr
and
cat
->
keyFieldsByIndex
().
count
(
column
))
{
{
reinsert
=
cat
->
mIndex
->
find
(
mData
);
reinsert
=
cat
->
mIndex
->
find
(
mData
);
...
@@ -2784,7 +2969,7 @@ void Row::assign(size_t column, const std::string& value, bool skipUpdateLinked)
...
@@ -2784,7 +2969,7 @@ void Row::assign(size_t column, const std::string& value, bool skipUpdateLinked)
// first remove old value with cix
// first remove old value with cix
if
(
mData
->
mValues
==
nullptr
)
if
(
mData
->
mValues
==
nullptr
)
;
// nothing to do
;
// nothing to do
else
if
(
mData
->
mValues
->
mColumnIndex
==
column
)
else
if
(
mData
->
mValues
->
mColumnIndex
==
column
)
{
{
auto
iv
=
mData
->
mValues
;
auto
iv
=
mData
->
mValues
;
...
@@ -2802,7 +2987,7 @@ void Row::assign(size_t column, const std::string& value, bool skipUpdateLinked)
...
@@ -2802,7 +2987,7 @@ void Row::assign(size_t column, const std::string& value, bool skipUpdateLinked)
iv
->
mNext
=
nv
->
mNext
;
iv
->
mNext
=
nv
->
mNext
;
nv
->
mNext
=
nullptr
;
nv
->
mNext
=
nullptr
;
delete
nv
;
delete
nv
;
break
;
break
;
}
}
}
}
...
@@ -2810,8 +2995,8 @@ void Row::assign(size_t column, const std::string& value, bool skipUpdateLinked)
...
@@ -2810,8 +2995,8 @@ void Row::assign(size_t column, const std::string& value, bool skipUpdateLinked)
if
(
not
value
.
empty
())
if
(
not
value
.
empty
())
{
{
auto
nv
=
new
(
value
.
length
())
ItemValue
(
value
.
c_str
(),
column
);
auto
nv
=
new
(
value
.
length
())
ItemValue
(
value
.
c_str
(),
column
);
if
(
mData
->
mValues
==
nullptr
)
if
(
mData
->
mValues
==
nullptr
)
mData
->
mValues
=
nv
;
mData
->
mValues
=
nv
;
else
else
...
@@ -2830,10 +3015,10 @@ void Row::assign(size_t column, const std::string& value, bool skipUpdateLinked)
...
@@ -2830,10 +3015,10 @@ void Row::assign(size_t column, const std::string& value, bool skipUpdateLinked)
auto
iv
=
col
.
mValidator
;
auto
iv
=
col
.
mValidator
;
if
(
not
skipUpdateLinked
and
iv
!=
nullptr
and
mCascade
)
if
(
not
skipUpdateLinked
and
iv
!=
nullptr
and
mCascade
)
{
{
auto
&
validator
=
cat
->
getValidator
();
auto
&
validator
=
cat
->
getValidator
();
auto
&
db
=
cat
->
db
();
auto
&
db
=
cat
->
db
();
for
(
auto
linked
:
validator
.
getLinksForParent
(
cat
->
mName
))
for
(
auto
linked
:
validator
.
getLinksForParent
(
cat
->
mName
))
{
{
auto
childCat
=
db
.
get
(
linked
->
mChildCategory
);
auto
childCat
=
db
.
get
(
linked
->
mChildCategory
);
if
(
childCat
==
nullptr
)
if
(
childCat
==
nullptr
)
...
@@ -2844,7 +3029,7 @@ void Row::assign(size_t column, const std::string& value, bool skipUpdateLinked)
...
@@ -2844,7 +3029,7 @@ void Row::assign(size_t column, const std::string& value, bool skipUpdateLinked)
Condition
cond
;
Condition
cond
;
std
::
string
childTag
;
std
::
string
childTag
;
for
(
size_t
ix
=
0
;
ix
<
linked
->
mParentKeys
.
size
();
++
ix
)
for
(
size_t
ix
=
0
;
ix
<
linked
->
mParentKeys
.
size
();
++
ix
)
{
{
std
::
string
pk
=
linked
->
mParentKeys
[
ix
];
std
::
string
pk
=
linked
->
mParentKeys
[
ix
];
...
@@ -2859,7 +3044,7 @@ void Row::assign(size_t column, const std::string& value, bool skipUpdateLinked)
...
@@ -2859,7 +3044,7 @@ void Row::assign(size_t column, const std::string& value, bool skipUpdateLinked)
}
}
else
else
{
{
const
char
*
pk_value
=
(
*
this
)[
pk
].
c_str
();
const
char
*
pk_value
=
(
*
this
)[
pk
].
c_str
();
if
(
*
pk_value
==
0
)
if
(
*
pk_value
==
0
)
cond
=
std
::
move
(
cond
)
&&
Key
(
ck
)
==
Empty
();
cond
=
std
::
move
(
cond
)
&&
Key
(
ck
)
==
Empty
();
else
else
...
@@ -2881,7 +3066,7 @@ void Row::assign(size_t column, const std::string& value, bool skipUpdateLinked)
...
@@ -2881,7 +3066,7 @@ void Row::assign(size_t column, const std::string& value, bool skipUpdateLinked)
// we then skip this renam
// we then skip this renam
Condition
cond_n
;
Condition
cond_n
;
for
(
size_t
ix
=
0
;
ix
<
linked
->
mParentKeys
.
size
();
++
ix
)
for
(
size_t
ix
=
0
;
ix
<
linked
->
mParentKeys
.
size
();
++
ix
)
{
{
std
::
string
pk
=
linked
->
mParentKeys
[
ix
];
std
::
string
pk
=
linked
->
mParentKeys
[
ix
];
...
@@ -2893,7 +3078,7 @@ void Row::assign(size_t column, const std::string& value, bool skipUpdateLinked)
...
@@ -2893,7 +3078,7 @@ void Row::assign(size_t column, const std::string& value, bool skipUpdateLinked)
cond_n
=
std
::
move
(
cond_n
)
&&
Key
(
ck
)
==
value
;
cond_n
=
std
::
move
(
cond_n
)
&&
Key
(
ck
)
==
value
;
else
else
{
{
const
char
*
pk_value
=
(
*
this
)[
pk
].
c_str
();
const
char
*
pk_value
=
(
*
this
)[
pk
].
c_str
();
if
(
*
pk_value
==
0
)
if
(
*
pk_value
==
0
)
cond_n
=
std
::
move
(
cond_n
)
&&
Key
(
ck
)
==
Empty
();
cond_n
=
std
::
move
(
cond_n
)
&&
Key
(
ck
)
==
Empty
();
else
else
...
@@ -2906,17 +3091,17 @@ void Row::assign(size_t column, const std::string& value, bool skipUpdateLinked)
...
@@ -2906,17 +3091,17 @@ void Row::assign(size_t column, const std::string& value, bool skipUpdateLinked)
{
{
if
(
cif
::
VERBOSE
)
if
(
cif
::
VERBOSE
)
std
::
cerr
<<
"Will not rename in child category since there are already rows that link to the parent"
<<
std
::
endl
;
std
::
cerr
<<
"Will not rename in child category since there are already rows that link to the parent"
<<
std
::
endl
;
continue
;
continue
;
}
}
for
(
auto
&
cr
:
rows
)
for
(
auto
&
cr
:
rows
)
cr
.
assign
(
childTag
,
value
,
false
);
cr
.
assign
(
childTag
,
value
,
false
);
}
}
}
}
}
}
void
Row
::
swap
(
size_t
cix
,
ItemRow
*
a
,
ItemRow
*
b
)
void
Row
::
swap
(
size_t
cix
,
ItemRow
*
a
,
ItemRow
*
b
)
{
{
if
(
a
==
nullptr
or
b
==
nullptr
)
if
(
a
==
nullptr
or
b
==
nullptr
)
throw
std
::
logic_error
(
"invalid Rows in swap"
);
throw
std
::
logic_error
(
"invalid Rows in swap"
);
...
@@ -2924,14 +3109,14 @@ void Row::swap(size_t cix, ItemRow* a, ItemRow* b)
...
@@ -2924,14 +3109,14 @@ void Row::swap(size_t cix, ItemRow* a, ItemRow* b)
assert
(
a
->
mCategory
==
b
->
mCategory
);
assert
(
a
->
mCategory
==
b
->
mCategory
);
if
(
a
->
mCategory
!=
b
->
mCategory
)
if
(
a
->
mCategory
!=
b
->
mCategory
)
throw
std
::
logic_error
(
"Categories not same in swap"
);
throw
std
::
logic_error
(
"Categories not same in swap"
);
auto
cat
=
a
->
mCategory
;
auto
cat
=
a
->
mCategory
;
// If the field is part of the Key for this Category, remove it from the index
// If the field is part of the Key for this Category, remove it from the index
// before updating
// before updating
bool
reinsert
=
false
;
bool
reinsert
=
false
;
if
(
cat
->
mIndex
!=
nullptr
and
cat
->
keyFieldsByIndex
().
count
(
cix
))
if
(
cat
->
mIndex
!=
nullptr
and
cat
->
keyFieldsByIndex
().
count
(
cix
))
{
{
reinsert
=
true
;
reinsert
=
true
;
...
@@ -2939,11 +3124,11 @@ void Row::swap(size_t cix, ItemRow* a, ItemRow* b)
...
@@ -2939,11 +3124,11 @@ void Row::swap(size_t cix, ItemRow* a, ItemRow* b)
cat
->
mIndex
->
erase
(
b
);
cat
->
mIndex
->
erase
(
b
);
}
}
ItemValue
*
ap
=
nullptr
;
// parent of ai
ItemValue
*
ap
=
nullptr
;
// parent of ai
ItemValue
*
ai
=
nullptr
;
ItemValue
*
ai
=
nullptr
;
ItemValue
*
bp
=
nullptr
;
// parent of bi
ItemValue
*
bp
=
nullptr
;
// parent of bi
ItemValue
*
bi
=
nullptr
;
ItemValue
*
bi
=
nullptr
;
if
(
a
->
mValues
==
nullptr
)
if
(
a
->
mValues
==
nullptr
)
;
;
else
if
(
a
->
mValues
->
mColumnIndex
==
cix
)
else
if
(
a
->
mValues
->
mColumnIndex
==
cix
)
...
@@ -2964,7 +3149,6 @@ void Row::swap(size_t cix, ItemRow* a, ItemRow* b)
...
@@ -2964,7 +3149,6 @@ void Row::swap(size_t cix, ItemRow* a, ItemRow* b)
}
}
}
}
if
(
b
->
mValues
==
nullptr
)
if
(
b
->
mValues
==
nullptr
)
;
;
else
if
(
b
->
mValues
->
mColumnIndex
==
cix
)
else
if
(
b
->
mValues
->
mColumnIndex
==
cix
)
...
@@ -3018,18 +3202,18 @@ void Row::swap(size_t cix, ItemRow* a, ItemRow* b)
...
@@ -3018,18 +3202,18 @@ void Row::swap(size_t cix, ItemRow* a, ItemRow* b)
auto
parentColName
=
cat
->
getColumnName
(
cix
);
auto
parentColName
=
cat
->
getColumnName
(
cix
);
// see if we need to update any child categories that depend on these values
// see if we need to update any child categories that depend on these values
auto
&
validator
=
cat
->
getValidator
();
auto
&
validator
=
cat
->
getValidator
();
auto
parentCatValidator
=
cat
->
getCatValidator
();
auto
parentCatValidator
=
cat
->
getCatValidator
();
for
(
auto
&
link
:
validator
.
getLinksForParent
(
cat
->
mName
))
for
(
auto
&
link
:
validator
.
getLinksForParent
(
cat
->
mName
))
{
{
if
(
find
(
link
->
mParentKeys
.
begin
(),
link
->
mParentKeys
.
end
(),
parentColName
)
==
link
->
mParentKeys
.
end
())
if
(
find
(
link
->
mParentKeys
.
begin
(),
link
->
mParentKeys
.
end
(),
parentColName
)
==
link
->
mParentKeys
.
end
())
continue
;
continue
;
auto
childCat
=
cat
->
db
().
get
(
link
->
mChildCategory
);
auto
childCat
=
cat
->
db
().
get
(
link
->
mChildCategory
);
if
(
childCat
==
nullptr
or
childCat
->
empty
())
if
(
childCat
==
nullptr
or
childCat
->
empty
())
continue
;
continue
;
auto
childCatValidator
=
childCat
->
getCatValidator
();
auto
childCatValidator
=
childCat
->
getCatValidator
();
if
(
childCatValidator
==
nullptr
)
if
(
childCatValidator
==
nullptr
)
continue
;
continue
;
...
@@ -3057,13 +3241,13 @@ void Row::swap(size_t cix, ItemRow* a, ItemRow* b)
...
@@ -3057,13 +3241,13 @@ void Row::swap(size_t cix, ItemRow* a, ItemRow* b)
if
(
pcix
==
cix
)
if
(
pcix
==
cix
)
{
{
linkChildColName
=
childColName
;
linkChildColName
=
childColName
;
if
(
not
(
i
==
nullptr
or
strcmp
(
i
->
mText
,
"."
)
==
0
or
strcmp
(
i
->
mText
,
"?"
)
==
0
))
if
(
not
(
i
==
nullptr
or
strcmp
(
i
->
mText
,
"."
)
==
0
or
strcmp
(
i
->
mText
,
"?"
)
==
0
))
childValue
=
i
->
mText
;
childValue
=
i
->
mText
;
}
}
else
else
{
{
std
::
string
ps
=
r
->
c_str
(
pcix
);
std
::
string
ps
=
r
->
c_str
(
pcix
);
if
(
not
(
ps
.
empty
()
or
ps
==
"."
or
ps
==
"?"
))
if
(
not
(
ps
.
empty
()
or
ps
==
"."
or
ps
==
"?"
))
childValue
=
ps
;
childValue
=
ps
;
}
}
...
@@ -3090,7 +3274,7 @@ void Row::swap(size_t cix, ItemRow* a, ItemRow* b)
...
@@ -3090,7 +3274,7 @@ void Row::swap(size_t cix, ItemRow* a, ItemRow* b)
// if (VERBOSE > 1)
// if (VERBOSE > 1)
// std::cerr << "Fixing link from " << cat->mName << " to " << childCat->mName << " with " << std::endl
// std::cerr << "Fixing link from " << cat->mName << " to " << childCat->mName << " with " << std::endl
// << cond[ab] << std::endl;
// << cond[ab] << std::endl;
rs
.
push_back
(
childCat
->
find
(
std
::
move
(
cond
[
ab
])));
rs
.
push_back
(
childCat
->
find
(
std
::
move
(
cond
[
ab
])));
}
}
...
@@ -3098,17 +3282,17 @@ void Row::swap(size_t cix, ItemRow* a, ItemRow* b)
...
@@ -3098,17 +3282,17 @@ void Row::swap(size_t cix, ItemRow* a, ItemRow* b)
{
{
auto
i
=
ab
==
0
?
bi
:
ai
;
auto
i
=
ab
==
0
?
bi
:
ai
;
for
(
auto
r
:
rs
[
ab
])
for
(
auto
r
:
rs
[
ab
])
{
{
// now due to the way links are defined, we might have found a row
// now due to the way links are defined, we might have found a row
// that contains an empty value for all child columns...
// that contains an empty value for all child columns...
// Now, that's not a real hit, is it?
// Now, that's not a real hit, is it?
size_t
n
=
0
;
size_t
n
=
0
;
for
(
auto
c
:
link
->
mChildKeys
)
for
(
auto
c
:
link
->
mChildKeys
)
if
(
r
[
c
].
empty
())
if
(
r
[
c
].
empty
())
++
n
;
++
n
;
if
(
n
==
link
->
mChildKeys
.
size
())
if
(
n
==
link
->
mChildKeys
.
size
())
{
{
if
(
VERBOSE
>
1
)
if
(
VERBOSE
>
1
)
...
@@ -3126,7 +3310,7 @@ void Row::swap(size_t cix, ItemRow* a, ItemRow* b)
...
@@ -3126,7 +3310,7 @@ void Row::swap(size_t cix, ItemRow* a, ItemRow* b)
}
}
}
}
size_t
Row
::
ColumnForItemTag
(
const
char
*
itemTag
)
const
size_t
Row
::
ColumnForItemTag
(
const
char
*
itemTag
)
const
{
{
size_t
result
=
0
;
size_t
result
=
0
;
if
(
mData
!=
nullptr
)
if
(
mData
!=
nullptr
)
...
@@ -3163,21 +3347,22 @@ void Row::lineNr(uint32_t l)
...
@@ -3163,21 +3347,22 @@ void Row::lineNr(uint32_t l)
mData
->
mLineNr
=
l
;
mData
->
mLineNr
=
l
;
}
}
Row
::
const_iterator
::
const_iterator
(
ItemRow
*
data
,
ItemValue
*
ptr
)
Row
::
const_iterator
::
const_iterator
(
ItemRow
*
data
,
ItemValue
*
ptr
)
:
mData
(
data
),
mPtr
(
ptr
)
:
mData
(
data
)
,
mPtr
(
ptr
)
{
{
if
(
mPtr
!=
nullptr
)
if
(
mPtr
!=
nullptr
)
fetch
();
fetch
();
}
}
Row
::
const_iterator
&
Row
::
const_iterator
::
operator
++
()
Row
::
const_iterator
&
Row
::
const_iterator
::
operator
++
()
{
{
if
(
mPtr
!=
nullptr
)
if
(
mPtr
!=
nullptr
)
mPtr
=
mPtr
->
mNext
;
mPtr
=
mPtr
->
mNext
;
if
(
mPtr
!=
nullptr
)
if
(
mPtr
!=
nullptr
)
fetch
();
fetch
();
return
*
this
;
return
*
this
;
}
}
...
@@ -3188,7 +3373,7 @@ void Row::const_iterator::fetch()
...
@@ -3188,7 +3373,7 @@ void Row::const_iterator::fetch()
mPtr
->
mText
);
mPtr
->
mText
);
}
}
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
Row
&
row
)
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
Row
&
row
)
{
{
auto
category
=
row
.
mData
->
mCategory
;
auto
category
=
row
.
mData
->
mCategory
;
std
::
string
catName
=
category
->
name
();
std
::
string
catName
=
category
->
name
();
...
@@ -3209,28 +3394,29 @@ File::File()
...
@@ -3209,28 +3394,29 @@ File::File()
{
{
}
}
File
::
File
(
std
::
istream
&
is
,
bool
validate
)
File
::
File
(
std
::
istream
&
is
,
bool
validate
)
:
File
()
:
File
()
{
{
load
(
is
);
load
(
is
);
}
}
File
::
File
(
const
std
::
string
&
path
,
bool
validate
)
File
::
File
(
const
std
::
string
&
path
,
bool
validate
)
:
File
()
:
File
()
{
{
try
try
{
{
load
(
path
);
load
(
path
);
}
}
catch
(
const
std
::
exception
&
ex
)
catch
(
const
std
::
exception
&
ex
)
{
{
std
::
cerr
<<
"Error while loading file "
<<
path
<<
std
::
endl
;
std
::
cerr
<<
"Error while loading file "
<<
path
<<
std
::
endl
;
throw
;
throw
;
}
}
}
}
File
::
File
(
File
&&
rhs
)
File
::
File
(
File
&&
rhs
)
:
mHead
(
nullptr
),
mValidator
(
nullptr
)
:
mHead
(
nullptr
)
,
mValidator
(
nullptr
)
{
{
std
::
swap
(
mHead
,
rhs
.
mHead
);
std
::
swap
(
mHead
,
rhs
.
mHead
);
std
::
swap
(
mValidator
,
rhs
.
mValidator
);
std
::
swap
(
mValidator
,
rhs
.
mValidator
);
...
@@ -3242,10 +3428,10 @@ File::~File()
...
@@ -3242,10 +3428,10 @@ File::~File()
delete
mValidator
;
delete
mValidator
;
}
}
void
File
::
append
(
Datablock
*
e
)
void
File
::
append
(
Datablock
*
e
)
{
{
e
->
setValidator
(
mValidator
);
e
->
setValidator
(
mValidator
);
if
(
mHead
==
nullptr
)
if
(
mHead
==
nullptr
)
mHead
=
e
;
mHead
=
e
;
else
else
...
@@ -3261,23 +3447,23 @@ void File::append(Datablock* e)
...
@@ -3261,23 +3447,23 @@ void File::append(Datablock* e)
ie
->
mNext
=
e
;
ie
->
mNext
=
e
;
break
;
break
;
}
}
ie
=
ie
->
mNext
;
ie
=
ie
->
mNext
;
}
}
}
}
}
}
void
File
::
load
(
const
std
::
string
&
p
)
void
File
::
load
(
const
std
::
string
&
p
)
{
{
fs
::
path
path
(
p
);
fs
::
path
path
(
p
);
std
::
ifstream
inFile
(
p
,
std
::
ios_base
::
in
|
std
::
ios_base
::
binary
);
std
::
ifstream
inFile
(
p
,
std
::
ios_base
::
in
|
std
::
ios_base
::
binary
);
if
(
not
inFile
.
is_open
())
if
(
not
inFile
.
is_open
())
throw
std
::
runtime_error
(
"Could not open file: "
+
path
.
string
());
throw
std
::
runtime_error
(
"Could not open file: "
+
path
.
string
());
io
::
filtering_stream
<
io
::
input
>
in
;
io
::
filtering_stream
<
io
::
input
>
in
;
std
::
string
ext
;
std
::
string
ext
;
if
(
path
.
extension
()
==
".bz2"
)
if
(
path
.
extension
()
==
".bz2"
)
{
{
in
.
push
(
io
::
bzip2_decompressor
());
in
.
push
(
io
::
bzip2_decompressor
());
...
@@ -3288,27 +3474,27 @@ void File::load(const std::string& p)
...
@@ -3288,27 +3474,27 @@ void File::load(const std::string& p)
in
.
push
(
io
::
gzip_decompressor
());
in
.
push
(
io
::
gzip_decompressor
());
ext
=
path
.
stem
().
extension
().
string
();
ext
=
path
.
stem
().
extension
().
string
();
}
}
in
.
push
(
inFile
);
in
.
push
(
inFile
);
try
try
{
{
load
(
in
);
load
(
in
);
}
}
catch
(
const
std
::
exception
&
ex
)
catch
(
const
std
::
exception
&
ex
)
{
{
std
::
cerr
<<
"Error loading file "
<<
path
<<
std
::
endl
;
std
::
cerr
<<
"Error loading file "
<<
path
<<
std
::
endl
;
throw
;
throw
;
}
}
}
}
void
File
::
save
(
const
std
::
string
&
p
)
void
File
::
save
(
const
std
::
string
&
p
)
{
{
fs
::
path
path
(
p
);
fs
::
path
path
(
p
);
std
::
ofstream
outFile
(
p
,
std
::
ios_base
::
out
|
std
::
ios_base
::
binary
);
std
::
ofstream
outFile
(
p
,
std
::
ios_base
::
out
|
std
::
ios_base
::
binary
);
io
::
filtering_stream
<
io
::
output
>
out
;
io
::
filtering_stream
<
io
::
output
>
out
;
if
(
path
.
extension
()
==
".gz"
)
if
(
path
.
extension
()
==
".gz"
)
{
{
out
.
push
(
io
::
gzip_compressor
());
out
.
push
(
io
::
gzip_compressor
());
...
@@ -3319,19 +3505,19 @@ void File::save(const std::string& p)
...
@@ -3319,19 +3505,19 @@ void File::save(const std::string& p)
out
.
push
(
io
::
bzip2_compressor
());
out
.
push
(
io
::
bzip2_compressor
());
path
=
path
.
stem
();
path
=
path
.
stem
();
}
}
out
.
push
(
outFile
);
out
.
push
(
outFile
);
save
(
out
);
save
(
out
);
}
}
void
File
::
load
(
std
::
istream
&
is
)
void
File
::
load
(
std
::
istream
&
is
)
{
{
Validator
*
saved
=
mValidator
;
Validator
*
saved
=
mValidator
;
setValidator
(
nullptr
);
setValidator
(
nullptr
);
Parser
p
(
is
,
*
this
);
Parser
p
(
is
,
*
this
);
p
.
parseFile
();
p
.
parseFile
();
if
(
saved
!=
nullptr
)
if
(
saved
!=
nullptr
)
{
{
setValidator
(
saved
);
setValidator
(
saved
);
...
@@ -3339,14 +3525,14 @@ void File::load(std::istream& is)
...
@@ -3339,14 +3525,14 @@ void File::load(std::istream& is)
}
}
}
}
void
File
::
load
(
std
::
istream
&
is
,
const
std
::
string
&
datablock
)
void
File
::
load
(
std
::
istream
&
is
,
const
std
::
string
&
datablock
)
{
{
Validator
*
saved
=
mValidator
;
Validator
*
saved
=
mValidator
;
setValidator
(
nullptr
);
setValidator
(
nullptr
);
Parser
p
(
is
,
*
this
);
Parser
p
(
is
,
*
this
);
p
.
parseSingleDatablock
(
datablock
);
p
.
parseSingleDatablock
(
datablock
);
if
(
saved
!=
nullptr
)
if
(
saved
!=
nullptr
)
{
{
setValidator
(
saved
);
setValidator
(
saved
);
...
@@ -3354,9 +3540,9 @@ void File::load(std::istream& is, const std::string& datablock)
...
@@ -3354,9 +3540,9 @@ void File::load(std::istream& is, const std::string& datablock)
}
}
}
}
void
File
::
save
(
std
::
ostream
&
os
)
void
File
::
save
(
std
::
ostream
&
os
)
{
{
Datablock
*
e
=
mHead
;
Datablock
*
e
=
mHead
;
while
(
e
!=
nullptr
)
while
(
e
!=
nullptr
)
{
{
e
->
write
(
os
);
e
->
write
(
os
);
...
@@ -3364,9 +3550,9 @@ void File::save(std::ostream& os)
...
@@ -3364,9 +3550,9 @@ void File::save(std::ostream& os)
}
}
}
}
void
File
::
write
(
std
::
ostream
&
os
,
const
std
::
vector
<
std
::
string
>&
order
)
void
File
::
write
(
std
::
ostream
&
os
,
const
std
::
vector
<
std
::
string
>
&
order
)
{
{
Datablock
*
e
=
mHead
;
Datablock
*
e
=
mHead
;
while
(
e
!=
nullptr
)
while
(
e
!=
nullptr
)
{
{
e
->
write
(
os
,
order
);
e
->
write
(
os
,
order
);
...
@@ -3374,17 +3560,17 @@ void File::write(std::ostream& os, const std::vector<std::string>& order)
...
@@ -3374,17 +3560,17 @@ void File::write(std::ostream& os, const std::vector<std::string>& order)
}
}
}
}
Datablock
*
File
::
get
(
const
std
::
string
&
name
)
const
Datablock
*
File
::
get
(
const
std
::
string
&
name
)
const
{
{
const
Datablock
*
result
=
mHead
;
const
Datablock
*
result
=
mHead
;
while
(
result
!=
nullptr
and
not
iequals
(
result
->
mName
,
name
))
while
(
result
!=
nullptr
and
not
iequals
(
result
->
mName
,
name
))
result
=
result
->
mNext
;
result
=
result
->
mNext
;
return
const_cast
<
Datablock
*>
(
result
);
return
const_cast
<
Datablock
*>
(
result
);
}
}
Datablock
&
File
::
operator
[](
const
std
::
string
&
name
)
Datablock
&
File
::
operator
[](
const
std
::
string
&
name
)
{
{
Datablock
*
result
=
mHead
;
Datablock
*
result
=
mHead
;
while
(
result
!=
nullptr
and
not
iequals
(
result
->
mName
,
name
))
while
(
result
!=
nullptr
and
not
iequals
(
result
->
mName
,
name
))
result
=
result
->
mNext
;
result
=
result
->
mNext
;
if
(
result
==
nullptr
)
if
(
result
==
nullptr
)
...
@@ -3398,7 +3584,7 @@ bool File::isValid()
...
@@ -3398,7 +3584,7 @@ bool File::isValid()
{
{
if
(
VERBOSE
)
if
(
VERBOSE
)
std
::
cerr
<<
"No dictionary loaded explicitly, loading default"
<<
std
::
endl
;
std
::
cerr
<<
"No dictionary loaded explicitly, loading default"
<<
std
::
endl
;
loadDictionary
();
loadDictionary
();
}
}
...
@@ -3414,7 +3600,7 @@ void File::validateLinks() const
...
@@ -3414,7 +3600,7 @@ void File::validateLinks() const
d
->
validateLinks
();
d
->
validateLinks
();
}
}
const
Validator
&
File
::
getValidator
()
const
const
Validator
&
File
::
getValidator
()
const
{
{
if
(
mValidator
==
nullptr
)
if
(
mValidator
==
nullptr
)
throw
std
::
runtime_error
(
"no Validator defined yet"
);
throw
std
::
runtime_error
(
"no Validator defined yet"
);
...
@@ -3426,7 +3612,7 @@ void File::loadDictionary()
...
@@ -3426,7 +3612,7 @@ void File::loadDictionary()
loadDictionary
(
"mmcif_ddl"
);
loadDictionary
(
"mmcif_ddl"
);
}
}
void
File
::
loadDictionary
(
const
char
*
dict
)
void
File
::
loadDictionary
(
const
char
*
dict
)
{
{
fs
::
path
dict_name
(
dict
);
fs
::
path
dict_name
(
dict
);
...
@@ -3437,7 +3623,7 @@ void File::loadDictionary(const char* dict)
...
@@ -3437,7 +3623,7 @@ void File::loadDictionary(const char* dict)
if
(
data
)
if
(
data
)
loadDictionary
(
*
data
);
loadDictionary
(
*
data
);
else
else
{
{
// might be a compressed dictionary on disk
// might be a compressed dictionary on disk
fs
::
path
p
=
dict
;
fs
::
path
p
=
dict
;
...
@@ -3449,7 +3635,7 @@ void File::loadDictionary(const char* dict)
...
@@ -3449,7 +3635,7 @@ void File::loadDictionary(const char* dict)
#if defined(CACHE_DIR) and defined(DATA_DIR)
#if defined(CACHE_DIR) and defined(DATA_DIR)
if
(
not
fs
::
exists
(
p
))
if
(
not
fs
::
exists
(
p
))
{
{
for
(
const
char
*
dir
:
{
CACHE_DIR
,
DATA_DIR
})
for
(
const
char
*
dir
:
{
CACHE_DIR
,
DATA_DIR
})
{
{
auto
p2
=
fs
::
path
(
dir
)
/
p
;
auto
p2
=
fs
::
path
(
dir
)
/
p
;
if
(
fs
::
exists
(
p2
))
if
(
fs
::
exists
(
p2
))
...
@@ -3478,7 +3664,7 @@ void File::loadDictionary(const char* dict)
...
@@ -3478,7 +3664,7 @@ void File::loadDictionary(const char* dict)
}
}
}
}
void
File
::
loadDictionary
(
std
::
istream
&
is
)
void
File
::
loadDictionary
(
std
::
istream
&
is
)
{
{
std
::
unique_ptr
<
Validator
>
v
(
new
Validator
());
std
::
unique_ptr
<
Validator
>
v
(
new
Validator
());
...
@@ -3488,7 +3674,7 @@ void File::loadDictionary(std::istream& is)
...
@@ -3488,7 +3674,7 @@ void File::loadDictionary(std::istream& is)
setValidator
(
v
.
release
());
setValidator
(
v
.
release
());
}
}
void
File
::
setValidator
(
Validator
*
v
)
void
File
::
setValidator
(
Validator
*
v
)
{
{
mValidator
=
v
;
mValidator
=
v
;
...
@@ -3496,13 +3682,13 @@ void File::setValidator(Validator* v)
...
@@ -3496,13 +3682,13 @@ void File::setValidator(Validator* v)
d
->
setValidator
(
mValidator
);
d
->
setValidator
(
mValidator
);
}
}
void
File
::
getTagOrder
(
std
::
vector
<
std
::
string
>
&
tags
)
const
void
File
::
getTagOrder
(
std
::
vector
<
std
::
string
>
&
tags
)
const
{
{
for
(
auto
d
=
mHead
;
d
!=
nullptr
;
d
=
d
->
mNext
)
for
(
auto
d
=
mHead
;
d
!=
nullptr
;
d
=
d
->
mNext
)
d
->
getTagOrder
(
tags
);
d
->
getTagOrder
(
tags
);
}
}
auto
File
::
iterator
::
operator
++
()
->
iterator
&
auto
File
::
iterator
::
operator
++
()
->
iterator
&
{
{
mCurrent
=
mCurrent
->
mNext
;
mCurrent
=
mCurrent
->
mNext
;
return
*
this
;
return
*
this
;
...
@@ -3518,4 +3704,4 @@ auto File::end() const -> iterator
...
@@ -3518,4 +3704,4 @@ auto File::end() const -> iterator
return
iterator
(
nullptr
);
return
iterator
(
nullptr
);
}
}
}
}
// namespace cif
src/Structure.cpp
View file @
345c4778
...
@@ -795,7 +795,7 @@ std::ostream &operator<<(std::ostream &os, const Atom &atom)
...
@@ -795,7 +795,7 @@ std::ostream &operator<<(std::ostream &os, const Atom &atom)
// First constructor used to be for waters only, but now accepts sugars as well.
// First constructor used to be for waters only, but now accepts sugars as well.
Residue
::
Residue
(
const
Structure
&
structure
,
const
std
::
string
&
compoundID
,
Residue
::
Residue
(
const
Structure
&
structure
,
const
std
::
string
&
compoundID
,
const
std
::
string
&
asymID
,
const
std
::
string
&
authSeqID
)
const
std
::
string
&
asymID
,
const
std
::
string
&
authSeqID
)
:
mStructure
(
&
structure
)
:
mStructure
(
&
structure
)
,
mCompoundID
(
compoundID
)
,
mCompoundID
(
compoundID
)
,
mAsymID
(
asymID
)
,
mAsymID
(
asymID
)
...
@@ -804,7 +804,7 @@ Residue::Residue(const Structure &structure, const std::string &compoundID,
...
@@ -804,7 +804,7 @@ Residue::Residue(const Structure &structure, const std::string &compoundID,
for
(
auto
&
a
:
mStructure
->
atoms
())
for
(
auto
&
a
:
mStructure
->
atoms
())
{
{
if
(
a
.
labelAsymID
()
!=
mAsymID
or
if
(
a
.
labelAsymID
()
!=
mAsymID
or
a
.
labelCompID
()
!=
mCompoundID
)
a
.
labelCompID
()
!=
mCompoundID
)
continue
;
continue
;
if
(
compoundID
==
"HOH"
)
if
(
compoundID
==
"HOH"
)
...
@@ -830,7 +830,7 @@ Residue::Residue(const Structure &structure, const std::string &compoundID, cons
...
@@ -830,7 +830,7 @@ Residue::Residue(const Structure &structure, const std::string &compoundID, cons
}
}
Residue
::
Residue
(
const
Structure
&
structure
,
const
std
::
string
&
compoundID
,
Residue
::
Residue
(
const
Structure
&
structure
,
const
std
::
string
&
compoundID
,
const
std
::
string
&
asymID
,
int
seqID
,
const
std
::
string
&
authSeqID
)
const
std
::
string
&
asymID
,
int
seqID
,
const
std
::
string
&
authSeqID
)
:
mStructure
(
&
structure
)
:
mStructure
(
&
structure
)
,
mCompoundID
(
compoundID
)
,
mCompoundID
(
compoundID
)
,
mAsymID
(
asymID
)
,
mAsymID
(
asymID
)
...
@@ -845,7 +845,7 @@ Residue::Residue(const Structure &structure, const std::string &compoundID,
...
@@ -845,7 +845,7 @@ Residue::Residue(const Structure &structure, const std::string &compoundID,
continue
;
continue
;
if
(
a
.
labelAsymID
()
!=
mAsymID
or
if
(
a
.
labelAsymID
()
!=
mAsymID
or
a
.
labelCompID
()
!=
mCompoundID
)
a
.
labelCompID
()
!=
mCompoundID
)
continue
;
continue
;
mAtoms
.
push_back
(
a
);
mAtoms
.
push_back
(
a
);
...
@@ -968,7 +968,7 @@ std::string Residue::unique_alt_id() const
...
@@ -968,7 +968,7 @@ std::string Residue::unique_alt_id() const
throw
std
::
runtime_error
(
"Invalid Residue object"
);
throw
std
::
runtime_error
(
"Invalid Residue object"
);
auto
firstAlt
=
std
::
find_if
(
mAtoms
.
begin
(),
mAtoms
.
end
(),
[](
auto
&
a
)
auto
firstAlt
=
std
::
find_if
(
mAtoms
.
begin
(),
mAtoms
.
end
(),
[](
auto
&
a
)
{
return
not
a
.
labelAltID
().
empty
();
});
{
return
not
a
.
labelAltID
().
empty
();
});
return
firstAlt
!=
mAtoms
.
end
()
?
firstAlt
->
labelAltID
()
:
""
;
return
firstAlt
!=
mAtoms
.
end
()
?
firstAlt
->
labelAltID
()
:
""
;
}
}
...
@@ -1104,7 +1104,7 @@ std::tuple<Point, float> Residue::centerAndRadius() const
...
@@ -1104,7 +1104,7 @@ std::tuple<Point, float> Residue::centerAndRadius() const
bool
Residue
::
hasAlternateAtoms
()
const
bool
Residue
::
hasAlternateAtoms
()
const
{
{
return
std
::
find_if
(
mAtoms
.
begin
(),
mAtoms
.
end
(),
[](
const
Atom
&
atom
)
return
std
::
find_if
(
mAtoms
.
begin
(),
mAtoms
.
end
(),
[](
const
Atom
&
atom
)
{
return
atom
.
isAlternate
();
})
!=
mAtoms
.
end
();
{
return
atom
.
isAlternate
();
})
!=
mAtoms
.
end
();
}
}
std
::
set
<
std
::
string
>
Residue
::
getAtomIDs
()
const
std
::
set
<
std
::
string
>
Residue
::
getAtomIDs
()
const
...
@@ -1476,7 +1476,7 @@ float Monomer::chiralVolume() const
...
@@ -1476,7 +1476,7 @@ float Monomer::chiralVolume() const
auto
atom3
=
atomByID
(
"CD2"
);
auto
atom3
=
atomByID
(
"CD2"
);
result
=
DotProduct
(
atom1
.
location
()
-
centre
.
location
(),
result
=
DotProduct
(
atom1
.
location
()
-
centre
.
location
(),
CrossProduct
(
atom2
.
location
()
-
centre
.
location
(),
atom3
.
location
()
-
centre
.
location
()));
CrossProduct
(
atom2
.
location
()
-
centre
.
location
(),
atom3
.
location
()
-
centre
.
location
()));
}
}
else
if
(
mCompoundID
==
"VAL"
)
else
if
(
mCompoundID
==
"VAL"
)
{
{
...
@@ -1486,7 +1486,7 @@ float Monomer::chiralVolume() const
...
@@ -1486,7 +1486,7 @@ float Monomer::chiralVolume() const
auto
atom3
=
atomByID
(
"CG2"
);
auto
atom3
=
atomByID
(
"CG2"
);
result
=
DotProduct
(
atom1
.
location
()
-
centre
.
location
(),
result
=
DotProduct
(
atom1
.
location
()
-
centre
.
location
(),
CrossProduct
(
atom2
.
location
()
-
centre
.
location
(),
atom3
.
location
()
-
centre
.
location
()));
CrossProduct
(
atom2
.
location
()
-
centre
.
location
(),
atom3
.
location
()
-
centre
.
location
()));
}
}
return
result
;
return
result
;
...
@@ -1740,6 +1740,14 @@ File::~File()
...
@@ -1740,6 +1740,14 @@ File::~File()
delete
mImpl
;
delete
mImpl
;
}
}
cif
::
Datablock
&
File
::
createDatablock
(
const
std
::
string
&
name
)
{
auto
db
=
new
cif
::
Datablock
(
name
);
mImpl
->
mData
.
append
(
db
);
mImpl
->
mDb
=
db
;
}
void
File
::
load
(
const
std
::
string
&
p
)
void
File
::
load
(
const
std
::
string
&
p
)
{
{
mImpl
->
load
(
p
);
mImpl
->
load
(
p
);
...
@@ -1778,8 +1786,11 @@ Structure::Structure(File &f, size_t modelNr, StructureOpenOptions options)
...
@@ -1778,8 +1786,11 @@ Structure::Structure(File &f, size_t modelNr, StructureOpenOptions options)
:
mFile
(
f
)
:
mFile
(
f
)
,
mModelNr
(
modelNr
)
,
mModelNr
(
modelNr
)
{
{
auto
&
db
=
*
mFile
.
impl
().
mDb
;
auto
db
=
mFile
.
impl
().
mDb
;
auto
&
atomCat
=
db
[
"atom_site"
];
if
(
db
==
nullptr
)
throw
std
::
logic_error
(
"Empty file!"
);
auto
&
atomCat
=
(
*
db
)[
"atom_site"
];
for
(
auto
&
a
:
atomCat
)
for
(
auto
&
a
:
atomCat
)
{
{
...
@@ -1864,13 +1875,13 @@ void Structure::updateAtomIndex()
...
@@ -1864,13 +1875,13 @@ void Structure::updateAtomIndex()
iota
(
mAtomIndex
.
begin
(),
mAtomIndex
.
end
(),
0
);
iota
(
mAtomIndex
.
begin
(),
mAtomIndex
.
end
(),
0
);
sort
(
mAtomIndex
.
begin
(),
mAtomIndex
.
end
(),
[
this
](
size_t
a
,
size_t
b
)
sort
(
mAtomIndex
.
begin
(),
mAtomIndex
.
end
(),
[
this
](
size_t
a
,
size_t
b
)
{
return
mAtoms
[
a
].
id
()
<
mAtoms
[
b
].
id
();
});
{
return
mAtoms
[
a
].
id
()
<
mAtoms
[
b
].
id
();
});
}
}
void
Structure
::
sortAtoms
()
void
Structure
::
sortAtoms
()
{
{
sort
(
mAtoms
.
begin
(),
mAtoms
.
end
(),
[](
auto
&
a
,
auto
&
b
)
sort
(
mAtoms
.
begin
(),
mAtoms
.
end
(),
[](
auto
&
a
,
auto
&
b
)
{
return
a
.
compare
(
b
)
<
0
;
});
{
return
a
.
compare
(
b
)
<
0
;
});
int
id
=
1
;
int
id
=
1
;
for
(
auto
&
atom
:
mAtoms
)
for
(
auto
&
atom
:
mAtoms
)
...
@@ -1914,8 +1925,8 @@ AtomView Structure::waters() const
...
@@ -1914,8 +1925,8 @@ AtomView Structure::waters() const
Atom
Structure
::
getAtomByID
(
std
::
string
id
)
const
Atom
Structure
::
getAtomByID
(
std
::
string
id
)
const
{
{
auto
i
=
std
::
lower_bound
(
mAtomIndex
.
begin
(),
mAtomIndex
.
end
(),
auto
i
=
std
::
lower_bound
(
mAtomIndex
.
begin
(),
mAtomIndex
.
end
(),
id
,
[
this
](
auto
&
a
,
auto
&
b
)
id
,
[
this
](
auto
&
a
,
auto
&
b
)
{
return
mAtoms
[
a
].
id
()
<
b
;
});
{
return
mAtoms
[
a
].
id
()
<
b
;
});
// auto i = find_if(mAtoms.begin(), mAtoms.end(),
// auto i = find_if(mAtoms.begin(), mAtoms.end(),
// [&id](auto& a) { return a.id() == id; });
// [&id](auto& a) { return a.id() == id; });
...
@@ -1931,10 +1942,10 @@ Atom Structure::getAtomByLabel(const std::string &atomID, const std::string &asy
...
@@ -1931,10 +1942,10 @@ Atom Structure::getAtomByLabel(const std::string &atomID, const std::string &asy
for
(
auto
&
a
:
mAtoms
)
for
(
auto
&
a
:
mAtoms
)
{
{
if
(
a
.
labelAtomID
()
==
atomID
and
if
(
a
.
labelAtomID
()
==
atomID
and
a
.
labelAsymID
()
==
asymID
and
a
.
labelAsymID
()
==
asymID
and
a
.
labelCompID
()
==
compID
and
a
.
labelCompID
()
==
compID
and
a
.
labelSeqID
()
==
seqID
and
a
.
labelSeqID
()
==
seqID
and
a
.
labelAltID
()
==
altID
)
a
.
labelAltID
()
==
altID
)
{
{
return
a
;
return
a
;
}
}
...
@@ -2013,12 +2024,12 @@ std::tuple<char, int, char> Structure::MapLabelToAuth(
...
@@ -2013,12 +2024,12 @@ std::tuple<char, int, char> Structure::MapLabelToAuth(
try
try
{
{
result
=
std
::
make_tuple
(
auth_asym_id
.
front
(),
std
::
stoi
(
auth_seq_num
),
result
=
std
::
make_tuple
(
auth_asym_id
.
front
(),
std
::
stoi
(
auth_seq_num
),
pdb_ins_code
.
empty
()
?
' '
:
pdb_ins_code
.
front
());
pdb_ins_code
.
empty
()
?
' '
:
pdb_ins_code
.
front
());
}
}
catch
(
const
std
::
exception
&
ex
)
catch
(
const
std
::
exception
&
ex
)
{
{
result
=
std
::
make_tuple
(
auth_asym_id
.
front
(),
0
,
result
=
std
::
make_tuple
(
auth_asym_id
.
front
(),
0
,
pdb_ins_code
.
empty
()
?
' '
:
pdb_ins_code
.
front
());
pdb_ins_code
.
empty
()
?
' '
:
pdb_ins_code
.
front
());
}
}
found
=
true
;
found
=
true
;
...
@@ -2037,7 +2048,7 @@ std::tuple<char, int, char> Structure::MapLabelToAuth(
...
@@ -2037,7 +2048,7 @@ std::tuple<char, int, char> Structure::MapLabelToAuth(
r
.
front
().
get
(
"pdb_strand_id"
,
"pdb_seq_num"
,
"pdb_ins_code"
);
r
.
front
().
get
(
"pdb_strand_id"
,
"pdb_seq_num"
,
"pdb_ins_code"
);
result
=
std
::
make_tuple
(
pdb_strand_id
.
front
(),
pdb_seq_num
,
result
=
std
::
make_tuple
(
pdb_strand_id
.
front
(),
pdb_seq_num
,
pdb_ins_code
.
empty
()
?
' '
:
pdb_ins_code
.
front
());
pdb_ins_code
.
empty
()
?
' '
:
pdb_ins_code
.
front
());
found
=
true
;
found
=
true
;
}
}
...
@@ -2089,7 +2100,7 @@ std::tuple<std::string, int, std::string, std::string> Structure::MapLabelToPDB(
...
@@ -2089,7 +2100,7 @@ std::tuple<std::string, int, std::string, std::string> Structure::MapLabelToPDB(
}
}
std
::
tuple
<
std
::
string
,
int
,
std
::
string
>
Structure
::
MapPDBToLabel
(
const
std
::
string
&
asymID
,
int
seqID
,
std
::
tuple
<
std
::
string
,
int
,
std
::
string
>
Structure
::
MapPDBToLabel
(
const
std
::
string
&
asymID
,
int
seqID
,
const
std
::
string
&
compID
,
const
std
::
string
&
iCode
)
const
const
std
::
string
&
compID
,
const
std
::
string
&
iCode
)
const
{
{
auto
&
db
=
datablock
();
auto
&
db
=
datablock
();
...
@@ -2161,10 +2172,10 @@ void Structure::insertCompound(const std::string &compoundID, bool isEntity)
...
@@ -2161,10 +2172,10 @@ void Structure::insertCompound(const std::string &compoundID, bool isEntity)
if
(
r
.
empty
())
if
(
r
.
empty
())
{
{
chemComp
.
emplace
({{
"id"
,
compoundID
},
chemComp
.
emplace
({{
"id"
,
compoundID
},
{
"name"
,
compound
->
name
()},
{
"name"
,
compound
->
name
()},
{
"formula"
,
compound
->
formula
()},
{
"formula"
,
compound
->
formula
()},
{
"formula_weight"
,
compound
->
formulaWeight
()},
{
"formula_weight"
,
compound
->
formulaWeight
()},
{
"type"
,
compound
->
type
()}});
{
"type"
,
compound
->
type
()}});
}
}
if
(
isEntity
)
if
(
isEntity
)
...
@@ -2176,13 +2187,13 @@ void Structure::insertCompound(const std::string &compoundID, bool isEntity)
...
@@ -2176,13 +2187,13 @@ void Structure::insertCompound(const std::string &compoundID, bool isEntity)
std
::
string
entityID
=
std
::
to_string
(
entity
.
size
()
+
1
);
std
::
string
entityID
=
std
::
to_string
(
entity
.
size
()
+
1
);
entity
.
emplace
({{
"id"
,
entityID
},
entity
.
emplace
({{
"id"
,
entityID
},
{
"type"
,
"non-polymer"
},
{
"type"
,
"non-polymer"
},
{
"pdbx_description"
,
compound
->
name
()},
{
"pdbx_description"
,
compound
->
name
()},
{
"formula_weight"
,
compound
->
formulaWeight
()}});
{
"formula_weight"
,
compound
->
formulaWeight
()}});
pdbxEntityNonpoly
.
emplace
({{
"entity_id"
,
entityID
},
pdbxEntityNonpoly
.
emplace
({{
"entity_id"
,
entityID
},
{
"name"
,
compound
->
name
()},
{
"name"
,
compound
->
name
()},
{
"comp_id"
,
compoundID
}});
{
"comp_id"
,
compoundID
}});
}
}
}
}
}
}
...
@@ -2305,7 +2316,7 @@ void Structure::moveAtom(Atom &a, Point p)
...
@@ -2305,7 +2316,7 @@ void Structure::moveAtom(Atom &a, Point p)
}
}
void
Structure
::
changeResidue
(
const
Residue
&
res
,
const
std
::
string
&
newCompound
,
void
Structure
::
changeResidue
(
const
Residue
&
res
,
const
std
::
string
&
newCompound
,
const
std
::
vector
<
std
::
tuple
<
std
::
string
,
std
::
string
>>
&
remappedAtoms
)
const
std
::
vector
<
std
::
tuple
<
std
::
string
,
std
::
string
>>
&
remappedAtoms
)
{
{
using
namespace
cif
::
literals
;
using
namespace
cif
::
literals
;
...
@@ -2333,15 +2344,15 @@ void Structure::changeResidue(const Residue &res, const std::string &newCompound
...
@@ -2333,15 +2344,15 @@ void Structure::changeResidue(const Residue &res, const std::string &newCompound
{
{
entityID
=
entity
.
getUniqueID
(
""
);
entityID
=
entity
.
getUniqueID
(
""
);
entity
.
emplace
({{
"id"
,
entityID
},
entity
.
emplace
({{
"id"
,
entityID
},
{
"type"
,
"non-polymer"
},
{
"type"
,
"non-polymer"
},
{
"pdbx_description"
,
compound
->
name
()},
{
"pdbx_description"
,
compound
->
name
()},
{
"formula_weight"
,
compound
->
formulaWeight
()}});
{
"formula_weight"
,
compound
->
formulaWeight
()}});
}
}
auto
&
pdbxEntityNonpoly
=
db
[
"pdbx_entity_nonpoly"
];
auto
&
pdbxEntityNonpoly
=
db
[
"pdbx_entity_nonpoly"
];
pdbxEntityNonpoly
.
emplace
({{
"entity_id"
,
entityID
},
pdbxEntityNonpoly
.
emplace
({{
"entity_id"
,
entityID
},
{
"name"
,
compound
->
name
()},
{
"name"
,
compound
->
name
()},
{
"comp_id"
,
newCompound
}});
{
"comp_id"
,
newCompound
}});
auto
&
pdbxNonPolyScheme
=
db
[
"pdbx_nonpoly_scheme"
];
auto
&
pdbxNonPolyScheme
=
db
[
"pdbx_nonpoly_scheme"
];
for
(
auto
&
nps
:
pdbxNonPolyScheme
.
find
(
"asym_id"
_key
==
asymID
))
for
(
auto
&
nps
:
pdbxNonPolyScheme
.
find
(
"asym_id"
_key
==
asymID
))
...
@@ -2356,10 +2367,10 @@ void Structure::changeResidue(const Residue &res, const std::string &newCompound
...
@@ -2356,10 +2367,10 @@ void Structure::changeResidue(const Residue &res, const std::string &newCompound
if
(
not
chemComp
.
exists
(
cif
::
Key
(
"id"
)
==
newCompound
))
if
(
not
chemComp
.
exists
(
cif
::
Key
(
"id"
)
==
newCompound
))
{
{
chemComp
.
emplace
({{
"id"
,
newCompound
},
chemComp
.
emplace
({{
"id"
,
newCompound
},
{
"name"
,
compound
->
name
()},
{
"name"
,
compound
->
name
()},
{
"formula"
,
compound
->
formula
()},
{
"formula"
,
compound
->
formula
()},
{
"formula_weight"
,
compound
->
formulaWeight
()},
{
"formula_weight"
,
compound
->
formulaWeight
()},
{
"type"
,
compound
->
type
()}});
{
"type"
,
compound
->
type
()}});
}
}
// update the struct_asym for the new entity
// update the struct_asym for the new entity
...
@@ -2377,7 +2388,7 @@ void Structure::changeResidue(const Residue &res, const std::string &newCompound
...
@@ -2377,7 +2388,7 @@ void Structure::changeResidue(const Residue &res, const std::string &newCompound
tie
(
a1
,
a2
)
=
a
;
tie
(
a1
,
a2
)
=
a
;
auto
i
=
find_if
(
atoms
.
begin
(),
atoms
.
end
(),
[
&
](
const
Atom
&
a
)
auto
i
=
find_if
(
atoms
.
begin
(),
atoms
.
end
(),
[
&
](
const
Atom
&
a
)
{
return
a
.
labelAtomID
()
==
a1
;
});
{
return
a
.
labelAtomID
()
==
a1
;
});
if
(
i
==
atoms
.
end
())
if
(
i
==
atoms
.
end
())
{
{
std
::
cerr
<<
"Missing atom for atom ID "
<<
a1
<<
std
::
endl
;
std
::
cerr
<<
"Missing atom for atom ID "
<<
a1
<<
std
::
endl
;
...
@@ -2400,6 +2411,31 @@ void Structure::changeResidue(const Residue &res, const std::string &newCompound
...
@@ -2400,6 +2411,31 @@ void Structure::changeResidue(const Residue &res, const std::string &newCompound
}
}
}
}
std
::
string
Structure
::
createEntityNonPoly
(
std
::
vector
<
cif
::
Item
>
data
,
const
std
::
string
&
mon_id
)
{
auto
&
db
=
mFile
.
data
();
auto
&
entity
=
db
[
"entity"
];
std
::
string
entity_id
=
entity
.
getUniqueID
(
""
);
// remove any ID fields
data
.
erase
(
std
::
remove_if
(
data
.
begin
(),
data
.
end
(),
[](
cif
::
Item
&
item
)
{
return
item
.
name
()
==
"id"
;
}),
data
.
end
());
// add our new ID
data
.
emplace_back
(
"id"
,
entity_id
);
data
.
emplace_back
(
"type"
,
"non-polymer"
);
entity
.
emplace
(
data
.
begin
(),
data
.
end
());
return
entity_id
;
}
std
::
string
Structure
::
createNonpoly
(
const
std
::
string
&
entity_id
,
const
std
::
vector
<
cif
::
Item
>
&
atoms
)
{
return
{};
}
void
Structure
::
cleanupEmptyCategories
()
void
Structure
::
cleanupEmptyCategories
()
{
{
using
namespace
cif
::
literals
;
using
namespace
cif
::
literals
;
...
...
test/structure-test.cpp
0 → 100644
View file @
345c4778
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 NKI/AVL, Netherlands Cancer Institute
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define BOOST_TEST_MODULE Structure_Test
#include <boost/test/included/unit_test.hpp>
#include <stdexcept>
#include "cif++/Cif++.hpp"
#include "cif++/Structure.hpp"
// --------------------------------------------------------------------
cif
::
File
operator
""
_cf
(
const
char
*
text
,
size_t
length
)
{
struct
membuf
:
public
std
::
streambuf
{
membuf
(
char
*
text
,
size_t
length
)
{
this
->
setg
(
text
,
text
,
text
+
length
);
}
}
buffer
(
const_cast
<
char
*>
(
text
),
length
);
std
::
istream
is
(
&
buffer
);
return
cif
::
File
(
is
);
}
// --------------------------------------------------------------------
BOOST_AUTO_TEST_CASE
(
create_nonpoly_1
)
{
cif
::
VERBOSE
=
1
;
// do this now, avoids the need for installing
cif
::
addFileResource
(
"mmcif_pdbx_v50.dic"
,
"../rsrc/mmcif_pdbx_v50.dic"
);
auto
expected
=
R"(
data_TEST
loop_
_entity.id
_entity.type
_entity.src_method
_entity.pdbx_description
_entity.formula_weight
1 non-polymer syn 'PROTOPORPHYRIN IX CONTAINING FE' 616.487
)"
_cf
;
expected
.
loadDictionary
(
"mmcif_pdbx_v50.dic"
);
mmcif
::
File
file
;
file
.
file
().
loadDictionary
(
"mmcif_pdbx_v50.dic"
);
file
.
createDatablock
(
"TEST"
);
// create a datablock
mmcif
::
Structure
structure
(
file
);
structure
.
createEntityNonPoly
({
{
"src_method"
,
"syn"
},
{
"pdbx_description"
,
"PROTOPORPHYRIN IX CONTAINING FE"
},
{
"formula_weight"
,
616.487
}
},
"HEM"
);
BOOST_TEST
(
expected
.
firstDatablock
()
==
structure
.
getFile
().
data
());
std
::
cout
<<
expected
.
firstDatablock
()
<<
std
::
endl
<<
std
::
endl
<<
structure
.
getFile
().
data
()
<<
std
::
endl
;
// // using namespace mmcif;
// auto f = R"(data_TEST
// #
// loop_
// _test.id
// _test.name
// 1 aap
// 2 noot
// 3 mies
// )"_cf;
// auto& db = f.firstDatablock();
// BOOST_CHECK(db.getName() == "TEST");
// auto& test = db["test"];
// BOOST_CHECK(test.size() == 3);
// // wrong! the next lines will crash. And that's OK, don't do that
// // for (auto r: test)
// // test.erase(r);
// // BOOST_CHECK(test.empty());
// // test.purge();
// auto n = test.erase(cif::Key("id") == 1, [](const cif::Row& r) {
// BOOST_CHECK_EQUAL(r["id"].as<int>(), 1);
// BOOST_CHECK_EQUAL(r["name"].as<std::string>(), "aap");
// });
// BOOST_CHECK_EQUAL(n, 1);
}
test/unit-test.cpp
View file @
345c4778
...
@@ -1664,4 +1664,4 @@ BOOST_AUTO_TEST_CASE(bondmap_2)
...
@@ -1664,4 +1664,4 @@ BOOST_AUTO_TEST_CASE(bondmap_2)
mmcif
::
CompoundFactory
::
instance
().
pushDictionary
(
"./UN_.cif"
);
mmcif
::
CompoundFactory
::
instance
().
pushDictionary
(
"./UN_.cif"
);
BOOST_CHECK
(
mmcif
::
BondMap
::
atomIDsForCompound
(
"UN_"
).
empty
()
==
false
);
BOOST_CHECK
(
mmcif
::
BondMap
::
atomIDsForCompound
(
"UN_"
).
empty
()
==
false
);
}
}
\ No newline at end of file
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